Open Sound Control

"Open Sound Control (OSC) is an open, transport-independent, message-based protocol developed for communication among computers, sound synthesizers, and other multimedia devices." (from http://opensoundcontrol.org/spec-1_0)

There are a number of OSC implementations, including a couple in C# (1, 2), but I decided to roll my own and make it freely available. This implementation sits atop the .NET 3.5 Framework and uses TCP or UDP as the transport protocol. It includes support for OSC Messages and Bundles, and supports the following payload data types: Int32, Int64, Float, Double, String, and Blob (byte array).

The OscServer class is at the heart of the system, and includes support for unicast, broadcast, and multicast. As OSC packets, bundles, and messages are received corresponding events are fired. Additionally, the system will (optionally) filter OSC address patterns that the user registers.

The package includes simple client and server examples in both C# and Visual Basic.NET.

Downloads (Current Version: 1.5.0.0 – Release Date: 5/1/2010)

Previous Revisions

40 Comments so far

  1. [...] Open Sound Control [...]

  2. ben on February 17th, 2009

    I’ve been looking for an open source OSC library for .net that works well. You made my day!

  3. Paul on February 17th, 2009

    Thanks Ben. I appreciate the positive feedback.

    Paul

  4. Rich on May 9th, 2009

    This is working great!

    Only thing was I found that the UDP listener thread was polling for available bytes and using 100% CPU in UdpServer.Start.

    I commented that out as below so it block in Receive until packets arrive. Any reason this shouldn’t work?

    while (mAcceptingConnections)
    {
    // This was eating CPU, so block until we get data
    // if (udpClient.Available > 0)
    // {
    IPEndPoint remoteEndPoint = null;
    byte[] data = udpClient.Receive(ref remoteEndPoint);
    if (data != null && data.Length > 0)
    {
    OnDataReceived(new UdpDataReceivedEventArgs(remoteEndPoint, data));
    }
    // }
    }

  5. Paul on May 9th, 2009

    Hi Rich,

    You’re right, doing a spin like that was a poor decision — and guaranteed to peg the CPU. The problem with not checking the udpClient.Available property and simply blocking on the Receive call, is that you can’t interrupt the call — even with a Thread.Abort or Thread.Interrupt. This means, that calling Stop on the UdpServer, which toggles the volatile bool mAcceptingConnections, won’t do anything until the Receive call finishes. If the UdpServer is continuously receiving data, you’ll never notice this. But if not, the Receive call will never finish and the Stop won’t actually stop.

    So a better route is a paired BeginReceive/EndReceive call for asynchronous communication without a while loop. I’ve written this and will upload a new release shortly.

    Paul

  6. [...] Open Sound Control [...]

  7. Paul on May 11th, 2009

    Rich,

    I’ve uploaded a new release which addresses the performance issue. Thanks for the heads up.

    Paul

  8. Chris on May 21st, 2009

    Hey Paul,

    I’ve encountered an unhandled error exception in the UdpServer object used in the client on line 276:

    byte[] data = udpClient.EndReceive(asyncResult, ref ipEndPoint);

    An unhandled exception of type ‘System.Net.Sockets.SocketException’ occurred in System.dll

    Additional information: The I/O operation has been aborted because of either a thread exit or an application request

    I corrected it by blocking lines 276 to 280 and catching the socket exception, while leaving the receive function call in the original try catch.

    Is there any reason why this shouldn’t work for continual use?

    Chris

  9. Paul on May 21st, 2009

    Hi Chris,

    I haven’t encountered that error in any of my testing. The EndReceive() call is paired with the BeginReceive() calls that originate in the Start() method and are continued after each EndReceive() completes. I assume what you mean by “blocking out lines 276-280″ is that you’re commenting out those calls — and within that the OnDataReceived() call is pretty critical. Also, if you’ve changed BeginReceive() to Receive(), you’re changing the behavior from asynchronous communication to a blocking call.

    In short, I’m not entirely clear on why you’re seeing the error and what your fix entails. If you’d like to send me your changes, I’d be happy to take a look. My email address is pvarchol [at] bespokesoftware.org.

    One last thought… are you interrupting the UdpServer thread using a Thread.Kill() anywhere? And is this exception happening in the included demo client/server?

    Paul

  10. Paul on May 22nd, 2009

    Chris,

    I’ve found the problem. With the 1.1 release of the library I changed to asynchronous communication using BeginReceive()/EndReceive(). However, I didn’t change the OscServer.Start() method — which called the underlying UdpServer.Start() in a separate thread. This was necessary in version 1.0 because the UdpServer didn’t use asynchronous communication and I didn’t want to block on the Start() call.

    When I went to asynchronous communication, I left the Start call in its own thread, but this thread now exists very rapidly. I found a 1-line blurb about this at: http://msdn.microsoft.com/en-us/library/dxkwh6zw.aspx which states that

    “All I/O initiated by a given thread is canceled when that thread exits. A pending asynchronous operation can fail if the thread exits before the operation completes.”

    Interestingly, I didn’t see this on my development machine — but when I tested this on a slightly faster computer the SocketException with error code 995 cropped up. This is the nature of thread exceptions and concurrent code — sometimes the bugs are intermittent. Anyhow, I’ve fixed the problem simply by making OscServer.Star()t call UdpServer.Start() in the OscServer thread. I’ve released version 1.2 of the library which includes this change.

    Paul

  11. Chris on May 22nd, 2009

    Paul,

    Thank you for the quick response and solution! Much appreciated. I’ll continue playing with it today :)

    Chris

  12. [...] Open Sound Control [...]

  13. bobo on August 7th, 2009

    how do you reference an appended value to an oscmessage from OscMessageReceivedEventArgs

    Message.append(“Hello”);

  14. Paul on August 8th, 2009

    You reference all appended values through the Data property — an array of objects. For example: mMessage.Data[index].

  15. Frank on January 6th, 2010

    Hi,
    thank you very much for providing this library.
    Is there any other example application (demo) available? Or a more detailled description of the included demo?

    Who can help me to understand what happens here in the demo (server)? :
    sMessage.Append(memoryStream.ToArray());

    Why the server creates the OSC message?

    Sorry for my stupid questions, but I would like to understand this application.

    Thanks
    Best regards Frank

  16. Paul on January 7th, 2010

    Hi Frank,

    The OSC message is created before the statement you’re referencing. Specifically, the message is created on line 24 of Program.cs with the following:

    sMessage = new OscMessage(new IPEndPoint(IPAddress.Loopback, Port), AliveMethod, sOscClient);

    That statement constructs a new OscMessage instance with the source endpoint of the local computer (IPAddress.Loopback and a port number), an OSC address (AliveMethod == “/osctest/alive”), and an OscClient instance if the transport type is TCP/IP (default is UDP).

    With UDP, the OscMessage is transmitted with sOscMessage.Send(Destination). Using TCP it’s simply sOscMessage.Send().

    The statement you asked about:

    sMessage.Append(memoryStream.ToArray());

    Appends a piece of data to the message. In this demo, that piece of data is a JPEG image that gets loaded into a MemoryStream object. The MemoryStream class has a ToArray() method that converts its contents to a byte array. The Bespoke OSC Library supports byte arrays, integers (32- and 64-bit) , floats, doubles, and strings. Thus, the OscMessage.Append() method is a generic method that accepts all of these data types.

    Hope this helps.

    Paul

  17. roxlu on January 27th, 2010

    Hi! Thanks for this perfect and clean implementation.. though I’m wondering how I can create a UDP client which listens on port 3333?

    I’ve been looking at the samples but found it a bit confusing that the ‘client’ examples creates a OscServer object and that the ’server’ example creates a OscClient object.. ?

    Did I miss something?

    Thanks
    Roxlu

  18. Paul on January 27th, 2010

    Hi Roxlu,

    I know, the terms “client” and “server” are a bit confusing. This terminology comes from the OSC specification (http://opensoundcontrol.org/spec-1_0). It states: “The unit of transmission of OSC is an OSC Packet. Any application that sends OSC Packets is an OSC Client; any application that receives OSC Packets is an OSC Server.”

    So, if you’re trying to create an application that listens for OSC packets, you’ll create a Bespoke.Common.Osc.OscServer object. In my OscDemo project (included with the distribution) I name the two sub-projects Client and Server with the more traditional meaning of the terms. In this demo, the “Client” project listens for OSC packets and the “Server” project sends them.

    Creating an OscServer object for UDP, bound to the loopback address (127.0.0.1) and port 3333 is as simple as:

    OscServer oscServer = new OscServer(TransportType.Udp, IPAddress.Loopback, 3333);

    Then you’ll attach a handler to the oscServer.MessageReceived event and start the server with oscServer.Start();

    Hope this helps.

    Paul

  19. Rob on February 24th, 2010

    Hello!

    I’m having some trouble getting this library working in VB.NET.

    I’ve done my best to convert the client demo from c# to vb.net

    however theres just one line that’s troubling me.

    sOscServer.MessageReceived = new OscMessageReceivedHandler(sOscServer_MessageReceived);

    Im assuming this add’s the handler for when a message is recieved. I Wondered if you could help me? or provide a basic VB.NET client (Listen on a port and output any data)

    any help is appriciated. Thanks a lot, Rob.

  20. Paul on February 25th, 2010

    Hi Rob,

    Yes, the code in question attaches a handler to the MessageReceived event. In VB.NET this is accomplished by declaring the OscServer object “WithEvents” and creating a function with the suffix: “Handles OscServerVariableName.MessageReceived”.

    I went a step further and ported the C# samples to VB.NET and uploaded them with revision 1.4. If you have any questions just shout.

    Paul

  21. [...] Open Sound Control [...]

  22. Rob on February 26th, 2010

    Paul, Thanks a lot.

    In my code I mistaked WithEvents for AddHandler.

    The source code you provided is working flawlessly, can’t thank you enough for your help.

    Rob.

  23. deadlock on April 3rd, 2010

    Hi Paul!

    I#m using your lib to build a tool to remote control Resolume Avenue via OSC. My Problem is that after I initialised the application and the oSC-sender like this:

    Dim adress As IPAddress = IPAddress.Parse(“127.0.0.1″)

    Dim port As Integer = 7000
    Dim udp As TransportType = TransportType.Udp

    Dim oscMessage As OscMessage
    Dim oscClient As New OscClient

    oscClient.Connect(adress, port)
    oscMessage = New OscMessage(New Net.IPEndPoint(adress, port), “/composition/disconnectall 1″, oscClient)

    But everytime I call these codelines i get an Error which says :”System.Net.Sockets.SocketException wurde nicht behandelt.
    ErrorCode=10061
    Message=”No connection could be made because the target machine actively refused it 127.0.0.1:7000″
    NativeErrorCode=10061
    Source=”System”
    StackTrace:
    at System.Net.Sockets.Socket.DoConnect(EndPoint endPointSnapshot, SocketAddress socketAddress)
    at System.Net.Sockets.Socket.Connect(EndPoint remoteEP)
    ……..”

    I have no clue how to fix this.

    When the app tries to connect to 127.0.0.1:7000 my firewall asks to pass the programm an i let it pass.

    I would like to hear from you!

    mfg deadlock

  24. Paul on April 3rd, 2010

    Hi deadlock,

    It’s likely that you aren’t intending to use TCP as the transport protocol; but wish to use UDP instead. However, the OscClient class is specifically for TCP communication. Have a look at the Visual Basic sample included with the distribution for the usage differences between TCP and UDP. UDP is a connection-less protocol and requires no explicit connection (which is what you’re invoking with the call to oscClient.Connect()). Instead, you only need to use the OscMessage class and its Send() method.

    Paul

  25. deadlock on April 6th, 2010

    Hi again Paul!

    Thanks for your helping hand. Your tip showed me the right way to do it. I will post my source code for everyone:
    ””””””””””””””’
    Dim adress As IPAddress = _ IPAddress.Parse(“127.0.0.1″)

    Dim port As Integer = 7123

    Dim destination As IPEndPoint = _ Net.IPEndPoint(adress.Loopback, port)

    Dim oscMessage As OscMessage
    oscMessage = New OscMessage(destination, “/layer2/clip0/connect 1″, oscClient)

    oscMessage.Send(destination)
    ”””””””””””””””””’

    oscClient is globaly declared without further settings.

    Now i modified your sample code so it is recieving the message at port 7123.

    But, unfortunately , Resolume Avenue is not reacting to it. I hope its just problem tracing and solving.

    ( If you have some time you can look yourself into the application. The demo is freely available at http://www.resolume.com/download/)

    But thanks for all!

    deadlock

  26. deadlock on April 6th, 2010

    Hi again!

    I’ve finally found out, that I forgot to give the adress a value via oscMessage.Append(value).

    Now everything works fine!

    Thanks again for all the help. Pretty handy Site and library!

  27. Paul on April 6th, 2010

    Glad to hear you’ve found a solution and that the software’s been useful for you.

    Paul

  28. [...] scriptable and flexible audio toolbox. The combined product is named Max for Live. There are existing C# libraries that allow Max, and hence Max for Live, to be controlled over a TCP [...]

  29. Thomas on June 20th, 2010

    Hi, I wanna use liveosc to create a c# control program for ableton live.

    1.Im a little confused if i should edit any .py-files for this to work, or just copy the folder into live.

    2. When creating a OscServer-object in the example, an “AliveMessage” is somehow attached. What is this for?

    Lets just say i wanna monitor som given live listener in my c# program. Whats the code for this?

  30. Paul on June 20th, 2010

    Hi Thomas,

    I’m afraid I can’t speak to any settings within Ableton Live — you’ll need to determine if you need to edit any python files.

    To your second question, the AliveMessage is merely an example. Understand that Open Sound Control is a specification for communicating messages — it doesn’t define them. My library implements this specification and makes it easy (hopefully) to send messages via OSC. You’ll need to determine what OSC messages Ableton Live is sending that you need to listen for. You can adapt the OscServer sample and replace the AliveMessage with those messages specific to Ableton Live.

    Paul

  31. Thomas on June 20th, 2010

    Thanks for your answer!

    Im still having a hard time understanding…

    Should I create one OscServer-object per message want to listen to?

  32. Paul on June 20th, 2010

    Hi Thomas,

    Nope, you only need 1 OscServer object — this is the class that sets up the communication via OSC. For every message you wish to receive, you call OscServer.RegisterMethod(“OscMessageAddress”). Where “OscMessageAddress” is the OSC structured address of your message.

    If you have any further questions, let’s take this conversation to the Forums (http://www.bespokesoftware.org/wordpress/?page_id=141). That’s a much better area for such topics.

    Paul

  33. renasis on August 15th, 2010

    Hello,

    The library works great, thanks! Is is possible to send UDP messages on the same pc port everytime?

    Thanks,

    -ren

  34. Paul on August 16th, 2010

    Hello ren,

    If I understand your question correctly, you’re asking if it’s possible to use the same outgoing port with each UDP datagram. If this is your question, I’m unaware of a mechanism to do this. Certainly you can send TO the same destination port with each datagram, but I don’t believe you can request which local port you bind to when sending outbound UDP packets. Quite the opposite when using TCP.

    Paul

  35. Paul on August 17th, 2010

    Paul,

    Yes, that is what I am asking, to send out on the same pc port everytime. I think you can specify the local port in the UDPClient constructor, ref ->http://msdn.microsoft.com/en-us/library/system.net.sockets.udpclient.udpclient.aspx. I suspect that the OscPacket class could be modified to allow this.

    Thanks,

    -ren

  36. Paul on August 17th, 2010

    I stand corrected, that constructor does indeed allow you to bind a UDP connection to a specific local port. I just experimented with this a bit, and found it to be problematic. The constructor behaves as advertised, but the reality of binding to the same port is troublesome when placed within OscPacket’s ctor. Not saying I can’t make this change, but it’s not a simple one-liner in the OscPacket ctor. Better might be to build a UdpClient within an overloaded OscPacket.Send() method that takes a source and a destination. You just eat the cost of the UdpClient instantiation with each Send.

    Paul

  37. Paul on August 17th, 2010

    Here’s the method I suggested. Not the last word in this, but for a 10-minute investigation, this is what I’ve got.

    public void Send(IPEndPoint source, IPEndPoint destination)
    {
    byte[] data = ToByteArray();
    UdpClient udpClient = new UdpClient(source);
    udpClient.Send(data, data.Length, destination);
    udpClient.Close();
    }

  38. renasis on August 19th, 2010

    Paul,

    Thanks, works great!

    -ren

  39. renasis on August 19th, 2010

    Paul,

    Got a new one for you. I able to udp send fine. Now I am want to receive osc msg. I send msg via click of button, like so:
    Dim smessage As New OscMessage(New IPEndPoint(IPAddress.Loopback, port), “/pwm/6″, x)
    smessage.Send(Local, Destination)

    But I am having problems receiving msgs destined for Local(my pc). I tried setting up via click of button(Server sent to Local params):

    sOscServer = New OscServer(TransportType, ServerAddress, ServerPort)
    sOscServer.RegisterMethod(“/pwm/6″)
    sOscServer.Start()

    Sub sOscServer_MessageReceived(ByVal sender As Object, ByVal e As OscMessageReceivedEventArgs) Handles sOscServer.MessageReceived

    Debug.WriteLine(String.Format(“Message Received [{0}]: {1}”, e.Message.SourceEndPoint.Address, e.Message.Address))
    End Sub

    All params OK, device sending to pc, but no debug msgs. Do you know how I can receive msgs?

    Thanks,

    -ren

  40. Paul on August 20th, 2010

    Hi ren,

    If you don’t mind, let’s take this conversation to the forums: http://www.bespokesoftware.org/wordpress/?page_id=141/open-sound-control-library/udp-send-problem/#p29

    Paul

Leave a reply