3

I am trying to capture audio from a Bluetooth Headset paired with an Android Device.

Following is the relevant code:

Intent in=null;
final int bufferSize=BufferElements2Rec*BytesPerElement;

final BroadcastReceiver brr=new BroadcastReceiver()
{
    @Override
    public void onReceive(Context context,Intent intent)
    {
        int state=intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,-1);
        Log.d(labelApp,"Audio SCO State = "+state);
        if(AudioManager.SCO_AUDIO_STATE_CONNECTED==state)
        {
            Log.d(labelApp,"Entered and Starting Recording");
            //recorder = new AudioRecord(MediaRecorder.AudioSource.DEFAULT,
            //        RECORDER_SAMPLERATE, RECORDER_CHANNELS,
            //        RECORDER_AUDIO_ENCODING, bufferSize);
            recorder = new AudioRecord(android.media.MediaRecorder.AudioSource.MIC,
                RECORDER_SAMPLERATE, RECORDER_CHANNELS,
                RECORDER_AUDIO_ENCODING, bufferSize);
            if(recorder==null)
            {
                Log.d(labelApp,"null");
            }
            else
            {
                Log.d(labelApp,"not null");
            }
            recorder.startRecording();
            recordingThread=new Thread(new Runnable()
            {
                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    writeAudioDataToFile();
                }

            },"AudioRecorder Thread");
            recordingThread.start();

            Log.d(labelApp,"Launched Recording Thread");
        }
    }
};

try
{
    Log.d(labelApp,"Initializing BT");
    am = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
    //am.setMode(AudioManager.MODE_IN_CALL);

    //in=registerReceiver(brr,new IntentFilter(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED));
    //in=registerReceiver(brr,new IntentFilter(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED));
    Log.d(labelApp,"Starting Bluetooth");
    am.setStreamSolo(AudioManager.MODE_IN_CALL, true);
    am.setBluetoothScoOn(true);
    am.setMode(AudioManager.MODE_IN_CALL);
    am.startBluetoothSco();
    Log.d(labelApp,"Can BT record from mic? "+am.isBluetoothScoAvailableOffCall());
    //in=registerReceiver(brr,new IntentFilter(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED));
    in=registerReceiver(brr,new IntentFilter(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED));
    // The following line makes the audio go to hell
    //am.setMode(AudioManager.MODE_IN_CALL);


    //am.setStreamSolo(AudioManager.MODE_IN_CALL, true);
    Log.d(labelApp,"Everything initializated");
    Log.d(labelApp,"Recorder is...");
}
catch(Exception e)
{
    Log.e(labelApp,"exception",e);
    writeStack(e);
}

try
{
        Log.d(labelApp,"Initializing BT");
        am = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
        //am.setMode(AudioManager.MODE_IN_CALL);

        //in=registerReceiver(brr,new IntentFilter(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED));
        //in=registerReceiver(brr,new IntentFilter(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED));
        Log.d(labelApp,"Starting Bluetooth");
        am.setStreamSolo(AudioManager.MODE_IN_CALL, true);
        am.setBluetoothScoOn(true);
        am.setMode(AudioManager.MODE_IN_CALL);
        am.startBluetoothSco();
        Log.d(labelApp,"Can BT record from mic? "+am.isBluetoothScoAvailableOffCall());
        //in=registerReceiver(brr,new IntentFilter(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED));
        in=registerReceiver(brr,new IntentFilter(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED));
        // The following line makes the audio go to hell
        //am.setMode(AudioManager.MODE_IN_CALL);


        //am.setStreamSolo(AudioManager.MODE_IN_CALL, true);
        Log.d(labelApp,"Everything initializated");
        Log.d(labelApp,"Recorder is...");
}
catch(Exception e)
{
        Log.e(labelApp,"exception",e);
        writeStack(e);
}

The Manifest asks permissions for:

  • WRITE_EXTERNAL_STORAGE
  • RECORD_AUDIO
  • INTERNET
  • MODIFY_AUDIO_SETTINGS
  • BROADCAST_STICKY
  • BLUETOOTH
  • BLUETOOTH_ADMIN

The typical Filtered LogCat output per the app is:

  1. Initializing BT
  2. Starting Bluetooth
  3. Can BT record from mic? true
  4. Everything initialized
  5. Recorder is...
  6. Audio SCO State = 2
  7. Audio SCO State = 1
  8. Entered and Starting Recording
  9. not null
  10. Launched Recording Thread

When the am.startBluetoothSco(); is invoked, I can hear a brief noise on the BT device, but then the app simply gets the audio from the Android Device's mic in place of the BT's one.

