1c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood/*
2c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood * Copyright (C) 2012 The Android Open Source Project
3c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood *
4c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood * Licensed under the Apache License, Version 2.0 (the "License");
5c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood * you may not use this file except in compliance with the License.
6c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood * You may obtain a copy of the License at
7c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood *
8c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood *      http://www.apache.org/licenses/LICENSE-2.0
9c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood *
10c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood * Unless required by applicable law or agreed to in writing, software
11c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood * distributed under the License is distributed on an "AS IS" BASIS,
12c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood * See the License for the specific language governing permissions and
14c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood * limitations under the License.
15c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood */
16c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
17c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood#define LOG_TAG "BluetoothA2dpSinkServiceJni"
18c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
19c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood#define LOG_NDEBUG 0
20c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
21c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood#include "com_android_bluetooth.h"
22c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood#include "hardware/bt_av.h"
23c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood#include "utils/Log.h"
24c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood#include "android_runtime/AndroidRuntime.h"
25c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
26c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood#include <string.h>
27c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
28c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodnamespace android {
29c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodstatic jmethodID method_onConnectionStateChanged;
30c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodstatic jmethodID method_onAudioStateChanged;
31c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodstatic jmethodID method_onAudioConfigChanged;
32c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
33c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodstatic const btav_interface_t *sBluetoothA2dpInterface = NULL;
34c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodstatic jobject mCallbacksObj = NULL;
35c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodstatic JNIEnv *sCallbackEnv = NULL;
36c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
37c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodstatic bool checkCallbackThread() {
38c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    // Always fetch the latest callbackEnv from AdapterService.
39c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    // Caching this could cause this sCallbackEnv to go out-of-sync
40c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    // with the AdapterService's ENV if an ASSOCIATE/DISASSOCIATE event
41c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    // is received
42c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    //if (sCallbackEnv == NULL) {
43c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    sCallbackEnv = getCallbackEnv();
44c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    //}
45c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
46c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    JNIEnv* env = AndroidRuntime::getJNIEnv();
47c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    if (sCallbackEnv != env || sCallbackEnv == NULL) return false;
48c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    return true;
49c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood}
50c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
51c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodstatic void bta2dp_connection_state_callback(btav_connection_state_t state, bt_bdaddr_t* bd_addr) {
52c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    jbyteArray addr;
53c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
54c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    ALOGI("%s", __FUNCTION__);
55c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
56c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    if (!checkCallbackThread()) {                                       \
57c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \
58c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        return;                                                         \
59c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    }
60c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
61c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    if (!addr) {
62c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        ALOGE("Fail to new jbyteArray bd addr for connection state");
63c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
64c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        return;
65c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    }
66c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
67c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
68c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectionStateChanged, (jint) state,
69c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood                                 addr);
70c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
71c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    sCallbackEnv->DeleteLocalRef(addr);
72c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood}
73c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
74c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodstatic void bta2dp_audio_state_callback(btav_audio_state_t state, bt_bdaddr_t* bd_addr) {
75c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    jbyteArray addr;
76c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
77c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    ALOGI("%s", __FUNCTION__);
78c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
79c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    if (!checkCallbackThread()) {                                       \
80c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \
81c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        return;                                                         \
82c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    }
83c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
84c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    if (!addr) {
85c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        ALOGE("Fail to new jbyteArray bd addr for connection state");
86c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
87c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        return;
88c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    }
89c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
90c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
91c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAudioStateChanged, (jint) state,
92c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood                                 addr);
93c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
94c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    sCallbackEnv->DeleteLocalRef(addr);
95c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood}
96c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
97c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodstatic void bta2dp_audio_config_callback(bt_bdaddr_t *bd_addr, uint32_t sample_rate, uint8_t channel_count) {
98c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    jbyteArray addr;
99c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
100c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    ALOGI("%s", __FUNCTION__);
101c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
102c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    if (!checkCallbackThread()) {                                       \
103c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__); \
104c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        return;                                                         \
105c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    }
106c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
107c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    if (!addr) {
108c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        ALOGE("Fail to new jbyteArray bd addr for connection state");
109c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
110c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        return;
111c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    }
112c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
113c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*) bd_addr);
114c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAudioConfigChanged, addr, (jint)sample_rate, (jint)channel_count);
115c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
116c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    sCallbackEnv->DeleteLocalRef(addr);
117c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood}
118c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
119c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodstatic btav_callbacks_t sBluetoothA2dpCallbacks = {
120c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    sizeof(sBluetoothA2dpCallbacks),
121c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    bta2dp_connection_state_callback,
122c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    bta2dp_audio_state_callback,
123c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    bta2dp_audio_config_callback
124c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood};
125c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
126c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodstatic void classInitNative(JNIEnv* env, jclass clazz) {
127c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    int err;
128c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    const bt_interface_t* btInf;
129c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    bt_status_t status;
130c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
131c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    method_onConnectionStateChanged =
132c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        env->GetMethodID(clazz, "onConnectionStateChanged", "(I[B)V");
133c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
134c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    method_onAudioStateChanged =
135c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        env->GetMethodID(clazz, "onAudioStateChanged", "(I[B)V");
136c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
137c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    method_onAudioConfigChanged =
138c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        env->GetMethodID(clazz, "onAudioConfigChanged", "([BII)V");
139c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
140c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    ALOGI("%s: succeeds", __FUNCTION__);
141c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood}
142c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
143c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodstatic void initNative(JNIEnv *env, jobject object) {
144c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    const bt_interface_t* btInf;
145c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    bt_status_t status;
146c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
147c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    if ( (btInf = getBluetoothInterface()) == NULL) {
148c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        ALOGE("Bluetooth module is not loaded");
149c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        return;
150c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    }
151c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
152c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    if (sBluetoothA2dpInterface !=NULL) {
153c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood         ALOGW("Cleaning up A2DP Interface before initializing...");
154c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood         sBluetoothA2dpInterface->cleanup();
155c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood         sBluetoothA2dpInterface = NULL;
156c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    }
157c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
158c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    if (mCallbacksObj != NULL) {
159c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood         ALOGW("Cleaning up A2DP callback object");
160c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood         env->DeleteGlobalRef(mCallbacksObj);
161c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood         mCallbacksObj = NULL;
162c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    }
163c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
164c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    if ( (sBluetoothA2dpInterface = (btav_interface_t *)
165c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood          btInf->get_profile_interface(BT_PROFILE_ADVANCED_AUDIO_SINK_ID)) == NULL) {
166c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        ALOGE("Failed to get Bluetooth A2DP Sink Interface");
167c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        return;
168c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    }
169c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
170c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    if ( (status = sBluetoothA2dpInterface->init(&sBluetoothA2dpCallbacks)) != BT_STATUS_SUCCESS) {
171c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        ALOGE("Failed to initialize Bluetooth A2DP Sink, status: %d", status);
172c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        sBluetoothA2dpInterface = NULL;
173c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        return;
174c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    }
175c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
176c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    mCallbacksObj = env->NewGlobalRef(object);
177c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood}
178c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
179c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodstatic void cleanupNative(JNIEnv *env, jobject object) {
180c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    const bt_interface_t* btInf;
181c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    bt_status_t status;
182c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
183c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    if ( (btInf = getBluetoothInterface()) == NULL) {
184c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        ALOGE("Bluetooth module is not loaded");
185c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        return;
186c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    }
187c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
188c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    if (sBluetoothA2dpInterface !=NULL) {
189c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        sBluetoothA2dpInterface->cleanup();
190c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        sBluetoothA2dpInterface = NULL;
191c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    }
192c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
193c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    if (mCallbacksObj != NULL) {
194c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        env->DeleteGlobalRef(mCallbacksObj);
195c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        mCallbacksObj = NULL;
196c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    }
197c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood}
198c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
199c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodstatic jboolean connectA2dpNative(JNIEnv *env, jobject object, jbyteArray address) {
200c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    jbyte *addr;
201c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    bt_bdaddr_t * btAddr;
202c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    bt_status_t status;
203c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
204c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    ALOGI("%s: sBluetoothA2dpInterface: %p", __FUNCTION__, sBluetoothA2dpInterface);
205c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    if (!sBluetoothA2dpInterface) return JNI_FALSE;
206c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
207c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    addr = env->GetByteArrayElements(address, NULL);
208c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    btAddr = (bt_bdaddr_t *) addr;
209c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    if (!addr) {
210c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        jniThrowIOException(env, EINVAL);
211c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        return JNI_FALSE;
212c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    }
213c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
214c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    if ((status = sBluetoothA2dpInterface->connect((bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
215c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        ALOGE("Failed HF connection, status: %d", status);
216c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    }
217c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    env->ReleaseByteArrayElements(address, addr, 0);
218c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
219c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood}
220c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
221c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodstatic jboolean disconnectA2dpNative(JNIEnv *env, jobject object, jbyteArray address) {
222c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    jbyte *addr;
223c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    bt_status_t status;
224c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
225c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    if (!sBluetoothA2dpInterface) return JNI_FALSE;
226c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
227c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    addr = env->GetByteArrayElements(address, NULL);
228c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    if (!addr) {
229c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        jniThrowIOException(env, EINVAL);
230c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        return JNI_FALSE;
231c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    }
232c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
233c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    if ( (status = sBluetoothA2dpInterface->disconnect((bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
234c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood        ALOGE("Failed HF disconnection, status: %d", status);
235c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    }
236c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    env->ReleaseByteArrayElements(address, addr, 0);
237c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
238c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood}
239c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
240c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodstatic JNINativeMethod sMethods[] = {
241c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    {"classInitNative", "()V", (void *) classInitNative},
242c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    {"initNative", "()V", (void *) initNative},
243c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    {"cleanupNative", "()V", (void *) cleanupNative},
244c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    {"connectA2dpNative", "([B)Z", (void *) connectA2dpNative},
245c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    {"disconnectA2dpNative", "([B)Z", (void *) disconnectA2dpNative},
246c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood};
247c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
248c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwoodint register_com_android_bluetooth_a2dp_sink(JNIEnv* env)
249c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood{
250c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood    return jniRegisterNativeMethods(env, "com/android/bluetooth/a2dp/A2dpSinkStateMachine",
251c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood                                    sMethods, NELEM(sMethods));
252c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood}
253c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood
254c030f08f419d596c4aa216c9cca9867e7b5486f0Mike Lockwood}
255