OSC local network communication between Android and OSX

I am trying to use OSC to communicate between a desktop computer (OSX) and an Android phone, which are both connected to the same wifi network. I’m working in Processing with the oscP5 library but I think everything is fine in the code - this is, I think, an address issue or permissions Android side.

Here is my computer/desktop code:

import oscP5.*;
import netP5.*;

OscP5 oscP5;
NetAddress myRemoteLocation;
int colour = 255;

void setup()
{
  size(600, 600);

  /* start oscP5, listening for incoming messages at port 1200 */
  oscP5 = new OscP5(this,1200);
  println(this);
  
  /* the address of this device */
  myRemoteLocation = new NetAddress("127.0.0.1",1300);
}


void draw()
{
  background(0);
  
  fill(colour);
  circle(width/2, height/2, 200);
  
  int i = int(random(0, 200));
  if (i == 1) sendmessage();
}


void sendmessage()
{
  /* create the message */
  OscMessage myMessage = new OscMessage("/one");
  color c = color(random(0, 255), random(0, 255), random(0, 255));
  myMessage.add(c);
  
  /* send the message */
  println("Sending message: " + myMessage);
  oscP5.send(myMessage, myRemoteLocation); 
}


/* incoming osc message are forwarded to the oscEvent method */
void oscEvent(OscMessage theOscMessage)
{
  colour = theOscMessage.get(0).intValue();
}

This runs without issue and gives this in the console:

### [2024/11/7 17:12:20] PROCESS @ OscP5 stopped.
### [2024/11/7 17:12:20] PROCESS @ UdpClient.openSocket udp socket initialized.
### [2024/11/7 17:12:21] PROCESS @ UdpServer.start() new Unicast DatagramSocket created @ port 1200
### [2024/11/7 17:12:21] PROCESS @ UdpServer.run() UdpServer is running @ 1200
### [2024/11/7 17:12:21] INFO @ OscP5 is running. you (192.168.0.106) are listening @ port 1200

For some reason it does not state that the ip is 127.0.0.1 and gives 192.168.0.106 instead - this is the ip of the computer so both point to the same device but Android does this differently (see below).

Here is the code that runs on the Android phone:

import oscP5.*;
import netP5.*;

OscP5 oscP5;
NetAddress myRemoteLocation;
int colour = 255;


void setup()
{
  size(600, 600);

  /* start oscP5, listening for incoming messages at port 12000 */
  oscP5 = new OscP5(this,1300);
  println(this);
  
  /* the address of this device */
  myRemoteLocation = new NetAddress("127.0.0.1",1200);
}


void draw()
{
  background(0);
  
  fill(colour);
  circle(width/2, height/2, 200);
  
  int i = int(random(0, 200));
  if (i == 1) sendmessage();
}


void sendmessage()
{
  /* create the message */
  OscMessage myMessage = new OscMessage("/two");
  color c = color(random(0, 255), random(0, 255), random(0, 255));
  myMessage.add(c);

  /* send the message */
  println("Sending message: " + myMessage);
  oscP5.send(myMessage, myRemoteLocation); 
}


/* incoming osc message are forwarded to the oscEvent method */
void oscEvent(OscMessage theOscMessage)
{
  colour = theOscMessage.get(0).intValue();
}

and the manifest has internet and wifi permissions as follows

<?xml version="1.0" encoding="UTF-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="">
    <application android:icon="@mipmap/ic_launcher" android:label="">
        <activity android:exported="true" android:name=".MainActivity" android:theme="@style/Theme.AppCompat.Light.NoActionBar.FullScreen">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
    <uses-permission android:name="android.permission.INTERNET"/>
</manifest>

This also runs without issue and gives this in the console:

### [2024/11/7 17:29:23] PROCESS @ OscP5 stopped.
### [2024/11/7 17:29:23] PROCESS @ UdpClient.openSocket udp socket initialized.
### [2024/11/7 17:29:24] PROCESS @ UdpServer.start() new Unicast DatagramSocket created @ port 1300
### [2024/11/7 17:29:24] PROCESS @ UdpServer.run() UdpServer is running @ 1300
### [2024/11/7 17:29:24] INFO @ OscP5 is running. you (127.0.0.1) are listening @ port 1300

But, note the 127.0.0.1 ip address.

Both sketches run but don’t communicate with each other. If I run the Android sketch on the desktop computer alongside the computer sketch they communicate without issue both ways. What am I missing/overlooking here?

I think I have it working on my system, but I’m not sure how it is supposed to work.
I see this image on both of my system; macos desktop and android Samsung tablet.

The dot used to change color but now just stays white. In order to connect to my Android tablet I had to change the permissions in the Manifest by adding the following:

Reference is here: https://stackoverflow.com/questions/56266801/java-net-socketexception-socket-failed-eperm-operation-not-permitted

Prior to adding those I got an EPERM error.

The log window of the Processing app is below:

I did change your source code; I added some code to the Android side from one of the oscP5 examples (client side). Below is what I used:
Processing:

import oscP5.*;
import netP5.*;

OscP5 oscP5;
NetAddress myRemoteLocation;
int colour = 255;

void setup() {
  size(600, 600);

  /* start oscP5, listening for incoming messages at port 1200 */
  oscP5 = new OscP5(this,1200);
  println(this);
  
  /* the address of this device */
  myRemoteLocation = new NetAddress("127.0.0.1",1300);
}

void draw() {
  background(0);
  
  fill(colour);
  circle(width/2, height/2, 200);
  
  int i = int(random(0, 200));
  if (i == 1) sendmessage();
}


void sendmessage() {
  /* create the message */
  OscMessage myMessage = new OscMessage("/one");
  color c = color(random(0, 255), random(0, 255), random(0, 255));
  myMessage.add(c);
  
  /* send the message */
  println("Sending message: " + myMessage);
  oscP5.send(myMessage, myRemoteLocation); 
}

/* incoming osc message are forwarded to the oscEvent method */
void oscEvent(OscMessage theOscMessage) {
  colour = theOscMessage.get(0).intValue();
}

Android:

import oscP5.*;
import netP5.*;

OscP5 oscP5;
NetAddress myRemoteLocation;
int colour = 255;

NetAddressList myNetAddressList = new NetAddressList();
/* listeningPort is the port the server is listening for incoming messages */
int myListeningPort = 32000;
/* the broadcast port is the port the clients should listen for incoming messages from the server*/
int myBroadcastPort = 12000;

String myConnectPattern = "/server/connect";
String myDisconnectPattern = "/server/disconnect";

void setup() {
  size(600, 600);

  /* start oscP5, listening for incoming messages at port 12000 */
  oscP5 = new OscP5(this,1300);
  println(this);
  
  /* the address of this device */
  myRemoteLocation = new NetAddress("10.0.0.251",1200);
}


void draw(){
  background(0); 
  fill(colour);
  circle(width/2, height/2, 200);
  
  int i = int(random(0, 200));
  if (i == 1) sendmessage();
}


void sendmessage() {
  /* create the message */
  OscMessage myMessage = new OscMessage("/two");
  color c = color(random(0, 255), random(0, 255), random(0, 255));
  myMessage.add(c);

  /* send the message */
  println("Sending message: " + myMessage);
  oscP5.send(myMessage, myRemoteLocation); 
}

/* incoming osc message are forwarded to the oscEvent method */
//void oscEvent(OscMessage theOscMessage) {
//  colour = theOscMessage.get(0).intValue();
//}

void oscEvent(OscMessage theOscMessage) {
  /* check if the address pattern fits any of our patterns */
  if (theOscMessage.addrPattern().equals(myConnectPattern)) {
    connect(theOscMessage.netAddress().address());
    colour = theOscMessage.get(0).intValue();
    println("colour = ",colour);
  }
  else if (theOscMessage.addrPattern().equals(myDisconnectPattern)) {
    disconnect(theOscMessage.netAddress().address());
  }
  /**
   * if pattern matching was not successful, then broadcast the incoming
   * message to all addresses in the netAddresList. 
   */
  else {
    oscP5.send(theOscMessage, myNetAddressList);
  }
}

 private void connect(String theIPaddress) {
     if (!myNetAddressList.contains(theIPaddress, myBroadcastPort)) {
       myNetAddressList.add(new NetAddress(theIPaddress, myBroadcastPort));
       println("### adding "+theIPaddress+" to the list.");
     } else {
       println("### "+theIPaddress+" is already connected.");
     }
     println("### currently there are "+myNetAddressList.list().size()+" remote locations connected.");
 }

private void disconnect(String theIPaddress) {
if (myNetAddressList.contains(theIPaddress, myBroadcastPort)) {
    myNetAddressList.remove(theIPaddress, myBroadcastPort);
       println("### removing "+theIPaddress+" from the list.");
     } else {
       println("### "+theIPaddress+" is not connected.");
     }
       println("### currently there are "+myNetAddressList.list().size());
 }

Addendum:

Finally got it changing colors on the Processing side, but not the Android side. Log on Processing side shows both one and two messages.

I have to keep setting the Permissions on the Android side because apparently the editor keeps erasing them. Don’t see ‘one’ showing up on the Android side however. It appears that Android is sending the ‘two’ string and Processing app is receiving it, but Android app is not receiving the ‘one’ string that Processing app is sending.
Android console: (no ‘one’)

