Programmatically connect to paired Bluetooth speaker and play audio

心已入冬 提交于 2019-11-30 13:01:45
zxshi

This one works for me. After receive BluetoothA2dp.STATE_CONNECTED, you can play music as normal.

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();
    }
}

}

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.

No need to establish RFComm channel.

For me. After you connected to BluetoothHeadsetService, 1. check whether audio is already connected

mBluetoothSpeaker.isAudioConnected(btSpeaker);

2. if not, establish audio connection

mBluetoothSpeaker.startVoiceRecognition(btSpeaker);

3. register BroadcastReceiver for BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED and BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED

registerReceiver(mReceiver, new IntentFilter(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED));
registerReceiver(mReceiver, new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED));

4. BroadcastReceiver

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);
            }
        }   
    }
};
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.

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