Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

asticode/go-astisrt

Open more actions menu

Repository files navigation

GoReportCard GoDoc Test Coveralls

SRT server, client and socket in GO

First off, a big thanks to the official GO bindings that was an amazing source of inspiration for this project.

However a few things bothered me in it therefore I decided to write my own bindings with a few goals in mind:

  • split the API between both high level entities, similar to GO's net/http entities, with very guided methods (ListenAndServe, Shutdown, Dial, Read, Write etc.) and low level entities, closer to C, with I-should-know-what-I-am-doing-before-using-them methods (Socket, etc.)
  • provide named and typed option setters and getters
  • make sure all errors are handled properly since they are thread-stored and ban the use of runtime.LockOSThread()
  • make sure there's a context specific to each connection in high level methods
  • make sure pointers are the same between the ListenCallback and Accept(), and between the ConnectCallback and Connect()
  • only use blocking mode in high level entities

astisrt has been tested on v1.5.3.

Examples

Examples are located in the examples directory

WARNING: the code below doesn't handle errors for readibility purposes. However you SHOULD!

Server

Go to full example

// Capture SIGTERM
doneSignal := make(chan os.Signal, 1)
signal.Notify(doneSignal, os.Interrupt)

// Create server
s, _ := astisrt.NewServer(astisrt.ServerOptions{
    // Provide options that will be passed to accepted connections
    ConnectionOptions: []astisrt.ConnectionOption{
        astisrt.WithLatency(300),
        astisrt.WithTranstype(astisrt.TranstypeLive),
    },

    // Specify how an incoming connection should be handled before being accepted
    // When false is returned, the connection is rejected.
    OnBeforeAccept: func(c *astisrt.Connection, version int, streamID string) bool {
        // Check stream id
        if streamID != "test" {
            // Set reject reason
            c.SetPredefinedRejectReason(http.StatusNotFound)
            return false
        }

        // Update passphrase
        c.Options().SetPassphrase("passphrase")

        // Add stream id to context
        *c = *c.WithContext(context.WithValue(c.Context(), ctxKeyStreamID, streamID))
        return true
    },

    // Similar to http.Handler behavior, specify how a connection
    // will be handled once accepted
    Handler: astisrt.ServerHandlerFunc(func(c *astisrt.Connection) {
        // Get stream id from context
        if v := c.Context().Value(ctxKeyStreamID); v != nil {
            log.Printf("main: handling connection with stream id %s\n", v.(string))
        }

        // Loop
        for {
            // Read
            b := make([]byte, 1500)
            n, _ := c.Read(b)

            // Log
            log.Printf("main: read `%s`\n", b[:n])

            // Get stats
            s, _ := c.Stats(false, false)

            // Log
            log.Printf("main: %d total bytes received\n", s.ByteRecvTotal())
        }
    }),

    // Addr the server should be listening to
    Host: "127.0.0.1",
    Port: 4000,
})
defer s.Close()

// Listen and serve in a goroutine
doneListenAndServe := make(chan error)
go func() { doneListenAndServe <- s.ListenAndServe(1) }()

// Wait for SIGTERM
<-doneSignal

// Create shutdown context with a timeout to make sure it's cancelled if it takes too much time
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

// Shutdown
s.Shutdown(ctx)

// Wait for listen and serve to be done
<-doneListenAndServe

Client

Go to full example

// Capture SIGTERM
doneSignal := make(chan os.Signal, 1)
signal.Notify(doneSignal, os.Interrupt)

// Dial
doneWrite := make(chan err)
c, _ := astisrt.Dial(astisrt.DialOptions{
    // Provide options to the connection
    ConnectionOptions: []astisrt.ConnectionOption{
        astisrt.WithLatency(300),
        astisrt.WithPassphrase("passphrase"),
        astisrt.WithStreamid("test"),
    },

    // Callback when the connection is disconnected
    OnDisconnect: func(c *astisrt.Connection, err error) { doneWrite <- err },

    // Addr that should be dialed
    Host: "127.0.0.1",
    Port: 4000,
})
defer c.Close()

// Write in a goroutine
go func() {
    defer func() { close(doneWrite) }()

    // Loop
    r := bufio.NewReader(os.Stdin)
    for {
        // Read from stdin
        t, _ := r.ReadString('\n')

        // Write to the server
        c.Write([]byte(t))
    }
}()

// Wait for either SIGTERM or write end
select {
case <-doneSignal:
    c.Close()
case err := <-doneWrite:
    log.Println(err)
}

// Make sure write is done
select {
case <-doneWrite:
default:
}

Socket

Listen

Go to full example

// Create socket
s, _ := astisrt.NewSocket()
defer s.Close()

// Set listen callback
s.SetListenCallback(func(s *astisrt.Socket, version int, addr *net.UDPAddr, streamID string) bool {
    // Check stream id
    if streamID != "test" {
        // Set reject reason
        s.SetRejectReason(1404)
        return false
    }

    // Update passphrase
    s.Options().SetPassphrase("passphrase")
    return true
})

// Bind
s.Bind("127.0.0.1", 4000)

// Listen
s.Listen(1)

// Accept
as, _, _ := s.Accept()

// Receive message
b := make([]byte, 1500)
n, _ := as.ReceiveMessage(b)

// Log
log.Printf("main: received `%s`\n", b[:n])

Connect

Go to full example

// Create socket
s, _ := astisrt.NewSocket()
defer s.Close()

// Set connect callback
doneConnect := make(chan error)
s.SetConnectCallback(func(s *astisrt.Socket, addr *net.UDPAddr, token int, err error) {
    doneConnect <- err
})

// Set passphrase
s.Options().SetPassphrase("passphrase")

// Set stream id
s.Options().SetStreamid("test")

// Connect
s.Connect("127.0.0.1", 4000)

// Send message
s.SendMessage([]byte("this is a test message"))

// Give time to the message to be received
time.Sleep(500 * time.Millisecond)

// Close socket
s.Close()

// Wait for disconnect
<-doneConnect

Install srtlib from source

You can find the instructions to install srtlib here.

However if you don't feel like doing it manually you can use the following command:

$ make install-srt

srtlib will be built from source in a directory named tmp and located in you working directory.

For your GO code to pick up srtlib dependency automatically, you'll need to add the following environment variables:

(don't forget to replace {{ path to your working directory }} with the absolute path to your working directory)

export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:{{ path to your working directory }}/tmp/v1.5.3/lib/",
export CGO_LDFLAGS="-L{{ path to your working directory }}/tmp/v1.5.3/lib/",
export CGO_CFLAGS="-I{{ path to your working directory }}/tmp/v1.5.3/include/",
export PKG_CONFIG_PATH="{{ path to your working directory }}/tmp/v1.5.3/lib/pkgconfig",

About

SRT server, client and socket in GO

Topics

Resources

License

Stars

Watchers

Forks

Contributors 2

  •  
  •  
Morty Proxy This is a proxified and sanitized view of the page, visit original site.