1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > Android 系统蓝牙 控制手机端音乐暂停 (AVRCP)

Android 系统蓝牙 控制手机端音乐暂停 (AVRCP)

时间:2022-11-19 22:15:56

相关推荐

Android 系统蓝牙 控制手机端音乐暂停 (AVRCP)

需求:Android 平板做为一个音响的功能使用。已经移植 BT 的 a2dp sink 的功能。现在需要加上 平板控制手机的声音播放,暂停,音量大小等功能

移植:

平台: rk3368 系统 android6.0

按网上的资料,/shichaog/article/details/52182987 。在 Android stdio 里移植,发现

import android.bluetooth.BluetoothAvrcpController;

import android.bluetooth.BluetoothAvrcp;

这两个 import 是找不到。查看源码,其实里面有的。网上查出原因,是因为用了 @hide 来隐藏,不暴露给app

于是想到在系统app 里尝试能否使用。

测试 在系统的源码里 package/app/Bluetooth 里的 src/com/android/bluetooth/a2dp/A2dpSinkStateMachine.java 加上

+import android.bluetooth.BluetoothAvrcpController;

+import android.bluetooth.BluetoothAvrcp;

编译,能够通过。证明系统app 是可以调用的。

于是在 A2dpSinkStateMachine.java 加了一个

+mAvrcpController.sendPassThroughCmd(device, BluetoothAvrcp.PASSTHROUGH_ID_STOP, BluetoothAvrcp.PASSTHROUGH_STATE_PRESS);

+mAvrcpController.sendPassThroughCmd(device, BluetoothAvrcp.PASSTHROUGH_ID_STOP, BluetoothAvrcp.PASSTHROUGH_STATE_RELEASE);

来暂停

那么问题来了,如何获取 mAvrcpController

看例子发现,需要一个 Listener

于是加了

+ private BluetoothProfile.ServiceListener mAvrcpServiceListener = new BluetoothProfile.ServiceListener(){

+ @Override

+ public void onServiceConnected(int profile, BluetoothProfile proxy) {

+ Log.d(TAG, "BT profile Service connected");

+if (profile == BluetoothProfile.AVRCP_CONTROLLER){

+ Log.d(TAG, "AvrcpControllerService connected");

+

+ mAvrcpController = (BluetoothAvrcpController) proxy;

+// mAvrcpController.setCallback(new AvrcpControllerCallback());

+

+ Log.d(TAG, "Avrcp devices: ");

+ List<BluetoothDevice> devices = mAvrcpController.getConnectedDevices();

+ for (BluetoothDevice device : devices)

+Log.d(TAG, " - " + device.getName() + " " + device.getAddress());

+}

+ }

+

+ @Override

+ public void onServiceDisconnected(int profile) {

+if (profile == BluetoothProfile.AVRCP_CONTROLLER) {

+ Log.d(TAG, "AvrcpControllerService disconnected");

+ //mAvrcpController.removeCallback();

+ mAvrcpController = null;

+}

+ }

+ };

+

然而程序进不了 onServiceConnected ,mAvrcpController 为空

在framework 里加 log 发现 在 frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java 里的 BluetoothAvrcpController avrcp = new BluetoothAvrcpController(context, listener);出了错。怀疑是 服务没有启动。

12-12 21:02:16.207 1700 1700 D BluetoothAdapter: wade getProfileProxy12

12-12 21:02:16.207 1700 1700 D BluetoothAdapter: wade new BluetoothAvrcpController

12-12 21:02:16.210 1700 1700 E BluetoothAvrcpController: Could not bind to Bluetooth AVRCP Controller Service with Intent { act=android.bluetooth.IBluetoothAvrcpController }

怎么启动 avrcp 的服务呢?没有想到很好的办法。比较以前有的一些补丁和源码。发现了问题。

--- a/packages/apps/Bluetooth/res/values/config.xml

+++ b/packages/apps/Bluetooth/res/values/config.xml

@@ -26,7 +26,7 @@

<bool name="pbap_include_photos_in_vcard">false</bool>

<bool name="pbap_use_profile_for_owner_vcard">true</bool>

<bool name="profile_supported_map">true</bool>

- <bool name="profile_supported_avrcp_controller">false</bool>

+ <bool name="profile_supported_avrcp_controller">true</bool>

<bool name="profile_supported_sap">false</bool>

在修改了这个之后,终于可以暂停手机端的音乐暂停了。

总结:

1. 编译要在源码里,编译系统app ,android stdio 用不了。

2. mAvrcpController 的获取需要加一个 BluetoothProfile.ServiceListener

3.系统本身要修改 config.xml 以打开 BluetoothAvrcpController 服务。

4. 只做到了一播放就暂停。关于场景的工作,(何时暂停,播放,或者按钮暂停播放没有做)

附所有的修改

app :

diff --git a/packages/apps/Bluetooth/res/values/config.xml b/packages/apps/Bluetooth/res/values/config.xml

index 0262064..57c8345 100644

--- a/packages/apps/Bluetooth/res/values/config.xml

+++ b/packages/apps/Bluetooth/res/values/config.xml

@@ -26,7 +26,7 @@

<bool name="pbap_include_photos_in_vcard">false</bool>

<bool name="pbap_use_profile_for_owner_vcard">true</bool>

<bool name="profile_supported_map">true</bool>

- <bool name="profile_supported_avrcp_controller">false</bool>

+ <bool name="profile_supported_avrcp_controller">true</bool>

<bool name="profile_supported_sap">false</bool>

<!-- If true, we will require location to be enabled on the device to

diff --git a/packages/apps/Bluetooth/src/com/android/bluetooth/a2dp/A2dpSinkStateMachine.java b/packages/apps/Bluetooth/src/com/android/bluetooth/a2dp/A2dpSinkStateMachine.

index ffe8931..a8bedda 100755

--- a/packages/apps/Bluetooth/src/com/android/bluetooth/a2dp/A2dpSinkStateMachine.java

+++ b/packages/apps/Bluetooth/src/com/android/bluetooth/a2dp/A2dpSinkStateMachine.java

@@ -35,6 +35,8 @@ import android.bluetooth.BluetoothDevice;

import android.bluetooth.BluetoothProfile;

import android.bluetooth.BluetoothUuid;

import android.bluetooth.IBluetooth;

+import android.bluetooth.BluetoothAvrcpController;

+import android.bluetooth.BluetoothAvrcp;

import android.content.Context;

import android.media.AudioFormat;

import android.media.AudioManager;

