Java 以编程方式连接到配对的蓝牙扬声器并播放音频
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22226552/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Programmatically connect to paired Bluetooth speaker and play audio
提问by Ted
In our app, I'd like to connect to a previously paired A2DP Bluetooth Speaker and direct audio playback to it, using Android v4.2 or later.
在我们的应用程序中,我想使用 Android v4.2 或更高版本连接到先前配对的 A2DP 蓝牙扬声器并直接播放音频。
I can successfully create an A2DP profile object using this code to start the process:
我可以使用此代码成功创建 A2DP 配置文件对象以启动该过程:
/* Manifest permissions */
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
// Get the default adapter
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// Establish connection to the proxy.
mBluetoothAdapter.getProfileProxy(this, mProfileListener, BluetoothProfile.A2DP)
And the following listener to respond to the connection:
以及响应连接的以下侦听器:
private BluetoothProfile.ServiceListener mProfileListener = new BluetoothProfile.ServiceListener() {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
if (profile == BluetoothProfile.A2DP) {
mBluetoothSpeaker = (BluetoothA2dp) proxy;
// no devices are connected
List<BluetoothDevice> connectedDevices = mBluetoothSpeaker.getConnectedDevices();
//the one paired (and disconnected) speaker is returned here
int[] statesToCheck = {BluetoothA2dp.STATE_DISCONNECTED};
List<BluetoothDevice> disconnectedDevices = mBluetoothSpeaker.getDevicesMatchingConnectionStates(statesToCheck);
BluetoothDevice btSpeaker = disconnectedDevices.get(0);
//WHAT NOW?
}
}
public void onServiceDisconnected(int profile) {
if (profile == BluetoothProfile.A2DP) {
mBluetoothSpeaker = null;
}
}
};
I'm just a little lost as to what to do now, to connect the device, and direct the audio output to it. I've tried connecting to the device, as detailed in the Android docs, with the following code, but the final BluetoothSpeaker.getConnectedDevices()
call returns no connected devices.
我对现在要做什么、连接设备并将音频输出定向到它有点不知所措。我已尝试使用以下代码连接到设备,如 Android 文档中所述,但最终BluetoothSpeaker.getConnectedDevices()
调用未返回任何连接的设备。
BluetoothSocket tmp = null;
UUID MY_UUID = UUID.fromString("00001108-0000-1000-8000-00805f9b34fb");
try {
tmp = btSpeaker.createInsecureRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e1) {
// TODO Auto-generated catch block
Log.d("createRfcommSocketToServiceRecord ERROR", e1.getMessage());
}
mmSocket = tmp;
try {
// Connect the device through the socket. This will block
// until it succeeds or throws an exception
mmSocket.connect();
} catch (IOException connectException) {
// Unable to connect; close the socket and get out
try {
Log.d("connectException", connectException.getMessage());
mmSocket.close();
} catch (IOException closeException) { }
return;
}
connectedDevices = mBluetoothSpeaker.getConnectedDevices();
The code does seem to connect to the device in some way though, as when I stop execution, the Bluetooth speaker annouces that it is ready to pair (as it always does when it disconnects from an audio source).
代码似乎确实以某种方式连接到设备,因为当我停止执行时,蓝牙扬声器宣布它已准备好配对(就像它与音频源断开连接时一样)。
Older versions of the BluetoothA2dp
seem to have a connect(BluetoothDevice device)
method, but that has now been removed (as of 4.2) and I'm struggling to find any clear examples of how to programmatically connect to an A2DP device, and to direct audio output to it. Any help on how to approach either would be gratefully received.
旧版本的BluetoothA2dp
似乎有一种connect(BluetoothDevice device)
方法,但现在已被删除(从 4.2 开始),我正在努力寻找任何清晰的示例,说明如何以编程方式连接到 A2DP 设备并将音频输出定向到它。将不胜感激地收到有关如何接近两者的任何帮助。
Any advice on how to approach this would be hugely appreciated.
任何关于如何解决这个问题的建议将不胜感激。
回答by zxshi
Ted,
泰德,
I have the same issue like you when I tried with BluetoothHeadset. I guess my work around may work with A2DP. Since my headset only support Handsfree profile. I am only test with BluetoothHeadset.
当我尝试使用蓝牙耳机时,我遇到了和你一样的问题。我想我的工作可能适用于 A2DP。由于我的耳机仅支持免提模式。我只用蓝牙耳机测试。
No need to establish RFComm channel.
无需建立 RFComm 通道。
For me. After you connected to BluetoothHeadsetService, 1. check whether audio is already connected
为了我。连接BluetoothHeadsetService后,1.检查音频是否已经连接
mBluetoothSpeaker.isAudioConnected(btSpeaker);
2. if not, establish audio connection
2.如果没有,建立音频连接
mBluetoothSpeaker.startVoiceRecognition(btSpeaker);
3. register BroadcastReceiver for BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED and BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED
3.为BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED和BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED注册BroadcastReceiver
registerReceiver(mReceiver, new IntentFilter(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED));
registerReceiver(mReceiver, new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED));
4. BroadcastReceiver
4. 广播接收器
protected BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
int state = BluetoothHeadset.STATE_DISCONNECTED;
int previousState = intent.getIntExtra(BluetoothHeadset.EXTRA_PREVIOUS_STATE, BluetoothHeadset.STATE_DISCONNECTED);
if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
state = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, BluetoothHeadset.STATE_DISCONNECTED);
if (state == BluetoothHeadset.STATE_CONNECTED) {
mConnectedHeadset = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
mInfoTextview.append("\n\nDevice name = " + mConnectedHeadset.getName());
// Audio should not be connected yet but just to make sure.
if (mBluetoothHeadset.isAudioConnected(mConnectedHeadset)) {
Log.d(TAG, "Headset audio connected already");
} else {
if (!mBluetoothHeadset.startVoiceRecognition(mConnectedHeadset)) {
Log.e(TAG, "maybe you do not call stopVoiceRecognition previously");
mBluetoothHeadset.stopVoiceRecognition(mConnectedHeadset);
mBluetoothHeadset.startVoiceRecognition(mConnectedHeadset);
}
}
}
else if (state == BluetoothHeadset.STATE_DISCONNECTED) {
mConnectedHeadset = null;
}
}
else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED))// audio
{
state = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE, BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
// Bluetooth audio connected. you send audio stream to headset now!!!
mAudioManager.setMode(AudioManager.STREAM_VOICE_CALL);
mMediaPlayer = new MediaPlayer();
AssetManager assetManager = getAssets();
try {
AssetFileDescriptor fd = assetManager.openFd("Radioactive.mp3");
mMediaPlayer.setDataSource(fd.getFileDescriptor());
// set audio stream type to STREAM_VOICE_CALL will send audio to headset
// @see <a href="http://developer.android.com/reference/android/media/AudioManager.html#startBluetoothSco()">SCO</a>
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_VOICE_CALL);
mMediaPlayer.prepare();
Log.d(TAG, "start play music");
mMediaPlayer.start();
} catch (IOException e) {
e.printStackTrace();
}
}
else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
if (mMediaPlayer != null) {
mMediaPlayer.stop();
mMediaPlayer = null;
}
mBluetoothHeadset.stopVoiceRecognition(mConnectedHeadset);
}
}
}
};
回答by zxshi
This one works for me. After receive BluetoothA2dp.STATE_CONNECTED, you can play music as normal.
这个对我有用。收到BluetoothA2dp.STATE_CONNECTED后,就可以正常播放音乐了。
public class A2DPActivity extends Activity {
protected static final String TAG = "ZS-A2dp";
Button mBtPlay;
BluetoothAdapter mBtAdapter;
BluetoothA2dp mA2dpService;
AudioManager mAudioManager;
MediaPlayer mPlayer;
BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context ctx, Intent intent) {
String action = intent.getAction();
Log.d(TAG, "receive intent for action : " + action);
if (action.equals(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED)) {
int state = intent.getIntExtra(BluetoothA2dp.EXTRA_STATE, BluetoothA2dp.STATE_DISCONNECTED);
if (state == BluetoothA2dp.STATE_CONNECTED) {
setIsA2dpReady(true);
playMusic();
} else if (state == BluetoothA2dp.STATE_DISCONNECTED) {
setIsA2dpReady(false);
}
} else if (action.equals(BluetoothA2dp.ACTION_PLAYING_STATE_CHANGED)) {
int state = intent.getIntExtra(BluetoothA2dp.EXTRA_STATE, BluetoothA2dp.STATE_NOT_PLAYING);
if (state == BluetoothA2dp.STATE_PLAYING) {
Log.d(TAG, "A2DP start playing");
Toast.makeText(A2DPActivity.this, "A2dp is playing", Toast.LENGTH_SHORT).show();
} else {
Log.d(TAG, "A2DP stop playing");
Toast.makeText(A2DPActivity.this, "A2dp is stopped", Toast.LENGTH_SHORT).show();
}
}
}
};
boolean mIsA2dpReady = false;
void setIsA2dpReady(boolean ready) {
mIsA2dpReady = ready;
Toast.makeText(this, "A2DP ready ? " + (ready ? "true" : "false"), Toast.LENGTH_SHORT).show();
}
private ServiceListener mA2dpListener = new ServiceListener() {
@Override
public void onServiceConnected(int profile, BluetoothProfile a2dp) {
Log.d(TAG, "a2dp service connected. profile = " + profile);
if (profile == BluetoothProfile.A2DP) {
mA2dpService = (BluetoothA2dp) a2dp;
if (mAudioManager.isBluetoothA2dpOn()) {
setIsA2dpReady(true);
playMusic();
} else {
Log.d(TAG, "bluetooth a2dp is not on while service connected");
}
}
}
@Override
public void onServiceDisconnected(int profile) {
setIsA2dpReady(false);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout ll = new LinearLayout(this);
setContentView(ll);
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
registerReceiver(mReceiver, new IntentFilter(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED));
registerReceiver(mReceiver, new IntentFilter(BluetoothA2dp.ACTION_PLAYING_STATE_CHANGED));
mBtAdapter = BluetoothAdapter.getDefaultAdapter();
mBtAdapter.getProfileProxy(this, mA2dpListener , BluetoothProfile.A2DP);
}
@Override
protected void onDestroy() {
mBtAdapter.closeProfileProxy(BluetoothProfile.A2DP, mA2dpService);
releaseMediaPlayer();
unregisterReceiver(mReceiver);
super.onDestroy();
}
@Override
protected void onPause() {
releaseMediaPlayer();
super.onPause();
}
private void releaseMediaPlayer() {
if (mPlayer != null) {
mPlayer.release();
mPlayer = null;
}
}
private void playMusic() {
mPlayer = new MediaPlayer();
AssetManager assetManager = this.getAssets();
AssetFileDescriptor fd;
try {
fd = assetManager.openFd("Radioactive.mp3");
Log.d(TAG, "fd = " + fd);
mPlayer.setDataSource(fd.getFileDescriptor());
mPlayer.prepare();
Log.d(TAG, "start play music");
mPlayer.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
回答by Simon
Had the same problem, but found that older post:
有同样的问题,但发现旧帖子:
Programmatically connect to paired Bluetooth device
In short, in order to connect to a paired a2dp device, you simply have to invoke BluetoothA2dp.connect(myPairedA2dpDevice), but right now that method is hidden from the public API, which is not helpful. So you access it through Java reflection. It's kind of a hack, but the way Google put it, there doesn't seem to be a clean solution for now.
简而言之,为了连接到配对的 a2dp 设备,您只需调用 BluetoothA2dp.connect(myPairedA2dpDevice),但现在该方法对公共 API 是隐藏的,这没有帮助。所以你通过Java反射访问它。这有点像黑客,但按照谷歌的说法,目前似乎没有一个干净的解决方案。