ge0rg / aprsdroid

APRSdroid - Geo-Location for Radio Amateurs
https://aprsdroid.org/
GNU General Public License v2.0
506 stars 97 forks source link

recorder.read() = -3 in AFSK mode #138

Open tarrinr opened 8 years ago

tarrinr commented 8 years ago

I am using the latest OSM version of APRSdroid, with AFSK and a cable I made connected to a baofeng. If I start tracking and wait a few minutes, it tells me the APRS service stopped, and in the log it says java.lang.RuntimeException: recorder.read() = -3.

ge0rg commented 8 years ago

This is a bug I'm hunting for for a long time already. Unfortunately, I don't know what is causing it or how to reproduce. It seems to be some kind of race condition (or maybe an out-of-memory thing?).

Can you provide any context to when or why this is happening? Does it also happen with the HQ demodulator disabled in the AFSK settings?

emiliogon commented 8 years ago

Hi Georg,

I am also having this issue with the same exception. This is the Play Store version on a Galaxy Nexus running Cyanogen 12.1, using a 4-pin cable for AFSK over audio I/O. I have the phone in "Do Not Disturb" mode to suppress notifications.

This was definitely doing it with the HQ demodulator enabled. Sometimes it happens within 30 seconds of starting the service, sometimes it takes 5-10 minutes.

It doesn't seem to do it with the HQ demod disabled. This is disappointing, since the HQ demod definitely seems to pull in more packets. However, I did have the service mysteriously stop once when switching apps a couple times, but there was no runtime exception.

I have attached a logcat from around the crash: aprsdroid-AFSKcrash-logcat.txt

I like the app, thanks!

tarrinr commented 8 years ago

I was about to reply that it only happened when HQ was enabled, but then the service stopped for me as well. I'm not sure if it's related to this problem, but I also can't say I'm 100% positive its the HQ demodulator... I can't find any reliable way to repeat the exception.

tarrinr commented 8 years ago

You probably already know this, but this is what I dug up by glancing over the code.

I assume the problem is starting in AfskDemodulator.scala. I've copied over some code that might not be happy.

val BUF_SIZE = 8192 val buffer_s = new Array[Short](BUF_SIZE) var recorder : AudioRecord = null recorder = new AudioRecord(in_type, samplerate, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, 4*BUF_SIZE) recorder.startRecording(); val count = recorder.read(buffer_s, 0, BUF_SIZE)

The last line is returning a -3, which means "ERROR_INVALID_OPERATION if the object isn't properly initialized".

In Emilio's log, it shows several D/APRSdroid.AfskDemod(17501): read 8192 samples ... which is good. But then it shows D/APRSdroid.AfskDemod(17501): read -3 samples which is the error we see. Right before that however, it says D/APRSdroid.AfskDemod(17501): read 2048 samples 2048 is one fourth of 8192, and you used 4*BUF_SIZE when creating recorder.

Here are the lines in the log before the above W/AudioPolicyManager( 139): stopInput() unknown input 2151 W/AudioPolicyManager( 139): releaseInput() releasing unknown input 2151 W/AudioPolicyManager( 139): startInput() unknown input 2152 W/AudioRecord(17501): restoreRecord_l() failed status -22

The first three errors are coming from AudioPolicyManager.cpp ssize_t index = mInputs.indexOfKey(input); if (index < 0) { LOGW("startInput() unknow input %d", input); return BAD_VALUE; }

Could it be that it's not staying connected to our cords? The log says several times that it's removing or adding sec_jack. Sometimes when I'm tracking, audio comes out of my phone's speakers even though the cable is plugged in to the headphone jack.

emiliogon commented 8 years ago

Here's another data point: the HQ demod is rock solid on an old HTC EVO 4G running Android 2.3.5. I just left it running for several hours and it was fine. This EVO definitely doesn't catch as many packets as the GNex, though; I'm not sure if it's the audio input (might be lower) or the slower CPU.

I had also noticed a couple moments where an APRS transmission came from the phone's internal speaker when the radio was plugged in, as well as a lot of those sec_jack events in logs.

ge0rg commented 8 years ago

I was thinking it might be a race condition in the code, or maybe something related to multi-core CPUs, but I never was able to reproduce the problem. Maybe I really need to work around it by checking for -3 and re-initializing the audio...

tarrinr commented 8 years ago

I have a theory, and I hope to try it out tonight. I just got done reading the android TRRS spec here https://source.android.com/devices/accessories/headset/specification.html There have been some people saying that when they plug in their cable, it opens up their music player, and I think that might be connected. The mic input is biased 2.2v to power the voltage divider buttons. It says in the spec that the mic must have over 1000 ohm impedance. Is it possible that since we're plugging it straight into a speaker out and not into an external microphone that the impedance is too low between ground so it's activating the mic buttons, throwing the insertion detection, or TRS vs TRRS when the signal starts coming through? That would also explain why audio sometimes comes out of the internal speaker, and why it's hard to reproduce... I want to throw a pull-down resistor on the phone's mic line and see if it changes anything.

Emilio, How did you make your cable?

emiliogon commented 8 years ago

Mine is pretty simple, I just followed the pinout here, including 510 Ohm resistors.

Still, the exact same radio (UV-5R V2+) and cable work fine using the same settings on my EVO. I think Georg's multi-core idea has some merit, though I'm not nearly enough of a dev to begin looking for that (I'm a UX designer by trade).

tarrinr commented 8 years ago

That's the exact same cable I made.

I'm not sure why it would work on your other phone, (unless it's old enough it's not using the HQ demodulator?) but this 100% fixed my problems.

First I soldered DC blocking caps on both lines. I tried the cord just like that, and the phone would always play it's packet through the internal speakers. This confirmed my suspicions. The cap was keeping the voltage equal to the bias, so it was tricking android into thinking there was nothing plugged in. Then I soldered a resistor from the phone's mic to ground. I've been at a park for the past hour and a half, and it was tracking the whole time. The service never ended, it never played anything on the internal speakers, and it was sending and receiving with 100% accuracy.

For me at least, I'm pretty sure the problem was with the way Android detects insertion of different plugs.

emiliogon commented 8 years ago

I tested it out a fair bit this weekend, including adding more resistance on the microphone line. A total of around 1.5K ohm on the mic line seems to have stopped the -3 crashes with the HQ demod on this Galaxy Nexus.

While the crashing has stopped, however, the connection seems far from reliable. I still get some transmissions emitted from the phone's speaker, or ones that don't but also don't seem to get picked up by the radio. Sometimes re-plugging the cable will help, sometimes toggling tracking will.

Perhaps the -3 exception and the external audio are separate but related issues? The headset detection could be unreliable, which in some cases (but not all) causes audio code to crash?

I've created a separate feature request that may help avoid some of these problems.

tarrinr commented 8 years ago

Hmm... maybe it's not as simple as I was thinking. I think your feature request is a great idea, I didn't know you could override the android detection. That's weird you found it less reliable... I seem to be picking up more packets than I ever have before. Maybe it is just differences in phones. Did you put that resistance on the mic line or to ground? This is a schematic of my cable to clear up my bad explanation... image

ge0rg commented 8 years ago

I'm not sure the audio channel override can be realistically implemented.

BTW, having a direct electrical connection between a 5W+ radio transmitter and an Android smartphone will have unexpected side effects. We were testing USB operation with a TH-D72 recently, and the Android USB stack crashed whenever we were transmitting a packet. We were able to solve the issue by using a USB cable with ferrite core shielding.

TheButterZone commented 5 years ago

I've been inconsistently getting this same error using the https://baofengtech.com/aprs-k2-trrs-cable

The most recent error (cleared the rest out of my logs thinking I'd fixed it) followed: AFSK OK callsign>APDR15,WIDE2-2::SMSGTE-SM:here{1

and before that, APRS Service single shot: Periodic GPS/Network Position, Audio (AFSK).

The error, those two events before it, and "APRS Service stopped." after it, all happened at the same H:M:S.

I'd succeeded in sending a SMSGTE-[alias] message earlier today, but the digi path then was WIDE1-1,WIDE2-1 instead of WIDE2-2 standalone.

1.3 GHz dual core processor in the phone, so not sure if the HQ Demodulator switch would make a difference.