Any hint on what am I missing/doing wrong?

Thanks in advance for the attention

Pozzo Apps
  • 1,859
  • 2
  • 22
  • 32
user3845389
  • 31
  • 1
  • 2
  • Hi, I encounter this problem too after so long time, can you tell me how to resolve it? Thanks. – mmm2006 Mar 22 '17 at 16:00

1 Answers1

4

Most importantly, you need to set
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />

in the manifest file. Without it, there will be no error message but the B/T state will refuse to change to connected.

Other relevant permissions include:

<uses-permission android:name="android.permission.RECORD_AUDIO"/> 
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/> 
<uses-permission android:name="android.permission.BROADCAST_STICKY"/>

Edit: In addition to the comments, here is some sample code that I have used before:

  am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);

brr(new BroadcastReceiver() {

    @Override
    public void onReceive(Context context, Intent intent) {
        int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -1);
        Log.d(TAG, "Audio SCO state: " + state);

        if (AudioManager.SCO_AUDIO_STATE_CONNECTED == state) { 
            /* 
             * Now the connection has been established to the bluetooth device. 
             * Record audio or whatever (on another thread).With AudioRecord you can record with an object created like this:
             * new AudioRecord(MediaRecorder.AudioSource.MIC, 8000, AudioFormat.CHANNEL_CONFIGURATION_MONO,
             * AudioFormat.ENCODING_PCM_16BIT, audioBufferSize);
             *
             * After finishing, don't forget to unregister this receiver and
             * to stop the bluetooth connection with am.stopBluetoothSco();
             */
            unregisterReceiver(this);
        }

    }
}, new IntentFilter(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED));

Log.d(TAG, "starting bluetooth");
am.startBluetoothSco();

Credits for this code go to user Stephan

Community
  • 1
  • 1
Wolfish
  • 960
  • 2
  • 8
  • 34
  • These permissions are already set, they are reported in the ending of my post (together with BLUETOOTH, BLUETOOTH_ADMIN, INTERNET, WRITE_EXTERNAL_STORAGE). Search my original post for "The Manifest asks permissions for:", thanks for your interesting though – user3845389 Jul 16 '14 at 15:07
  • 1
    @user3845389 Oh, sorry, I missed that. Too busy reading below about what your log contained. I have some sample code for B/T recording too, I'll post it as an edit. – Wolfish Jul 16 '14 at 15:10
  • Thanks for the snippet, it looks pretty much similar to the one in my post. Unfortunately, everything looks "Ok" (the Intent is called and the connection is on, otherwise we wouldn't see the "not null" message referring to the AudioRecord recorder), but the app will simply capture the audio from the device's own mic and not from the BT paired device...dunno why! Looks much an issue with the way I used the AudioRecord recorder maybe? – user3845389 Jul 16 '14 at 15:28
  • 1
    @user3845389 Wait, could you use `REMOTE_SUBMIX` in place of `MIC`? http://developer.android.com/reference/android/media/MediaRecorder.AudioSource.html#REMOTE_SUBMIX – Wolfish Jul 16 '14 at 15:40
  • 1
    @user3845389 Actually, now that I'm doing some research, I keep finding links to this [google post](https://code.google.com/p/android/issues/detail?id=60323). Maybe recording from bluetooth can't be done? – Wolfish Jul 16 '14 at 15:50
  • I've tried REMOTE_SUBMIX and VOICE_UPLINK, but these end up in LogCat exceptions: Error creating AudioRecord instance: initialization check failed, Error code -20 when initializating native AudioRecord object; and java.lang.RuntimeException: Error receiving broadcast Intent. MIC and DEFAULT won't get to exceptions but won't work with BT! – user3845389 Jul 16 '14 at 15:55
  • I have read the google post content. However, I'm trying to capture audio through BT not during a phone call, I need to capture it _out_ of a phone call, so I thought that the code response: "Can BT record from mic? true" was quite promising. – user3845389 Jul 17 '14 at 10:09
  • 1
    @user3845389 I get the context of when you're recording, I was just considering the fact that the code to do so simply might not exist based on that post. However, there is no evidence to support either yes or no. As for that code response, the impression I get from that is using an external device to record from the phone's mic, not vice versa. – Wolfish Jul 17 '14 at 13:14
  • 1
    @user3845389 additionally, I'm reading up on some apps that apparently already do what you're trying to accomplish, and apparently they don't work on every device. Maybe that's the problem you have? Unsupported hardware? – Wolfish Jul 17 '14 at 13:17