How to record audio from bluetooth headset (startBluetoothSco() )

荒凉一梦 提交于 2019-12-03 09:50:01

问题


I am trying to record audio from bluetooth headset, startBluetoothSco() works different in different versions of android, Recording audio from bluetooth headset on android 4.2, 4.4, and 5.0. using "Nokia BH-310 and 9xxPlantronics" bluetooth headsets.

SAMPLE_RATE = 8000;

  1. Devices running Android 4.2 records audio from bluetooth device only when when AudioRecord() object is created like this

AudioSource.DEFAULT

mRecorder = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, SAMPLE_RATE,
                    AudioFormat.CHANNEL_IN_MONO,     AudioFormat.ENCODING_PCM_16BIT,
                    bufferSize);
  1. Devices running Android 4.4 records audio from bluetooth device only when when AudioRecord() object is created like this

AudioSource.DEFAULT

    mRecorder = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, SAMPLE_RATE,
                    AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT,
                    bufferSize);

Or

AudioSource.MIC

    mRecorder = new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLE_RATE,
                    AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT,
                    bufferSize);
  1. Devices running Android 5.0 Lollipop records audio from bluetooth device only when when AudioRecord() object is created like this

AudioSource.VOICE_COMMUNICATION

    mRecorder = new AudioRecord(MediaRecorder.AudioSource.VOICE_COMMUNICATION, SAMPLE_RATE,
                    AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT,
                    bufferSize);

//with other AudioSource types (MIC, DEFAULT) sco returns connected state but record from phone mic

LOG for Android 5.0 device connction states

D/inside onRcv﹕ state=0
D/State=﹕ conn -> 0
D/inside onRcv﹕ state=2
D/State=﹕ conn -> 2
D/inside onRcv﹕ state=1
D/inside onRcv﹕ Unregister rcvr
D/inside onRcv﹕ Connected Record from bluetooth

//But still record from phone mic if Audio record object is created using MIC or DEFAULT

Full code i am using to do above is here.

BluetoothManager.java



public class BluetoothRecordingManager {
private static int count = 0;
private static int TIMEOUT = 3000;
private static int COUNTDOWN_INTERVAL = 1000;
private static final int MAX_ATTEPTS_TO_CONNECT = 3;

/**
 * This method check for bluetooh settings (bluetooth flag and bluetooth is
 * on or off) and decide wheather to record from bluetooth headset or phone
 * mic. If settings are not correct then start's recording using phone mic.
 *
 * @param context
 * @param BluetoothRecording :- Interface object
 * @param resume             :- Pass through
 */
public static void checkAndRecord(final Context context, final OnBluetoothRecording BluetoothRecording, boolean resume) {

    if (getBluetoothFlag() && isBluetoothON()) {
        Log.d("start bluetooth recording"," calling");
        startBluetoothRecording(BluetoothRecording, resume, context);
    } else {
        // If Bluetooth is OFF Show Toast else Dont Show
        if (getBluetoothFlag() && !isBluetoothON()) {
            Toast.makeText(context, "bluetooth_off", Toast.LENGTH_LONG).show();
            // false because recording not started
            BluetoothRecording.onStartRecording(resume, false);
        } else {
            // false because recording not started
            BluetoothRecording.onStartRecording(resume, false);
        }
    }
}

/**
 * Connect to bluetooth headset and start recording if headset failed to
 * connect then records normally using phone mic.
 *
 * @param BluetoothRecording
 * @param resume
 * @param context
 */
private static void startBluetoothRecording(final OnBluetoothRecording BluetoothRecording, final boolean resume, final Context context) {
    final AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
    audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
    //audioManager.setBluetoothScoOn(true);

    final CountDownTimer timer = getTimer(BluetoothRecording, audioManager, resume);
    Log.d("inside","startBlue rec");

    final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -1);
            Log.d("inside onRcv","state="+state);
            if (AudioManager.SCO_AUDIO_STATE_CONNECTED == state ) {
                // cancel Timer
                timer.cancel();
                Log.d("inside onRcv","Unregister rcvr");
                context.unregisterReceiver(this);
                Log.d("inside onRcv","Connected Record from bluetooth");
                // pass through and true because
                // recording from bluetooth so set 8000kHz
                BluetoothRecording.onStartRecording(resume, true);
            }
        }
    };

    Log.d("calling","registr broadcast rcvr");
    context.registerReceiver(broadcastReceiver, new IntentFilter(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED));
    // Start the timer

    try {
        // Android 2.2 onwards supports BT SCO for non-voice call use case
        // Check the Android version whether it supports or not.
        if(audioManager.isBluetoothScoAvailableOffCall()){
            if(audioManager.isBluetoothScoOn()){
                Log.d("SCO","stopped SCO");
               // audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
                audioManager.stopBluetoothSco();
                timer.start();
                Log.d("Starting sco","start");
                audioManager.startBluetoothSco();
            }else {
                timer.start();
                Log.d("Starting sco","start");
                audioManager.startBluetoothSco();
            }
        }else {
            Log.d("Sco","Not availiable");
        }
    } catch (Exception e) {
        Log.d("sco elsepart startBluetoothSCO"," "+e);
        timer.cancel();
        context.unregisterReceiver(broadcastReceiver);
        BluetoothRecording.onStartRecording(resume, false);
    }
}

