Thursday, October 27, 2022
HomeWordPress DevelopmentConstruct A Ok-pop Radio in Go!

Construct A Ok-pop Radio in Go!


The total code could be discovered right here:
https://github.com/raymond-design/kpop-cli



Intro:

We’ll be studying the way to use the Gorilla websockets websocket consumer and faiface/beep to stream Ok-pop music 🎹



Setup the challenge:

Let’s first init our Go challenge by operating:
go mod init [project name]

We’ll have to obtain two libraries:

Beep:
go get github.com/faiface/beep

Gorilla Websocket:
go get github.com/gorilla/websocket



Begin coding!

It will likely be useful if we first setup our challenge construction.

First create a foremost.go file at in our challenge listing. This can be our entrypoint.

Then create 4 extra directories:
join
play
sorts
ui

The challenge construction ought to look one thing like this (I additionally suggest making a .gitignore when you plan on pushing to git:

The Project opened up in VsCode



Consumer Interface

Let’s first create a file contained in the ui folder. We identify the file ui.go.

This file will outline a perform that prints track information the terminal! First let’s import the "fmt" bundle:

bundle ui

import (
    "fmt"
)
Enter fullscreen mode

Exit fullscreen mode

Now let’s create a perform named WriteToFunction. Be certain that to capitalize the primary letter (since we’ll use it elsewhere):

func WriteToScreen(identify string, creator string, album string) {
    fmt.Print("33[H33[2J")
    fmt.Println("Now Playing:")
    fmt.Println("Title: " + name)
    fmt.Println("Artist: " + author)
    if album != "" {
        fmt.Println("Album: " + album)
    }
}
Enter fullscreen mode

Exit fullscreen mode

ui.go looks like this:

ui.go



Define Types

A helpful pattern in Go is to define related struct types in one place. Let’s create a types.go file in the types directory.

The song info will be in json format. First import that:

package types

import "encoding/json"
Enter fullscreen mode

Exit fullscreen mode

Next, we need to describe some types for WebSockets connection:

type SocketRes struct {
    Op int64 `json:"op"`
    D  json.RawMessage
}

type SendData struct {
    Op int64 `json:"op"`
}

type HeartbeatData struct {
    Message   string `json:"message"`
    Heartbeat int64  `json:"heartbeat"`
}
Enter fullscreen mode

Exit fullscreen mode

Next, we will define some structs related to the songs themselves(Song, Album, etc.):

type PlayingData struct {
    Song       Song        `json:"song"`
    Requester  interface{} `json:"requester"`
    Event      interface{} `json:"event"`
    StartTime  string      `json:"startTime"`
    LastPlayed []Track      `json:"lastPlayed"`
    Listeners  int64       `json:"listeners"`
}

sort Track struct {
    ID       int64         `json:"id"`
    Title    string        `json:"title"`
    Sources  []interface{} `json:"sources"`
    Artists  []Album       `json:"artists"`
    Albums   []Album       `json:"albums"`
    Length int64         `json:"length"`
}

sort Album struct {
    ID         int64   `json:"id"`
    Title       string  `json:"identify"`
    NameRomaji *string `json:"nameRomaji"`
    Picture      *string `json:"picture"`
}
Enter fullscreen mode

Exit fullscreen mode

Now that we completed definitions, we are able to create the consumer to stream audio!



Create the WebSocket Shopper 🔌

Head over to the join listing and create a join.go file.

On this bundle, we’ll have to import Gorilla websocket and the 2 packages we have already created:

bundle join

import (
    "encoding/json"
    "log"
    "time"

    "github.com/raymond-design/kpop-cli/sorts"
    "github.com/raymond-design/kpop-cli/ui"

    "github.com/gorilla/websocket"
)
Enter fullscreen mode

Exit fullscreen mode

We additionally have to outline 3 package-level variables:

var conn *websocket.Conn
var performed = false
var ticker *time.Ticker
Enter fullscreen mode

Exit fullscreen mode

Let’s a create a perform to initialize the connection:

func Begin(url string) { 

}
Enter fullscreen mode

Exit fullscreen mode

(In a while, url string would be the WebSocket server url that we wish to stream from)

Now paste the next:

conn_l, _, err := websocket.DefaultDialer.Dial(url, nil)
if err != nil {
    log.Deadly("Could not hook up with websocket")
}
conn = conn_l
Enter fullscreen mode

Exit fullscreen mode

If the conn does not work, there could possibly be an error with the URL!

Now, let’s run an nameless perform Goroutine to keep up the WebSocket connection:

go func() {
        for {
            if performed {
                conn.Shut()
                break
            }
            _, msg, err := conn.ReadMessage()
            if err != nil {
                log.Deadly("Could not learn websocket message")
            }

            handleMessage(msg)
        }
}()
Enter fullscreen mode

Exit fullscreen mode

We’ll carry on sustaining the connection till program break or a learn error. The perform ought to look one thing like this:

function code

Now we have to implement that handleMessage perform!

func handleMessage(in []byte) {
    var msg sorts.SocketRes
    json.Unmarshal(in, &msg)
    swap msg.Op {
    case 0:
        var knowledge sorts.HeartbeatData
        json.Unmarshal(msg.D, &knowledge)
        setHeartbeat(knowledge.Heartbeat)
    case 1:
        var knowledge sorts.PlayingData
        json.Unmarshal(msg.D, &knowledge)
        album := "None"
        if len(knowledge.Track.Albums) > 0 {
            album = knowledge.Track.Albums[0].Title
        }
        ui.WriteToScreen(knowledge.Track.Title, knowledge.Track.Artists[0].Title, album)
    }
}
Enter fullscreen mode

Exit fullscreen mode

Within the begin perform, we regularly name this perform which is able to seize the present track knowledge and print it.

To make the code cleaner, the precise set heartbeat logic can be in two different capabilities:

func sendHeartBeat() {
    knowledge := sorts.SendData{
        Op: 9,
    }
    conn.WriteJSON(knowledge)
}

func setHeartbeat(repeat int64) {
    sendHeartBeat()
    ticker = time.NewTicker(time.Length(repeat) * time.Millisecond)
    go func() {
        <-ticker.C
        sendHeartBeat()
    }()
}
Enter fullscreen mode

Exit fullscreen mode

If you wish to learn extra about WebSockets connections, here is a useful article:
https://www.programmerall.com/article/821816187/

Lastly, we simply want a stopping perform that can get away of that for loop:

func Cease() {
    ticker.Cease()
    performed = true
}
Enter fullscreen mode

Exit fullscreen mode

Now that we’ve got these WebSockets connection capabilities, we are able to carry sound into the app!



Together with Sound!

To usher in sound, we can be importing faiface/beep:

bundle play

import (
    "log"
    "internet/http"
    "time"

    "github.com/faiface/beep"
    "github.com/faiface/beep/mp3"
    "github.com/faiface/beep/speaker"
)
Enter fullscreen mode

Exit fullscreen mode

We can even create a worldwide var from this beep bundle:

var stream beep.StreamSeekCloser
Enter fullscreen mode

Exit fullscreen mode

We’ll want two capabilities. One to play and one to cease.

The play perform is kind of easy. We’ll verify the validity of the http url after which use the beep/mp3 to beginning streaming audio contents!

func Play(url string) {
    resp, err := http.Get(url)
    if err != nil {
        log.Deadly("http error")
    }

    l_streamer, format, err := mp3.Decode(resp.Physique)
    stream = l_streamer
    if err != nil {
        log.Deadly("decoding error")
    }

    speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/10))
    speaker.Play(stream)
}
Enter fullscreen mode

Exit fullscreen mode

The cease perform is even easier. We simply shut the stream:

func Cease() {
    stream.Shut()
}
Enter fullscreen mode

Exit fullscreen mode

The code seems one thing like this:

Play Audio Code



Mission Entrypoint

Now we are able to create the entrypoint to our app! Let’s import our packages:

bundle foremost

import (
    "fmt"
    "os"
    "os/sign"

    "github.com/raymond-design/kpop-cli/join"
    "github.com/raymond-design/kpop-cli/play"
)
Enter fullscreen mode

Exit fullscreen mode

Now let’s outline the server URL that we’ll stream from:

const JPOP string = "https://pay attention.moe/fallback"
const KPOP string = "https://pay attention.moe/kpop/fallback"

const JSOCKET string = "wss://pay attention.moe/gateway_v2"
const KSOCKET string = "wss://pay attention.moe/kpop/gateway_v2"
Enter fullscreen mode

Exit fullscreen mode

By the way in which, it’s also possible to stream J-pop music now!

Now create the principle perform:

func foremost(){
    c := make(chan os.Sign, 1)
    sign.Notify(c, os.Interrupt)
    mode := "kpop"
    var stream string
    var socket string

    if len(os.Args) == 2 {
        mode = os.Args[1]
    }
}
Enter fullscreen mode

Exit fullscreen mode

We are able to use a swap perform to change between Ok-pop and J-pop music:

swap mode {
    case "kpop":
        stream = KPOP
        socket = KSOCKET
    case "jpop":
        stream = JPOP
        socket = JSOCKET
    default:
        fmt.Println("Error")
        os.Exit(1)
}
Enter fullscreen mode

Exit fullscreen mode

Now, we are able to join and begin streaming music!

join.Begin(socket)
play.Play(stream)

interrupt := make(chan os.Sign, 1)
sign.Notify(interrupt, os.Interrupt)
<-interrupt

fmt.Println("Exiting Participant")
play.Cease()
join.Cease()
Enter fullscreen mode

Exit fullscreen mode

(Discover we cease first cease decoding audio, then disconnect from the WebSockets server)

The primary perform seems like this:

Main Function



Listening to the radio 🎶🤘

  • Run a go get to get all dependencies.
  • Run go construct . within the challenge.
  • Run ./kpop-cli kpop to play Ok-pop music or ./kpop-cli jpop (If you happen to carried out J-pop).

Now you understand how to implement sound and WebSocket streaming in Go!

Additionally strive streaming different forms of knowledge sooner or later 😀

The total code could be discovered right here:
https://github.com/raymond-design/kpop-cli

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisment -
Google search engine

Most Popular

Recent Comments