quiet / org.quietmodem.Quiet

Quiet for Android - TCP over sound
1.43k stars 125 forks source link

Some help needed #7

Closed emansih closed 7 years ago

emansih commented 7 years ago

Hello Brian.

I have been playing with this lib for a couple of hours and I'm stuck with a bug. When the receiver activity is first started, the logcat would show:

W/AudioRecord: AUDIO_INPUT_FLAG_FAST denied by client; transfer 1, track 44100 Hz, primary 48000 Hz

I/System.out: Read timeout

Subsequent start would show:

W/AudioRecord: AUDIO_INPUT_FLAG_FAST denied by client; transfer 1, track 44100 Hz, primary 48000 Hz

E/AudioRecord: start() status -38

I/System.out: Read timeout

From what I understand, the microphone isn't initialized as per this stackoverflow thread, which results in error status -38. But what is causing the read timeout?

The attached is the source code. Thanks for any help.

Link to pastebin

brian-armstrong commented 7 years ago

@emansih

Hi,

Sorry to hear it isn't working. From my experience you can safely ignore the line about AUDIO_INPUT_FLAG_FAST. It would be ideal if this didn't happen but I get it too and it doesn't seem to impact anything.

I'll take a closer look at this later. First, can you tell me what environment you're using, sim or device? And if sim, are you using the stock sim or Genymotion? The stock sim doesn't support mic input at all unfortunately. Also it would be good to make sure your app has the Android mic permission.

Thanks for trying Quiet :) I'll see if I can think of anything else that might cause this

brian-armstrong commented 7 years ago

From that issue you linked it looks like not all devices will support Quiet's sample rate of 44.1 kHz. Fortunately Quiet does have its own resampler, I just need to add some functionality to the Android binding to probe available resample rates and select the correct one. But I would recommend in the meantime checking that you have the RECORD_AUDIO permission

emansih commented 7 years ago

Hello,

yes, I do have <uses-permission android:name="android.permission.RECORD_AUDIO"/> in my AndroidManifest.xml . I tried this on my Xperia Z3(stock Sony) Android 6.0.1 and Nexus 7(2013)(CyannogenMod) Android 7.0.1. I have uploaded the code to Github. https://github.com/emansih/sp_ats_reboot/blob/master/app/src/main/java/org/sp/attendance/ats/nearby/reboot/ReceiveActivity.java

The System Timeout occurs when I enter ReceiveAcitivty

brian-armstrong commented 7 years ago

Ah, one thing I see is that you'll want to set the receiver into blocking mode by calling receiver.setBlocking(seconds, nano). By default it is nonblocking. This isn't very clear, and I need to update the README about this, sorry. I'd recommend printing the exception messages where you can since I generally try to attach good messages to exceptions. In this case yours is probably complaining about Async operation would block. But again, the README really needs fixed here. If you choose seconds and nano as 0 then your receiver calls will block forever until a frame is received.

I'm not able to reproduce the AudioRecord error that you're getting either in my sim or on my LG device, and I suspect it will be a showstopper for you. Once you make the receiver blocking, I suspect that reading from it would just hang forever with the error you're getting since it wouldn't be getting any audio samples.

I'll let you know once I've pushed a possible fix to that error. I'll need you to test it since I can't reproduce it.

emansih commented 7 years ago

I don't really understand what does "receiver.setBlocking(x,x)" do. Am i supposed to use that to block the UI thread or put the line of code into a background thread(runnable thread)?

emansih commented 7 years ago

The receiving code for my project is mostly copied from your README.md, so...I am not really sure what am i doing wrong

brian-armstrong commented 7 years ago

You can think of the FrameReceiver and Transmitter as behaving something like kernel sockets. They perform the actual transmitting/receiving on another thread. When the receiver decodes a frame, it places the frame into a receive queue. Calling receiver.receive() just pulls a single frame from this queue and places it in your buffer.

By default this call is nonblocking, so if there's no frame in the queue, it will fail immediately. This would be safe to call from the UI thread but you would want to poll it periodically in order to get a new frame. If you put it into blocking mode then the call will block until a frame appears in the queue. Since this does put the thread to sleep, you would want to run the blocking version from another thread.

It's up to you which strategy would be best for your application. Running in blocking mode is probably the cleanest approach but this does require running the receiver on another thread which does come with the extra complication of interthread communication. The app https://github.com/alexbirkett/QuietShare does implement the receiver call in blocking mode so it might be a helpful example

emansih commented 7 years ago

Thanks, I used the example from QuietShare to get everything to work. :D closing the issue. Once again, thanks.

brian-armstrong commented 7 years ago

Glad to hear it helped. Your feedback will help me come up with better documentation.

Does this mean you have transmitted successfully between both devices?

emansih commented 7 years ago

Yes, I have successfully transmitted ultrasonic-experimental between both devices. I'm using this lib for a school project. Initially, I was using Nearby API by Google for my project, but it has Google Play dependecy, which limits the amount of platform I can run on

brian-armstrong commented 7 years ago

Awesome! That sounds like a fun project.

When you finish the project, consider putting a writeup on Medium or somewhere like that. I think there are a lot of people who would be interested in knowing what you learn :)