/**
 * set the Timeout
 *
 * @param BluetoothRecording
 * @param audioManager
 * @param resume
 * @return
 */
private static CountDownTimer getTimer(final OnBluetoothRecording BluetoothRecording, final AudioManager audioManager, final boolean resume) {
    return new CountDownTimer(TIMEOUT, COUNTDOWN_INTERVAL) {
        @Override
        public void onTick(long millisUntilFinished) {
            // Do Nothing
        }

        @Override
        public void onFinish() {
            // stopBluetoothSCO() and start Normal Recording
            audioManager.stopBluetoothSco();

            // false because recording button is already clicked but still not recording.
            BluetoothRecording.onStartRecording(resume, false);
        }
    };
}

/**
 * Return's the bluetooth state
 *
 * @return
 */
private static boolean isBluetoothON() {
    /*BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    if (bluetoothAdapter != null) {
        return bluetoothAdapter.isEnabled();
    } else {
        return false;
    }*/
    return true;
}

/**
 * Return's the bluetoothFlag state
 *
 * @return
 */
private static boolean getBluetoothFlag() {

    return true;
}
   }

MainActivity.java

This is how i am creating audio record object and starting recording.

public class MainActivity extends Activity implements AdapterView.OnItemSelectedListener {

public static final int SAMPLE_RATE = 8000;
private AudioRecord mRecorder;
private File mRecording;
private short[] mBuffer;
private final String startRecordingLabel = "Start recording";
private final String stopRecordingLabel = "Stop recording";
private boolean mIsRecording = false;
private ProgressBar mProgressBar;
float iGain = 1.0f;
CheckBox gain;
Button showPref;
OnBluetoothRecording bluetoothRecording;
protected int bitsPerSamples = 16;

@Override
public void onCreate(final Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.fragment_main);

    initRecorder()

button.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(final View v) {
            if (!mIsRecording) {
                BluetoothRecordingManager.checkAndRecord(getApplicationContext(), new OnBluetoothRecording() {

                    @Override
                    public void onStartRecording(boolean state, boolean bluetoothFlag) {

                        Log.d("CallBack", "starting Recording");
                        if (!mIsRecording) {
                            button.setText(stopRecordingLabel);
                            mIsRecording = true;
                            mRecorder.startRecording();
                            mRecording = getFile("raw");
                            startBufferedWrite(mRecording);
                        } else {
                            Log.d("stop", "else part of start");
                            button.setText(startRecordingLabel);
                            mIsRecording = false;
                            mRecorder.stop();
                            File waveFile = getFile("wav");
                            try {
                                rawToWave(mRecording, waveFile);
                            } catch (IOException e) {
                                Toast.makeText(MainActivity.this, e.getMessage(),
                                        Toast.LENGTH_SHORT).show();
                            }
                            Toast.makeText(MainActivity.this,
                                    "Recorded to " + waveFile.getName(),
                                    Toast.LENGTH_SHORT).show();
                        }
                    }

                    @Override
                    public void onCancelRecording() {
                    }
                }, true);
            } else {
                Log.d("stop", "stopped recording");
                button.setText(startRecordingLabel);
                mIsRecording = false;
                mRecorder.stop();
                File waveFile = getFile("wav");
                try {
                    rawToWave(mRecording, waveFile);
                } catch (IOException e) {
                    Toast.makeText(MainActivity.this, e.getMessage(),
                            Toast.LENGTH_SHORT).show();
                }
                final AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
                //audioManager.setMode(AudioManager.MODE_NORMAL);
                if (audioManager.isBluetoothScoOn()) {
                    Log.d("SCO", "stopped SCO");
                    audioManager.stopBluetoothSco();
                }
                Toast.makeText(MainActivity.this,
                        "Recorded to " + waveFile.getName(),
                        Toast.LENGTH_SHORT).show();
            }
        }
    });
}
  private void initRecorder() {
    int bufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE,
            AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
    mBuffer = new short[bufferSize];

            Log.d("Creating Obj", "" + Mic);
            mRecorder = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, SAMPLE_RATE,
                    AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT,
                    bufferSize);
}
}

来源:https://stackoverflow.com/questions/28450355/how-to-record-audio-from-bluetooth-headset-startbluetoothsco

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!