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

No errors, but data not sent with TCP #81

Open
arlomedia opened this issue Dec 12, 2024 · 7 comments
Open

No errors, but data not sent with TCP #81

arlomedia opened this issue Dec 12, 2024 · 7 comments

Comments

@arlomedia
Copy link

arlomedia commented Dec 12, 2024

I'm trying to integrate JavaOSC into an Android (Kotlin) app. I need to use TCP, so I downloaded the current version of the source code but rolled back first change in 2cbbc43 so it would run on Android. Here's my code to connect to a server and send some data:

val remoteSocketAddress = InetSocketAddress("10.0.1.24", 24601)
val localSocketAddress = InetSocketAddress(this.myAddress, 24601)
val client: OSCPortOut?
try {
	client = OSCPortOutBuilder().setLocalSocketAddress(localSocketAddress).setRemoteSocketAddress(remoteSocketAddress).setNetworkProtocol(NetworkProtocol.TCP).build()
} catch (e: Exception) {
	Log.d("serverConnect", "error creating client")
	return
}

val data = arrayListOf<Any>("a", "b", "c")
App.instance.runInBackground({ // sending will throw an exception if run on the main thread
	val message = OSCMessage("/my/app/setup", data)
	try {
		client.send(message)
	} catch (e: Exception) {
		Log.d("serverConnectContinue", "error sending to server")
	}
})

For testing, I'm sending to the OSCSmith app on my Mac. That shows the Android app connecting and then disconnecting in the same second, but it doesn't show any data received. However, I can add breakpoints to the source code and see that it's getting all the way to ByteArrayListBytesReceiver.writeTo(), and the data there is correct. I don't know why the OutputStream from that point isn't delivering the data to the server.

If I change the network protocol to UDP and leave all the other code the same, the data is sent as expected. (OSCSmith can receive on TCP or UDP and with TCP can receive SLIP or PLH format. I have it set to PLH because it sounds like JavaOSC doesn't support SLIP yet.)

I think the connection and immediate disconnection is expected, because a comment in TCPTransport.send() says, "Closing the output stream is necessary...." I can't find what part of the code triggers the disconnection, but when I add a breakpoint at the end of ByteArrayListBytesReceiver.writeTo(), I can see that the disconnect doesn't happen until after all the data is written.

I'm not getting any errors in the Android Studio console. It's like the data is just disappearing. Can anyone, perhaps @daveyarwood, who added TCP compatibility, give any insight on this?

@daveyarwood
Copy link
Collaborator

I think you're on the right track. The TCP implementation automatically creates a connection when you call send, and closes the connection after the message is sent.

Off hand, I'm not sure why the message isn't being delivered. As a troubleshooting step, have you tried your same code on desktop?

@arlomedia
Copy link
Author

Thanks for the reply! Do you mean build the app for Windows or Linux? I don't think that's possible with an app built with the Android SDK. I only know how to build Android and iOS apps. (I'm using sammyOSCKit for the iOS version of this app.)

I did try running the app in the Android emulator on my Mac, but the device discovery doesn't work there, so that would be a different thing to troubleshoot. I also set up the app to send data to its own OSCPortIn, but it doesn't receive any data it sends. It does receive data sent from the iOS app, so I know the receive part is working. I've been testing it on an Android 13 tablet, but just tried on an older Android 8 tablet with the same results.

BTW, when adding breakpoints to the source code to see how far the send process gets, I could go as far as ByteArrayListBytesReceiver.writeTo(), but the next step is OutputStream.write() in a java.io class. Android Studio lets me view the source for that class and add a breakpoint to it, but it doesn't stop on the breakpoint. I think that indicates that breakpoints don't reliably work in decompiled SDK classes, not that that function isn't called.

However, after adding breakpoints to the decompiled java.net.Socket class, I'm now seeing an error in the getOutputStream() function whenever I try sending data: "Cannot find local variable 'impl'". This is triggered by the line try (OutputStream out = clientSock.getOutputStream()) in TCPTransport.send(). I don't know if this is how that class normally works, or if it indicates the socket setup is incomplete somehow. That line does return an output stream that has its impl property set:

Screenshot 2024-12-12 at 10 48 17 AM
Screenshot 2024-12-12 at 10 41 57 AM
Screenshot 2024-12-12 at 10 55 59 AM

@hoijui
Copy link
Owner

hoijui commented Dec 30, 2024

Me no Android .. someone else needs to step-up, I am afraid.

@arlomedia
Copy link
Author

arlomedia commented Jan 22, 2025

After checking, rechecking, tweaking and completely rewriting the socket code, I finally realized that JavaOSC was sending the data, but the two other apps I was sending it to (OSCKit in the iOS version of my app, and OSCSmith on my Mac) were rejecting it. That seems to be a combination of two problems:

  1. Outgoing TCP messages weren't getting a packet length header. I fixed that as shown in issue 82.

  2. The other apps are still ignoring the messages about 80% of the time. I have a suspicion that because the TCP thread closes as soon as the message is sent, it closes before the receiving app finishes processing the message and the receiving app then discards it. I've added breakpoints to OSCKit on iOS and can see something like that happening: OSCKit receives and parses the message correctly, but then it checks for the sender's IP address and if that's null, it discards the message.

So my next step is to figure out how to keep the socket open longer. So far, I can't figure out what's closing it. A comment in TCPTransport.send() says it closes when a -1 byte is sent, but there's no -1 in my outgoing data. TCPTransport has a close() function, but that's not getting called.

Before I spend more time on that, can anyone tell me, does JavaOSC support a client receiving response data from the server? I don't see any code that would handle that, and if the socket is meant to close as soon as the client sends its message, I don't know how that would work.

@daveyarwood
Copy link
Collaborator

My understanding is that OSC is a one-way protocol, but I could be wrong about that. Assuming I'm right, you could always create a second port going the other way.

@arlomedia
Copy link
Author

Ah, I guess the way clients and servers interact is beyond the scope of the OSC protocol, so different library authors are implementing that differently. OSCKit on iOS includes an OSCTcpClient object that can send data to another device (a server) and read a response back from it, but to do that here I'll have to create both an output and input port. Thanks for the course correction.

First I'll have to figure out why other libraries are dropping most of the messages sent from JavaOSC, whether that's due to the socket closing too quickly or some other reason.

@arlomedia
Copy link
Author

As a test, I modified the send function to repeat all outgoing data 10 times. Then OSCKit on iOS read the data every time. Sometimes it read it once, or 3 or 6 times, before the connection closed. This seems to support my hunch that the socket is closing before the receiving app is done parsing the data.

However, when I modified the send function to simply add 1000 0's at the end of the data, or 999 0's and a 1, the problem returned. So I don't know exactly what is happening there.

In an attempt at a related solution, I tried setting setSoLinger(true, 5) on the client socket, and then setKeepAlive(true), but neither had any effect.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants