Removed A2DP sink disconnect event on A2DP connect fail
[platform/core/connectivity/bluetooth-frwk.git] / bt-service-adaptation / services / audio / a2dp_sink / bt-service-a2dp-sink.c
1 /*
2  * Bluetooth-frwk
3  *
4  * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact:  Nilesh Trimbake <t.shripati@samsung.com>
7  *
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
11  *
12  *              http://www.apache.org/licenses/LICENSE-2.0
13  *
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.
19  *
20  */
21
22 #include <sys/socket.h>
23 #include <sys/errno.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <vconf.h>
27
28 #include "oal-hardware.h"
29 #include "oal-device-mgr.h"
30 #include <oal-manager.h>
31 #include <oal-a2dp-sink.h>
32
33 #include <bt-service-a2dp-sink.h>
34 #include <bt-service-event.h>
35
36 int _bt_a2dp_connect_remote_source(bluetooth_device_address_t *device_address/*,
37                                                 bt_audio_function_data_t *func_data*/)
38 {
39         oal_status_t status = OAL_STATUS_SUCCESS;
40         int result = BLUETOOTH_ERROR_NONE;
41         BT_INFO("+");
42
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 = BLUETOOTH_ERROR_INTERNAL;
47         }
48         return result;
49 }
50
51 int _bt_a2dp_disconnect_remote_source(bluetooth_device_address_t *device_address/*,
52                                                 bt_audio_function_data_t *func_data*/)
53 {
54         oal_status_t status = OAL_STATUS_SUCCESS;
55         int result = BLUETOOTH_ERROR_NONE;
56         BT_INFO("+");
57
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 = BLUETOOTH_ERROR_INTERNAL;
62         }
63         return result;
64 }
65
66 static void __bt_handle_av_source_connected_state(bluetooth_device_address_t *address)
67 {
68         char addr[BT_ADDRESS_STRING_SIZE] = { 0 };
69
70         bt_headset_wait_t *wait_device = NULL;
71         bluetooth_device_address_t wait_device_address;
72         GVariant *param;
73         int result = BLUETOOTH_ERROR_NONE;
74         ret_if(NULL == address);
75         BT_INFO("+");
76
77         _bt_convert_addr_type_to_string(addr, address->addr);
78         BT_INFO("Address of connected device [%s]", addr);
79
80         /* Set VCONF Key for A2DP Connected status */
81         _bt_set_device_values(TRUE, VCONFKEY_BT_DEVICE_A2DP_HEADSET_CONNECTED);
82
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);
86
87         /* Add data from the connected list */
88         _bt_add_headset_to_list(BT_AUDIO_A2DP_SOURCE, BT_STATE_CONNECTED, addr);
89
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))
94                 _bt_rel_wait_data();
95         else {
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();
106                 }
107         }
108         BT_INFO("-");
109 }
110
111 static void __bt_handle_av_source_disconnected_state(bluetooth_device_address_t *address)
112 {
113         char addr[BT_ADDRESS_STRING_SIZE] = { 0 };
114         int result = BLUETOOTH_ERROR_NONE;
115         GArray *out_param;
116         bt_headset_wait_t *wait_device;
117         bluetooth_device_address_t device_address;
118         GVariant *param;
119         invocation_info_t *req_info = NULL;
120         ret_if(NULL == address);
121         BT_INFO("+");
122
123         _bt_convert_addr_type_to_string(addr, address->addr);
124
125         /* Set VCONF status for A2DP Disconnection */
126         _bt_set_device_values(FALSE, VCONFKEY_BT_DEVICE_A2DP_HEADSET_CONNECTED);
127
128
129         /* Remove data from the connected list */
130         _bt_remove_headset_from_list(BT_AUDIO_A2DP_SOURCE, addr);
131
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");
140
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);
145
146                         /*
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
150                          */
151 #if 0
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..");
155
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..");
159                                 else
160                                         BT_INFO("Audio DisConnect All request is found..");
161                         } else {
162                                 BT_INFO("Audio Connect All request is found..");
163                                 result = BLUETOOTH_ERROR_INTERNAL;
164                                 data = _bt_get_pending_audio_conn_info(addr);
165                                 if (data) {
166                                         BT_INFO("Pending connect is found, delete it..");
167                                         _bt_cleanup_audio_pending_conn_info_and_reply_pending_req(data, BLUETOOTH_ERROR_NONE);
168                                         req_info = NULL;
169                                 } else {
170                                         BT_INFO("Pending connect is Not found..");
171                                 }
172                         }
173 #endif
174                         goto check_wait_device;
175                 } else {
176                         BT_ERR("AV Connect request has failed.."); /* DBUS return needed */
177                         result = BLUETOOTH_ERROR_INTERNAL;
178
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) {
182                                 _bt_rel_wait_data();
183                                 goto dbus_return;
184                         }
185
186                         goto check_wait_device;
187                 }
188         } else {
189                 BT_ERR("AV Disconnect request found for [%s], means disconnect request is successful", addr); /* DBUS return needed */
190
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);
195
196                 goto check_wait_device;
197         }
198 check_wait_device:
199         wait_device = _bt_get_audio_wait_data();
200
201         if (wait_device == NULL)
202                 goto dbus_return;
203
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);
214                 }
215         }
216 dbus_return:
217         if (req_info) {
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,
221                                 out_param, result);
222                 g_array_free(out_param, TRUE);
223                 g_free(req_info->user_data);
224                 _bt_free_info_from_invocation_list(req_info);
225         }
226 }
227
228 static void __bt_reply_av_source_connection_pending_request(bluetooth_device_address_t *address)
229 {
230         BT_DBG("+");
231         char addr[BT_ADDRESS_STRING_SIZE] = { 0 };
232         bluetooth_device_address_t device_address;
233         GArray *out_param;
234         invocation_info_t *req_info;
235         bt_pending_audio_conn_t *data = NULL;
236         int result = BLUETOOTH_ERROR_NONE;
237         memcpy(device_address.addr, address->addr, BLUETOOTH_ADDRESS_LENGTH);
238         _bt_convert_addr_type_to_string(addr, address->addr);
239
240         req_info = _bt_get_request_info_data(BT_AV_SOURCE_CONNECT, addr);
241         if (NULL == req_info) {
242                 BT_INFO("AV source Connect request not found or possibly already replied");
243                 req_info = _bt_get_request_info_data(BT_AUDIO_CONNECT, addr);
244
245                 if (req_info == NULL) {
246                         BT_INFO("AV Connect request & Audio All connect not found or possibly already replied");
247                         return;
248                 } else {
249                         BT_INFO("Audio All connect request found for address [%s]", addr);
250                         /* TODO Delete the search info if present */
251                         data = _bt_get_pending_audio_conn_info(addr);
252                         if (data) {
253                                 BT_INFO("Audio Connect All request present and pending connect is also present, delete info");
254                                 _bt_cleanup_audio_pending_conn_info_and_reply_pending_req(data, BLUETOOTH_ERROR_NONE);
255                         } else {
256                                 BT_ERR("Abnormal: Audio Connect All request present but pending connect absent");
257                         }
258                 }
259         } else {
260                 BT_INFO("AV Connect request found for [%s]", addr);
261         }
262
263         out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
264         g_array_append_vals(out_param, addr, BT_ADDRESS_STRING_SIZE);
265         _bt_service_method_return(req_info->context,
266                         out_param, result);
267         g_array_free(out_param, TRUE);
268         g_free(req_info->user_data);
269         _bt_free_info_from_invocation_list(req_info);
270 }
271
272 static void __bt_reply_av_source_disconnection_pending_request(bluetooth_device_address_t *address)
273 {
274         BT_DBG("+");
275         char addr[BT_ADDRESS_STRING_SIZE] = { 0 };
276         bluetooth_device_address_t device_address;
277         GArray *out_param;
278         invocation_info_t *req_info;
279         int result = BLUETOOTH_ERROR_NONE;
280         memcpy(device_address.addr, address->addr, BLUETOOTH_ADDRESS_LENGTH);
281         _bt_convert_addr_type_to_string(addr, address->addr);
282
283         req_info = _bt_get_request_info_data(BT_AV_SOURCE_DISCONNECT, addr);
284         if (NULL == req_info) {
285                 BT_INFO("AV DisConnect request not found or possibly already replied");
286                 req_info = _bt_get_request_info_data(BT_AUDIO_DISCONNECT, addr);
287                 if (req_info == NULL) {
288                         BT_INFO("AUDIO Disconnect All request also not found or possibly already replied");
289                         return;
290                 } else {
291                         BT_INFO("Audio All DisConnect request found..");
292                 }
293         } else {
294                 BT_INFO("AV Source DisConnect request found for [%s]", addr);
295         }
296
297         /* In any of the above cases, do DBUS return */
298         out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
299         g_array_append_vals(out_param, &device_address,
300                         sizeof(bluetooth_device_address_t));
301         _bt_service_method_return(req_info->context,
302                         out_param, result);
303         g_array_free(out_param, TRUE);
304         g_free(req_info->user_data);
305         _bt_free_info_from_invocation_list(req_info);
306 }
307
308 void _bt_a2dp_sink_handle_incoming_authorization(char *address, int service_id)
309 {
310         char connected_address[BT_ADDRESS_STRING_SIZE + 1];
311         gboolean connected;
312         bluetooth_device_address_t device_address;
313         oal_status_t res = OAL_STATUS_SUCCESS;
314         BT_INFO("+");
315
316         _bt_convert_addr_string_to_type(device_address.addr, address);
317
318         switch (service_id) {
319         case A2DP_SRC_SERVICE_ID:
320                 connected = _bt_is_headset_type_connected(BT_AUDIO_A2DP_SOURCE, connected_address);
321                 if (connected) {
322                         BT_INFO("A2DP (Remote Source) is already connected..check which device..");
323                         if (g_strcmp0(connected_address, address) != 0) {
324                                 BT_INFO("Different device is connected[%s] reject current [%s] device authorization request",
325                                                 connected_address, address);
326                                 res = device_reply_auth_request((bt_address_t*)&device_address, service_id, FALSE, FALSE);
327                                 if (res != OAL_STATUS_SUCCESS)
328                                         BT_ERR("authorize_response: %d", res);
329                                 return;
330                         }
331                 } else {
332                         res = device_reply_auth_request((bt_address_t*)&device_address, service_id, TRUE, FALSE);
333                         if (res != OAL_STATUS_SUCCESS)
334                                 BT_ERR("authorize_response: %d", res);
335                 }
336                 break;
337         default:
338                 BT_ERR("Invalid Audio Service ID..");
339         }
340
341         BT_INFO("-");
342 }
343
344 void _bt_a2dp_sink_event_handler(int oal_event, gpointer event_data)
345 {
346         BT_INFO("+");
347         bluetooth_device_address_t * bd_addr = (bluetooth_device_address_t*)event_data;
348
349         switch (oal_event) {
350         case OAL_EVENT_A2DP_SINK_CONNECTING:
351                 BT_INFO("A2DP Sink Profile connecting..");
352                 __bt_reply_av_source_connection_pending_request(bd_addr);
353                 break;
354         case OAL_EVENT_A2DP_SINK_DISCONNECTING:
355                 BT_INFO("A2DP Sink Profile disconnecting..");
356                 __bt_reply_av_source_disconnection_pending_request(bd_addr);
357                 break;
358         case OAL_EVENT_A2DP_SINK_CONNECTED:
359                 BT_INFO("A2DP Sink Profile connected..");
360                 __bt_handle_av_source_connected_state(bd_addr);
361                 break;
362         case OAL_EVENT_A2DP_SINK_DISCONNECTED:
363                 BT_INFO("A2DP Sink Profile dissconnected..");
364                 __bt_handle_av_source_disconnected_state(bd_addr);
365                 break;
366         default:
367                 BT_INFO("Invalid Event = %d", oal_event);
368                 break;
369         }
370         BT_INFO("-");
371 }