Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

can not receive messages from supercollider server #6

Open
briansorahan opened this issue Feb 4, 2015 · 5 comments
Open

can not receive messages from supercollider server #6

briansorahan opened this issue Feb 4, 2015 · 5 comments

Comments

@briansorahan
Copy link
Contributor

I need support for the laddr argument of net.DialUDP to be able to receive messages from scsynth (the supercollider server program). I have a changeset in my fork that changes the signature of NewOscClient from

func NewOscClient(addr string, port int) (client *OscClient)

to

func NewOscClient(laddr, raddr *net.UDPAddr) (client *OscClient)

Would you be interested in supporting something like this?
I have searched pretty thoroughly for evidence of how to configure scsynth to send to a particular addr/port, but it seems like currently the only way to do this is to include the local addr in messages you send.
See this thread for a discussion.

Also, here is a test program I wrote with my local changes that successfully received a status reply from scsynth:

package main

import (
    "fmt"
    "github.com/briansorahan/go-osc/osc"
    "log"
    "net"
)

const (
    addr       = "127.0.0.1"
    remotePort = 57110
    localPort  = 57120
)

func main() {
    server := osc.NewOscServer(addr, localPort)

    statusChan := make(chan *osc.OscMessage)
    server.AddMsgHandler("/status.reply", func(msg *osc.OscMessage) {
        statusChan <- msg
    })

    cerr := make(chan error)
    go func() {
        cerr <- server.ListenAndDispatch()
    }()
    go func() {
        err := <-cerr
        if err != nil {
            log.Fatal(err)
        }
    }()

    localAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", addr, localPort))
    if err != nil {
        log.Fatal(err)
    }
    remoteAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", addr, remotePort))
    if err != nil {
        log.Fatal(err)
    }

    client := osc.NewOscClient(localAddr, remoteAddr)
    msg := osc.NewOscMessage("/status")
    client.Send(msg)

    status := <-statusChan
    osc.PrintOscMessage(status)
}

Here is a link to the scsynth command reference in case you're interested. There is mention there (for the /notify message) of the fact that scsynth replies to your return address.

@briansorahan
Copy link
Contributor Author

Another way to implement this could be to include a method:

func (client *OscClient) AddLocalAddr(addr string, port int)

which could add the laddr field to the OscClient. This way we wouldn't have to change the signature of NewOscClient.
@hypebeast I'll wait to send a PR until I hear which you would prefer.

@hypebeast
Copy link
Owner

Hi Brian. I think it would be great to add support for supercollider. Let me have a look at it. I think I'll have some time on friday.

@briansorahan
Copy link
Contributor Author

Cool. I think I'll prepare a PR with my second suggestion. It has zero impact on existing client code, and would let me accomplish what I need.

@hypebeast
Copy link
Owner

Great. That sounds good :)

@briansorahan
Copy link
Contributor Author

So I'm not actually sure why my first code snippet on this thread worked, but after using SetLocalAddr to communicate with scsynth I started getting bind errors saying the address/port were already in use. What was happening was that I was binding a server to an address/port and setting that address/port as the localAddr of a client, then using that client to communicate with scsynth. It seems that setting localAddr on the client causes it to bind implicitly to this addr when you send a message, but it can't because I've already bound a server to the addr/port.

Here is the example again (updated to reflect the latest API changes):

package main

import (
    "fmt"
    "github.com/hypebeast/go-osc/osc"
    "log"
    "time"
)

const (
    addr       = "127.0.0.1"
    remotePort = 57110
    localPort  = 57120
)

func main() {
    server := osc.Server{
        fmt.Sprintf("%s:%d", addr, remotePort),
        osc.NewOscDispatcher(),
        time.Second,
    }

    statusChan := make(chan *osc.Message)
    server.Handle("/status.reply", func(msg *osc.Message) {
        statusChan <- msg
    })

    cerr := make(chan error)
    go func() {
        cerr <- server.ListenAndServe()
    }()
    go func() {
        err := <-cerr
        if err != nil {
            log.Fatal(err)
        }
    }()

    client := osc.NewClient(addr, remotePort)
    client.SetLocalAddr(addr, localPort)
    msg := osc.NewMessage("/status")
    client.Send(msg)

    status := <-statusChan
    osc.PrintMessage(status)
}

If in one terminal I do

$ scsynth -u 57710

then in another (with the above example in a file called localAddr.go)

$ go run localAddr.go

I get

2015/03/23 17:30:08 listen udp 127.0.0.1:57110: bind: address already in use
exit status 1

I think the cleanest way of getting around this is actually to implement a Send method on the Server type.

Here is a first pass I wrote:

func (self *Server) SendTo(addr net.Addr, packet OscPacket) (err error) {
    if self.conn == nil {
        return fmt.Errorf("connection not initialized")
    }
    data, err := packet.ToByteArray()
    if err != nil {
        self.conn.Close()
        return err
    }

    written, err := self.conn.WriteTo(data, addr)
    if err != nil {
        fmt.Println("could not write packet")
        self.conn.Close()
        return err
    }
    if written != len(data) {
        errmsg := "only wrote %d bytes of osc packet with length %d"
        return fmt.Errorf(errmsg, written, len(data))
    }

    return nil
}

This implementation does not work with your master branch because there is no longer a conn member of the Server type, but I'd like to hear your thoughts about adding this method and removing Client.SetLocalAddr.

@briansorahan briansorahan reopened this Mar 23, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants