• After 15+ years, we've made a big change: Android Forums is now Early Bird Club. Learn more here.

Apps Unusual activity when opening an AudioRecord instance

hackster84

Lurker
May 15, 2014
8
1
Hi,

I am writing an app that does data communication through the 3.5mm audio port on the device. I have the system working great on most of the phones that I've tested it on (these are all working personal cell phones that belong to people I work with) but I'm having trouble getting it to work on the Motorola Droid Mini.

The problem is that I can't initialize the AudioRecord source for any of the possible sample rates, audio formats or configurations (stereo or mono) that are supposed to be standard for every Android device on either the DEFAULT or MIC input sources (Error code -20 when initializing native AudioRecord object). I can get the instance to initialize properly when I set the input source to VOICE_RECOGNITION, however, on only the Droid Mini, the data that I receive from that input source is pure gibberish. the VOICE_RECOGNITION source does work for every other phone that I've tried it on, however - even phones whose OS goes back as far as Android 2.3.

Here's the interesting part: if I reset the phone and start my app immediately, I can get full communication to work properly (only when using the DEFAULT input source), but if I wait a couple of minutes or I restart my app, it crashes again. This behavior coupled with the research I've been doing on the matter lead me to believe that there is something else which is tying up that resource and thus making it impossible for me to start an AudioRecord instance using that input. (Maybe something like google voice control or another voice control related app - I looked to see what was running, but I couldn't find anything) I don't believe that the problem is due to my app, as every time the app exits or something is unplugged from the audio jack, I have the code set up to release all of the audio resources - including calling AudioRecord.stop() and AudioRecord.release(). (This was something I was doing before but was suggested in many forum posts as a possible solution).

That brings me to my question: is there a way to find out what process/service/app may be using that resource, and is there a way to change focus or gain priority access to it over the app that is running in the background? There is a way to gain audio focus for output - one would assume that there is a way to do so for input.

The reason that I'm using the AudioRecord function instead of the MediaRecorder is that I need to be able to have direct access to the input audio buffer in order to process the data and turn it into my binary data stream. As far as I can tell, this is something that the MediaRecorder class is incapable of doing.

I've included my AudioRecord initialization and release routines just in case someone can think of something that I'm not doing properly. Once again, this only happens on one phone - the Motorola Droid Mini. My app works flawlessly on every other phone I've tried it on, including the Samsung Galaxy S3 and the S5, the Motorola Droid RAZR M, the Kyocera Event, and a couple of others. (The Galaxys were a chore to get working correctly, as Samsung uses their own special audio hardware).

As always, thank you in advance for any help that you can offer on this situation. My code is include below.

-Chris

Here is my AudioRecord initialization routine:

Code:
	private static int[] mSampleRates = new int[] {44100, 22050, 11025, 8000};

	public AudioRecord findAudioRecord() {
		AudioRecord recorder = null;
		int source;
// This is here because I found that I can use the VOICE_RECOGNITION 
//input source on every phone but the Droid Mini, which (when it works) 
//only works using the DEFAULT audio source
		if (android.os.Build.MODEL.equals("XT1030")){
			source = MediaRecorder.AudioSource.DEFAULT;				
		}
		else 
			source = MediaRecorder.AudioSource.VOICE_RECOGNITION;

_mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
		for (int rate : mSampleRates) {
	        for (short audioFormat : new short[] { AudioFormat.ENCODING_PCM_8BIT, AudioFormat.ENCODING_PCM_16BIT }) {
	            for (short channelConfig : new short[] { AudioFormat.CHANNEL_IN_MONO, AudioFormat.CHANNEL_IN_STEREO }) {
	                try {
	                    int bufferSize = AudioRecord.getMinBufferSize(rate, channelConfig, audioFormat);

	                    if (bufferSize != AudioRecord.ERROR_BAD_VALUE) {
	                        // check if we can instantiate and have a success
	                		android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
	                        recorder = new AudioRecord(source, rate, channelConfig, audioFormat, bufferSize);

	                        if (recorder.getState() == AudioRecord.STATE_INITIALIZED){
	                        	_inputSampleFrequency = recorder.getSampleRate();
	                        	_inputEncoding = recorder.getAudioFormat();
	                        	_inputChannelConfig = recorder.getChannelConfiguration();
	                        	recBufferSize = bufferSize;
	                        	
	                            return recorder;
	                        }
	                    }
	                    
	                } catch (Exception e) {
	        			e.printStackTrace();
	                }
	            }
	        }
	    }
	    return null;
	}

that is called by

Code:
                AudioRecord _audioRecord = findAudioRecord();
		_audioRecord.startRecording();
		_audioTrack.play();


When the headphone jack is unplugged or the app is closed, this is called:

Code:
_audioRecord.stop();
if (_audioRecord != null)_audioRecord.release();
_audioRecord = null;


Again, thanks in advance for any assistance and all assistance you can offer.
 
Scary Alien,

Thanks for your suggestion, analysis of an "adb bugreport" did actually give me the information I needed in order to track down the issue. It turns out that on this phone, Google Search is constantly running the hotword detection service which ties up the resource that I'm trying to use. If I go into the system settings and kill the google search service, my app works great. Once I click on the google search bar which restarts the google search service, the hotword detection feature works fine again but will crash my app if I try to run it without again killing the google search service from the system menu. Obviously, this is a laborious process and only a workaround for an issue, so I need to be able to kill or pause it somehow within my code.

I noticed that there is a permission (com.google.android.googlequicksearchbox.permission.PAUSE_HOTWORD) which insinuates to me that somewhere there is a function or action that I can take to pause this service in order to start my own, but I'm having a hell of a time trying to find it. Anyone have any ideas?

As always, thank you in advance for any help you can provide.


-Chris
 
  • Like
Reactions: scary alien
Upvote 0
Happy to have helped a bit, Chris :) :thumbup:.

I wonder if you can send that permission as an intent? (I'm a bit wobbly here regarding how exactly that is done properly :p).

I de-compiled the .apk (it barfed but I got far enough to get the AndroidManifest.xml file) which shows:

PHP:
<permission android:name="com.google.android.googlequicksearchbox.permission.PAUSE_HOTWORD" android:protectionLevel="signatureOrSystem" />

<uses-permission android:name="com.google.android.googlequicksearchbox.permission.PAUSE_HOTWORD" />

so perhaps an intent can be sent to cause the quicksearch to temporarily relinquish control? :dontknow:

That's all I got--best of luck! :)
 
Upvote 0

BEST TECH IN 2023

We've been tracking upcoming products and ranking the best tech since 2007. Thanks for trusting our opinion: we get rewarded through affiliate links that earn us a commission and we invite you to learn more about us.

Smartphones