@@ -106,6 +108,11 @@ final class A2dpSinkStateMachine extends StateMachine {

private final WakeLock mWakeLock;

private static final int MSG_CONNECTION_STATE_CHANGED = 0;

+ public static final int AVRC_ID_PAUSE = 0x46;

+ public static final int KEY_STATE_PRESSED = 0;

+ public static final int KEY_STATE_RELEASED = 1;

+ private BluetoothAvrcpController mAvrcpController;

+ private static final String TAG = "AVRCPa2dpsinktest";

// mCurrentDevice is the device connected before the state changes

// mTargetDevice is the device to be connected

@@ -145,6 +152,7 @@ final class A2dpSinkStateMachine extends StateMachine {

mService = svc;

mContext = context;

mAdapter = BluetoothAdapter.getDefaultAdapter();

+ mAdapter.getProfileProxy(context, mAvrcpServiceListener, BluetoothProfile.AVRCP_CONTROLLER);

initNative();

@@ -312,6 +320,9 @@ final class A2dpSinkStateMachine extends StateMachine {

log("Exit Disconnected: " + getCurrentMessage().what);

}

+

+

+

// in Disconnected state

private void processConnectionEvent(int state, BluetoothDevice device) {

switch (state) {

@@ -670,6 +681,8 @@ final class A2dpSinkStateMachine extends StateMachine {

mAudioManager.requestAudioFocus(mAudioFocusListener, AudioManager.STREAM_MUSIC,

AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);

audioPlay();

+ Log.d(TAG, "audioPlay now");

+sendCommand(BluetoothAvrcp.PASSTHROUGH_ID_STOP);

break;

case AUDIO_STATE_REMOTE_SUSPEND:

logd("in remote suspend here do nothing");

@@ -687,6 +700,23 @@ final class A2dpSinkStateMachine extends StateMachine {

}

}

+ private void sendCommand(int keyCode){

+ if (mAvrcpController == null)

+ {

+ Log.d(TAG, "sendCommand mAvrcpController null");

+ return;

+ }

+

+

+ List<BluetoothDevice> devices = mAvrcpController.getConnectedDevices();

+ for (BluetoothDevice device : devices){

+Log.d(TAG, "send command to device: "+ keyCode + device.getName() + " " + device.getAddress());

+//<B8>÷<BD><B7><A8><CA><C7>Ҫ<U+05F7><D7>ٵ<C4><D6>ص<E3>֮<B6><FE>

+mAvrcpController.sendPassThroughCmd(device, keyCode, BluetoothAvrcp.PASSTHROUGH_STATE_PRESS);

+mAvrcpController.sendPassThroughCmd(device, keyCode, BluetoothAvrcp.PASSTHROUGH_STATE_RELEASE);

+ }

+ }

+

private void processAudioConfigEvent(BluetoothAudioConfig audioConfig, BluetoothDevice device) {

mAudioConfigs.put(device, audioConfig);

int lastSamprate = currentSamprate;

@@ -926,6 +956,34 @@ final class A2dpSinkStateMachine extends StateMachine {

}

};

+

+ private BluetoothProfile.ServiceListener mAvrcpServiceListener = new BluetoothProfile.ServiceListener(){

+ @Override

+ public void onServiceConnected(int profile, BluetoothProfile proxy) {

+ Log.d(TAG, "BT profile Service connected");

+if (profile == BluetoothProfile.AVRCP_CONTROLLER){

+ Log.d(TAG, "AvrcpControllerService connected");

+

+ mAvrcpController = (BluetoothAvrcpController) proxy;

+// mAvrcpController.setCallback(new AvrcpControllerCallback());

+

+ Log.d(TAG, "Avrcp devices: ");

+ List<BluetoothDevice> devices = mAvrcpController.getConnectedDevices();

+ for (BluetoothDevice device : devices)

+Log.d(TAG, " - " + device.getName() + " " + device.getAddress());

+}

+ }

+

+ @Override

+ public void onServiceDisconnected(int profile) {

+if (profile == BluetoothProfile.AVRCP_CONTROLLER) {

+ Log.d(TAG, "AvrcpControllerService disconnected");

+ //mAvrcpController.removeCallback();

+ mAvrcpController = null;

+}

+ }

+ };

+

class RecordThread extends Thread{

@Override

public void run() {

diff --git a/packages/apps/Bluetooth/src/com/android/bluetooth/avrcp/AvrcpControllerService.java b/packages/apps/Bluetooth/src/com/android/bluetooth/avrcp/AvrcpControllerSe

index ed426ec..2bf0e30 100644

--- a/packages/apps/Bluetooth/src/com/android/bluetooth/avrcp/AvrcpControllerService.java

+++ b/packages/apps/Bluetooth/src/com/android/bluetooth/avrcp/AvrcpControllerService.java

@@ -40,7 +40,7 @@ import java.util.HashMap;

* @hide

*/

public class AvrcpControllerService extends ProfileService {

- private static final boolean DBG = false;

+ private static final boolean DBG = true;

private static final String TAG = "AvrcpControllerService";

private static final int MESSAGE_SEND_PASS_THROUGH_CMD = 1;

framework:

wade@SuperX:~/work/rk3368_618$ git diff frameworks

diff --git a/frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java b/frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java

index 1f3ff51..ba59f29 100644

--- a/frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java

+++ b/frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java

@@ -1805,8 +1805,12 @@ public final class BluetoothAdapter {

*/

public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener,

int profile) {

- if (context == null || listener == null) return false;

-

+ if (context == null || listener == null)

+ {

+Log.d(TAG, "wade getprofileproxy context or listenser is null");

+return false;

+ }

+Log.d(TAG, "wade getProfileProxy" + profile);

if (profile == BluetoothProfile.HEADSET) {

BluetoothHeadset headset = new BluetoothHeadset(context, listener);

return true;

@@ -1817,6 +1821,7 @@ public final class BluetoothAdapter {

BluetoothA2dpSink a2dpSink = new BluetoothA2dpSink(context, listener);

return true;

} else if (profile == BluetoothProfile.AVRCP_CONTROLLER) {

+Log.d(TAG, "wade new BluetoothAvrcpController");

BluetoothAvrcpController avrcp = new BluetoothAvrcpController(context, listener);

return true;

} else if (profile == BluetoothProfile.INPUT_DEVICE) {

diff --git a/frameworks/base/core/java/android/bluetooth/BluetoothAvrcpController.java b/frameworks/base/core/java/android/bluetooth/BluetoothAvrcpController.java

index b53a8fc..425fba7 100644

--- a/frameworks/base/core/java/android/bluetooth/BluetoothAvrcpController.java

+++ b/frameworks/base/core/java/android/bluetooth/BluetoothAvrcpController.java

@@ -211,6 +211,7 @@ public final class BluetoothAvrcpController implements BluetoothProfile {

public void sendPassThroughCmd(BluetoothDevice device, int keyCode, int keyState) {

if (DBG) Log.d(TAG, "sendPassThroughCmd");

+ Log.d(TAG, "sendPassThroughCmd");

if (mService != null && isEnabled()) {

try {

mService.sendPassThroughCmd(device, keyCode, keyState);

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。