4 * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Nilesh Trimbake <t.shripati@samsung.com>
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
22 #include <sys/socket.h>
23 #include <sys/errno.h>
28 #include "oal-hardware.h"
29 #include "oal-device-mgr.h"
30 #include <oal-manager.h>
31 #include <oal-a2dp-sink.h>
33 #include <bt-service-a2dp-sink.h>
34 #include <bt-service-event.h>
36 int _bt_a2dp_connect_remote_source(bluetooth_device_address_t *device_address/*,
37 bt_audio_function_data_t *func_data*/)
39 oal_status_t status = OAL_STATUS_SUCCESS;
40 int result = BLUETOOTH_ERROR_NONE;
43 status = a2dp_sink_connect((bt_address_t*)device_address);
44 if (status != OAL_STATUS_SUCCESS) {
45 BT_ERR("Connection could not be established, err: [%d]", status);
46 result = _bt_convert_oal_status_to_bt_error(status);
51 int _bt_a2dp_disconnect_remote_source(bluetooth_device_address_t *device_address/*,
52 bt_audio_function_data_t *func_data*/)
54 oal_status_t status = OAL_STATUS_SUCCESS;
55 int result = BLUETOOTH_ERROR_NONE;
58 status = a2dp_sink_disconnect((bt_address_t*)device_address);
59 if (status != OAL_STATUS_SUCCESS) {
60 BT_ERR("DisConnection err: [%d]", status);
61 result = _bt_convert_oal_status_to_bt_error(status);
66 static void __bt_handle_av_source_connected_state(bluetooth_device_address_t *address)
68 char addr[BT_ADDRESS_STRING_SIZE] = { 0 };
70 bt_headset_wait_t *wait_device = NULL;
71 bluetooth_device_address_t wait_device_address;
73 int result = BLUETOOTH_ERROR_NONE;
74 ret_if(NULL == address);
77 _bt_convert_addr_type_to_string(addr, address->addr);
78 BT_INFO("Address of connected device [%s]", addr);
80 /* Set VCONF Key for A2DP Connected status */
81 _bt_set_device_values(TRUE, VCONFKEY_BT_DEVICE_A2DP_HEADSET_CONNECTED);
83 /* Send A2DP(SRC Role) connected event to Application */
84 param = g_variant_new("(is)", result, addr);
85 _bt_send_event(BT_HEADSET_EVENT, BLUETOOTH_EVENT_AV_SOURCE_CONNECTED, param);
87 /* Add data from the connected list */
88 _bt_add_headset_to_list(BT_AUDIO_A2DP_SOURCE, BT_STATE_CONNECTED, addr);
90 /* Delete waiting device data if present */
91 wait_device = _bt_get_audio_wait_data();
92 if (wait_device != NULL &&
93 (g_strcmp0(wait_device->address, addr) == 0))
96 if (wait_device != NULL) {
97 BT_INFO("A2DP Profile connected for device [%s] but another device [%s]is waiting to be connnected type [%d]",
98 addr, wait_device->address, wait_device->type);
99 BT_INFO("Trigger connect for the waiting device [%s], audio type [%d]",
100 wait_device->address, wait_device->type);
101 _bt_convert_addr_string_to_type(wait_device_address.addr,
102 wait_device->address);
103 _bt_audio_connect(wait_device->type, &wait_device_address);
104 /* Now free the wait list */
105 //_bt_rel_wait_data();
111 static void __bt_handle_av_source_disconnected_state(bluetooth_device_address_t *address)
113 char addr[BT_ADDRESS_STRING_SIZE] = { 0 };
114 int result = BLUETOOTH_ERROR_NONE;
116 bt_headset_wait_t *wait_device;
117 bluetooth_device_address_t device_address;
119 invocation_info_t *req_info = NULL;
120 ret_if(NULL == address);
123 _bt_convert_addr_type_to_string(addr, address->addr);
125 /* Set VCONF status for A2DP Disconnection */
126 _bt_set_device_values(FALSE, VCONFKEY_BT_DEVICE_A2DP_HEADSET_CONNECTED);
129 /* Remove data from the connected list */
130 _bt_remove_headset_from_list(BT_AUDIO_A2DP_SOURCE, addr);
132 req_info = _bt_get_request_info_data(BT_AV_SOURCE_DISCONNECT, addr);
133 BT_INFO("Address of disconnected device[%s]", addr);
134 if (NULL == req_info) {
135 BT_INFO("AV DisConnect request not found or possibly already replied");
136 req_info = _bt_get_request_info_data(BT_AV_SOURCE_CONNECT, addr);
137 if (NULL == req_info) {
138 /* This means, AV Disconnect request has successfully passed, and real disconnect is completed */
139 BT_INFO("Neither AV Connect or AV Disconnect request is found..means, AV Profile is disconnected");
141 /* Send A2DP(SRC Role) disconnected event to Application */
142 result = BLUETOOTH_ERROR_NONE;
143 param = g_variant_new("(is)", result, addr);
144 _bt_send_event(BT_HEADSET_EVENT, BLUETOOTH_EVENT_AV_SOURCE_DISCONNECTED, param);
147 * TODO: Below logic is not required for BT_AUDIO_CONNECT/BT_AUDIO_DISCONNECT.
148 * But if Tizen supports a device with A2DP Sink and HFP both profiles (BT_AUDIO_HFP_SOURCE)
149 * then below logic will be required for corresponding connect/disconnect function
152 req_info = _bt_get_request_info_data(BT_AUDIO_CONNECT, addr);
153 if (req_info == NULL) {
154 BT_INFO("Audio Connect All request is also Not found..");
156 req_info = _bt_get_request_info_data(BT_AUDIO_DISCONNECT, addr);
157 if (req_info == NULL)
158 BT_INFO("Audio DisConnect All request is also Not found..");
160 BT_INFO("Audio DisConnect All request is found..");
162 BT_INFO("Audio Connect All request is found..");
163 result = BLUETOOTH_ERROR_INTERNAL;
164 data = _bt_get_pending_audio_conn_info(addr);
166 BT_INFO("Pending connect is found, delete it..");
167 _bt_cleanup_audio_pending_conn_info_and_reply_pending_req(data, BLUETOOTH_ERROR_NONE);
170 BT_INFO("Pending connect is Not found..");
174 goto check_wait_device;
176 BT_ERR("AV Connect request has failed.."); /* DBUS return needed */
177 result = BLUETOOTH_ERROR_INTERNAL;
179 /* Delete waiting device data if present for this device */
180 wait_device = _bt_get_audio_wait_data();
181 if (wait_device && strncasecmp(wait_device->address, addr, BT_ADDRESS_STRING_SIZE) == 0) {
186 goto check_wait_device;
189 BT_ERR("AV Disconnect request found for [%s], means disconnect request is successful", addr); /* DBUS return needed */
191 /* Send A2DP(SRC Role) disconnected event to Application */
192 result = BLUETOOTH_ERROR_NONE;
193 param = g_variant_new("(is)", result, addr);
194 _bt_send_event(BT_HEADSET_EVENT, BLUETOOTH_EVENT_AV_SOURCE_DISCONNECTED, param);
196 goto check_wait_device;
199 wait_device = _bt_get_audio_wait_data();
201 if (wait_device == NULL)
204 if (((wait_device->type == BT_AUDIO_ALL) &&
205 (wait_device->ag_flag == TRUE)) ||
206 (wait_device->type == BT_AUDIO_A2DP_SOURCE) ||
207 (wait_device->disconnection_type == BT_AUDIO_A2DP_SOURCE)) {
208 if (g_strcmp0(wait_device->address, addr) != 0) {
209 BT_INFO("Trigger connect for the waiting device [%s], audio type [%d]",
210 wait_device->address, wait_device->type);
211 _bt_convert_addr_string_to_type(device_address.addr,
212 wait_device->address);
213 _bt_audio_connect(wait_device->type, &device_address);
218 out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
219 g_array_append_vals(out_param, addr, BT_ADDRESS_STRING_SIZE);
220 _bt_service_method_return(req_info->context,
222 g_array_free(out_param, TRUE);
223 _bt_free_info_from_invocation_list(req_info);
227 static void __bt_reply_av_source_connection_pending_request(bluetooth_device_address_t *address)
230 char addr[BT_ADDRESS_STRING_SIZE] = { 0 };
231 bluetooth_device_address_t device_address;
233 invocation_info_t *req_info;
234 bt_pending_audio_conn_t *data = NULL;
235 int result = BLUETOOTH_ERROR_NONE;
236 memcpy(device_address.addr, address->addr, BLUETOOTH_ADDRESS_LENGTH);
237 _bt_convert_addr_type_to_string(addr, address->addr);
239 req_info = _bt_get_request_info_data(BT_AV_SOURCE_CONNECT, addr);
240 if (NULL == req_info) {
241 BT_INFO("AV source Connect request not found or possibly already replied");
242 req_info = _bt_get_request_info_data(BT_AUDIO_CONNECT, addr);
244 if (req_info == NULL) {
245 BT_INFO("AV Connect request & Audio All connect not found or possibly already replied");
248 BT_INFO("Audio All connect request found for address [%s]", addr);
249 /* TODO Delete the search info if present */
250 data = _bt_get_pending_audio_conn_info(addr);
252 BT_INFO("Audio Connect All request present and pending connect is also present, delete info");
253 _bt_cleanup_audio_pending_conn_info_and_reply_pending_req(data, BLUETOOTH_ERROR_NONE);
255 BT_ERR("Abnormal: Audio Connect All request present but pending connect absent");
259 BT_INFO("AV Connect request found for [%s]", addr);
262 out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
263 g_array_append_vals(out_param, addr, BT_ADDRESS_STRING_SIZE);
264 _bt_service_method_return(req_info->context,
266 g_array_free(out_param, TRUE);
267 _bt_free_info_from_invocation_list(req_info);
270 static void __bt_reply_av_source_disconnection_pending_request(bluetooth_device_address_t *address)
273 char addr[BT_ADDRESS_STRING_SIZE] = { 0 };
274 bluetooth_device_address_t device_address;
276 invocation_info_t *req_info;
277 int result = BLUETOOTH_ERROR_NONE;
278 memcpy(device_address.addr, address->addr, BLUETOOTH_ADDRESS_LENGTH);
279 _bt_convert_addr_type_to_string(addr, address->addr);
281 req_info = _bt_get_request_info_data(BT_AV_SOURCE_DISCONNECT, addr);
282 if (NULL == req_info) {
283 BT_INFO("AV DisConnect request not found or possibly already replied");
284 req_info = _bt_get_request_info_data(BT_AUDIO_DISCONNECT, addr);
285 if (req_info == NULL) {
286 BT_INFO("AUDIO Disconnect All request also not found or possibly already replied");
289 BT_INFO("Audio All DisConnect request found..");
292 BT_INFO("AV Source DisConnect request found for [%s]", addr);
295 /* In any of the above cases, do DBUS return */
296 out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
297 g_array_append_vals(out_param, &device_address,
298 sizeof(bluetooth_device_address_t));
299 _bt_service_method_return(req_info->context,
301 g_array_free(out_param, TRUE);
302 _bt_free_info_from_invocation_list(req_info);
305 void _bt_a2dp_sink_handle_incoming_authorization(char *address, int service_id)
307 char connected_address[BT_ADDRESS_STRING_SIZE + 1];
309 bluetooth_device_address_t device_address;
310 oal_status_t res = OAL_STATUS_SUCCESS;
313 _bt_convert_addr_string_to_type(device_address.addr, address);
315 switch (service_id) {
316 case A2DP_SRC_SERVICE_ID:
317 connected = _bt_is_headset_type_connected(BT_AUDIO_A2DP_SOURCE, connected_address);
319 BT_INFO("A2DP (Remote Source) is already connected..check which device..");
320 if (g_strcmp0(connected_address, address) != 0) {
321 BT_INFO("Different device is connected[%s] reject current [%s] device authorization request",
322 connected_address, address);
323 res = device_reply_auth_request((bt_address_t*)&device_address, service_id, FALSE, FALSE);
324 if (res != OAL_STATUS_SUCCESS)
325 BT_ERR("authorize_response: %d", res);
329 res = device_reply_auth_request((bt_address_t*)&device_address, service_id, TRUE, FALSE);
330 if (res != OAL_STATUS_SUCCESS)
331 BT_ERR("authorize_response: %d", res);
335 BT_ERR("Invalid Audio Service ID..");
341 void _bt_a2dp_sink_event_handler(int oal_event, gpointer event_data)
344 bluetooth_device_address_t * bd_addr = (bluetooth_device_address_t*)event_data;
347 case OAL_EVENT_A2DP_SINK_CONNECTING:
348 BT_INFO("A2DP Sink Profile connecting..");
349 __bt_reply_av_source_connection_pending_request(bd_addr);
351 case OAL_EVENT_A2DP_SINK_DISCONNECTING:
352 BT_INFO("A2DP Sink Profile disconnecting..");
353 __bt_reply_av_source_disconnection_pending_request(bd_addr);
355 case OAL_EVENT_A2DP_SINK_CONNECTED:
356 BT_INFO("A2DP Sink Profile connected..");
357 __bt_handle_av_source_connected_state(bd_addr);
358 BT_PERMANENT_LOG("Connected A2DP sink");
360 case OAL_EVENT_A2DP_SINK_DISCONNECTED:
361 BT_INFO("A2DP Sink Profile dissconnected..");
362 __bt_handle_av_source_disconnected_state(bd_addr);
363 BT_PERMANENT_LOG("Disconnected A2DP sink");
366 BT_INFO("Invalid Event = %d", oal_event);