Bluetooth ヘッドセットからオーディオを録音しようとしています。startBluetoothSco() は Android のバージョンによって動作が異なります。Android 4.2、4.4、および 5.0 で Bluetooth ヘッドセットからオーディオを録音します。" Nokia BH-310 および 9xxPlantronics " Bluetooth ヘッドセットを使用。
サンプルレート = 8000;
- Android 4.2 を実行しているデバイスは、AudioRecord() オブジェクトが次のように作成された場合にのみ、Bluetooth デバイスからオーディオを録音します。
AudioSource.DEFAULT
mRecorder = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, SAMPLE_RATE,
AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT,
bufferSize);
- Android 4.4 を実行しているデバイスは、AudioRecord() オブジェクトが次のように作成された場合にのみ、Bluetooth デバイスからオーディオを録音します。
AudioSource.DEFAULT
mRecorder = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, SAMPLE_RATE,
AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT,
bufferSize);
または
AudioSource.MIC
mRecorder = new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLE_RATE,
AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT,
bufferSize);
- Android 5.0 Lollipop を実行しているデバイスは、AudioRecord() オブジェクトが次のように作成された場合にのみ、Bluetooth デバイスからオーディオを録音します。
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
Android 5.0 デバイスの接続状態のログ
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
上記の実行に使用している完全なコードはこちらです。
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
これは、オーディオレコードオブジェクトを作成して録音を開始する方法です。
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);
}
}