android_server_BluetoothA2dpService.cpp
回调函数:
DBusHandlerResult a2dp_event_filter(DBusMessage *msg, JNIEnv *env) {
DBusError err;
if (!nat) {
ALOGV("... skipping %s\n", __FUNCTION__);
ALOGV("... ignored\n");
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
dbus_error_init(&err);
if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL) {
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
if (dbus_message_is_signal(msg, "org.bluez.AudioSink",
"PropertyChanged")) {
jobjectArray str_array =
parse_property_change(env, msg, (Properties *)&sink_properties,
sizeof(sink_properties) / sizeof(Properties));
const char *c_path = dbus_message_get_path(msg);
jstring path = env->NewStringUTF(c_path);
env->CallVoidMethod(nat->me,
method_onSinkPropertyChanged,
path,
str_array);
env->DeleteLocalRef(path);
result = DBUS_HANDLER_RESULT_HANDLED;
return result;
} else if (dbus_message_is_signal(msg, "org.bluez.Control",
"GetPlayStatus")) {
frameworks/base/core/java/android/server/BluetoothA2dpService.java
/**
* Called by native code on a PropertyChanged signal from
* org.bluez.AudioSink.
*
* @param path the object path for the changed device
* @param propValues a string array containing the key and one or more
* values.
*/
private synchronized void onSinkPropertyChanged(String path, String[] propValues) {
if (!mBluetoothService.isEnabled()) {
return;
}
String name = propValues[0];
String address = mBluetoothService.getAddressFromObjectPath(path);
if (address == null) {
Log.e(TAG, "onSinkPropertyChanged: Address of the remote device in null");
return;
}
BluetoothDevice device = mAdapter.getRemoteDevice(address);
if (name.equals(PROPERTY_STATE)) {
int state = convertBluezSinkStringToState(propValues[1]);
log("A2DP: onSinkPropertyChanged newState is: " + state + "mPlayingA2dpDevice: " + mPlayingA2dpDevice);
if (mAudioDevices.get(device) == null) {
// This is for an incoming connection for a device not known to us.
// We have authorized it and bluez state has changed.
addAudioSink(device);
handleSinkStateChange(device, BluetoothA2dp.STATE_DISCONNECTED, state);
} else {
if (state == BluetoothA2dp.STATE_PLAYING && mPlayingA2dpDevice == null) {
if (tmgr.getCallState() == TelephonyManager.CALL_STATE_IDLE) {
mPlayingA2dpDevice = device;
handleSinkPlayingStateChange(device, state, BluetoothA2dp.STATE_NOT_PLAYING);
} else {
log("suspend Sink");
// During call active a2dp device is in suspended state
// so audio will not be routed to A2dp. To avoid IOP
// issues send a SUSPEND on A2dp if remote device asks
// for PLAY during call active state.
suspendSinkNative(mBluetoothService.getObjectPathFromAddress(
device.getAddress()));
}
} else if (state == BluetoothA2dp.STATE_CONNECTED && mPlayingA2dpDevice != null) {
mPlayingA2dpDevice = null;
handleSinkPlayingStateChange(device, BluetoothA2dp.STATE_NOT_PLAYING,
BluetoothA2dp.STATE_PLAYING);
} else {
mPlayingA2dpDevice = null;
int prevState = mAudioDevices.get(device);
handleSinkStateChange(device, prevState, state);
}
}
}
}
private void handleSinkPlayingStateChange(BluetoothDevice device, int state, int prevState) {
Intent intent = new Intent(BluetoothA2dp.ACTION_PLAYING_STATE_CHANGED);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState);
intent.putExtra(BluetoothProfile.EXTRA_STATE, state);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
if (DBG) log("A2DP Playing state : device: " + device + " State:" + prevState + "->" + state);
}
handleSinkPlayingStateChange() 会发送一个ACTION_PLAYING_STATE_CHANGED的Intent,会被BluetoothService收到。