Fix:

If you change one line of your Android code it should now work as expected:

import oscP5.*;
import netP5.*;

OscP5 oscP5;
NetAddress myRemoteLocation;
int colour = 255;

void setup() {
  size(600, 600);

  /* start oscP5, listening for incoming messages at port 12000 */
  oscP5 = new OscP5(this,1200);
  // oscP5 = new OscP5(this,1300);
  println(this);
  
  /* the address of this device */
  myRemoteLocation = new NetAddress("127.0.0.1",1200);
}

void draw() {
  background(0);
  
  fill(colour);
  circle(width/2, height/2, 200);
  
  int i = int(random(0, 200));
  if (i == 1) sendmessage();
}

void sendmessage() {
  /* create the message */
  OscMessage myMessage = new OscMessage("/two");
  color c = color(random(0, 255), random(0, 255), random(0, 255));
  myMessage.add(c);

  /* send the message */
  println("Sending message: " + myMessage);
  oscP5.send(myMessage, myRemoteLocation); 
}


/* incoming osc message are forwarded to the oscEvent method */
void oscEvent(OscMessage theOscMessage) {
  colour = theOscMessage.get(0).intValue();
  println("incoming",colour);
}

I changed:
oscP5 = new OscP5(this,1300);
to:
oscP5 = new OscP5(this,1200);

The Android log now shows incoming data; it’s a negative number but I think that’s the color which is not being transmitted correctly. However, the Android dot now changes colors just like the Processing app.

The two permissions:

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>

Are accessed in Processing via the Android > Sketch Permissions menu. As long as they are checked there they should not be removed from the manifest:

If I am understanding the oscP5 documentation then if you use the same port in a sketches listening and sending then it is effectively just listening to itself. There are examples on the oscP5 site that demonstrate that (the demos are a little odd - not sure why anyone would need to send and receive in one sketch). I gave each of the sketches different ‘patterns’ so an easy way to eliminate the possibility of a sketch listening to itself is to add this if to the oscEvent:

// incoming osc message are forwarded to the oscEvent method.
void oscEvent(OscMessage theOscMessage)
{
   /* check if theOscMessage has the address pattern we are looking for. */  
  if (theOscMessage.checkAddrPattern("/two") == true)
  {
    colour = theOscMessage.get(0).intValue();
  }
}

I tried what you suggested and it did work but with this if stopped working (suggests it was listening to itself). Also, very annoyingly, don’t pay too much attention to the computer sketches (the Java mode sketch) console as it sees to output prints from both running sketches, computer and Android.

In the meantime I have also tried multicast (https://sojamo.de/libraries/oscp5/examples/oscP5multicast/oscP5multicast.pde), which also didn’t work, so convinced this is a ip address or firewall issue.

1 Like

I agree with your assessments. I think you can get by with just one Android permission: INTERNET. The fact remains that an oscP5 message sent by the desktop never gets into the Android device while a message does go in the other direction, from the Android device to the desktop. It appears that the Android firewall is suspect, but I’m unable to figure out how to open it up. And I agree with your observations about the Processing console logs; I saw the same thing. I wish I could be of more help; I’ve spent a lot of time on this and seem to always come up short, similar to my experiences with oscP5 in the past. I remember it as being very frustrating to work with. There is also a UDP library, but have no experience using it.

Addendum:
Good idea on the changes to oscEvent() to filter out the app talking to itself.

I’ve been barking up the wrong tree trying to use the localhost address for both systems. The key is to use the other side’s respective ip address and forget 127.0.0.1. Look up the ip address for the Android device and use it as ‘myRemoteLocation’ on the Processing side and use the ip address of your computer on the Android side. Add println code to your new oscEvent to confirm that messages are being sent both ways. For example, on Processing side println(“Message from Android”) and on the Android side println(“Message from Processing”). You should see these show up in the console logs and there will be color dots on both systems.

1 Like

I think you can get by with just one Android permission: INTERNET.

Yes I think so too. Posts on forums were circling around the three but I think this was slight overkill - in case the app being developed started to do more and more with networks.

I’ve been barking up the wrong tree trying to use the localhost address for both systems. The key is to use the other side’s respective ip address and forget 127.0.0.1.

Same here. I read the oscP5 examples setting the variable myRemoteLocation as the ip address of the device the code is running on - never dawned on me it was the opposite way around. Anyway I’ve been chasing this in parallel on Stackoverflow and someone pointed this out yesterday - java - OSC communication on local network between Android and OSX - Stack Overflow. Just swap the ips around and it works. Thanks for your help.