Fix wrong av disconnected event sending issue
[platform/core/connectivity/bluetooth-frwk.git] / bt-service-adaptation / services / audio / a2dp_src / bt-service-a2dp-src.c
1 /*
2  * Bluetooth-frwk
3  *
4  * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact:  Anupam Roy <anupam.r@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-audio-src.h>
32
33 #include <bt-service-a2dp-src.h>
34 #include <bt-service-event.h>
35
36 int _bt_a2dp_connect_remote_sink(bluetooth_device_address_t *device_address)
37 {
38         oal_status_t status = OAL_STATUS_SUCCESS;
39         int result = BLUETOOTH_ERROR_NONE;
40         BT_INFO("+");
41
42         status = audio_connect((bt_address_t*)device_address);
43         if (status != OAL_STATUS_SUCCESS) {
44                 BT_ERR("Connection could not be established, err: [%d]", status);
45                 result = BLUETOOTH_ERROR_INTERNAL;
46         }
47         return result;
48 }
49
50 int _bt_a2dp_disconnect_remote_sink(bluetooth_device_address_t *device_address)
51 {
52         oal_status_t status = OAL_STATUS_SUCCESS;
53         int result = BLUETOOTH_ERROR_NONE;
54         BT_INFO("+");
55
56         status = audio_disconnect((bt_address_t*)device_address);
57         if (status != OAL_STATUS_SUCCESS) {
58                 BT_ERR("DisConnection err: [%d]", status);
59                 result = BLUETOOTH_ERROR_INTERNAL;
60         }
61         return result;
62 }
63
64 static void __bt_handle_av_connected_state(bluetooth_device_address_t *address)
65 {
66         char addr[BT_ADDRESS_STRING_SIZE] = { 0 };
67         char connected_address[BT_ADDRESS_STRING_SIZE + 1];
68         gboolean connected;
69         bt_headset_wait_t *wait_device = NULL;
70         bluetooth_device_address_t device_address;
71         bluetooth_device_address_t wait_device_address;
72         GVariant *param;
73
74         GArray *out_param;
75         invocation_info_t *req_info;
76         bt_pending_audio_conn_t *data = NULL;
77
78         int result = BLUETOOTH_ERROR_NONE;
79         ret_if(NULL == address);
80         BT_INFO("+");
81
82         _bt_convert_addr_type_to_string(addr, address->addr);
83         BT_INFO("Address of connected device [%s]", addr);
84
85         /* Set VCONF Key for A2DP Connected status */
86         _bt_set_device_values(TRUE, VCONFKEY_BT_DEVICE_A2DP_HEADSET_CONNECTED);
87
88         /* Set readout notification of tts */
89 #ifdef TIZEN_FEATURE_READOUT_NOTIFICATION
90         _bt_set_readout_notification_of_tts();
91 #endif
92
93         /* Send A2DP(SRC Role) connected event to Application */
94         param = g_variant_new("(is)", result, addr);
95         _bt_send_event(BT_HEADSET_EVENT, BLUETOOTH_EVENT_AV_CONNECTED, param);
96
97         connected = _bt_is_headset_type_connected(BT_AUDIO_A2DP, connected_address);
98         if (connected) {
99                 BT_INFO("connected_address: %s", connected_address);
100                 if (g_strcmp0(connected_address, addr) != 0) {
101                         _bt_convert_addr_string_to_type(
102                                         device_address.addr,
103                                         connected_address);
104                         _bt_audio_disconnect(BT_AUDIO_A2DP, &device_address);
105                 }
106         }
107
108         /* Add data from the connected list */
109         _bt_add_headset_to_list(BT_AUDIO_A2DP, BT_STATE_CONNECTED, addr);
110
111 #ifdef TIZEN_FEATURE_BT_AVC_TARGET
112         /* Send the information to Absolute Volume Controller */
113         _bt_audio_handle_a2dp_state_changed(addr, true);
114 #endif
115
116         /* Delete waiting device data if present */
117         wait_device = _bt_get_audio_wait_data();
118         if (wait_device != NULL &&
119                         (g_strcmp0(wait_device->address, addr) == 0))
120                 _bt_rel_wait_data();
121         else {
122                 if (wait_device != NULL) {
123                         BT_INFO("A2DP Profile connected for device [%s] but another device [%s]is waiting to be connnected type [%d]",
124                                         addr, wait_device->address, wait_device->type);
125                         BT_INFO("Trigger connect for the waiting device [%s], audio type [%d]",
126                                         wait_device->address, wait_device->type);
127                         _bt_convert_addr_string_to_type(wait_device_address.addr,
128                                         wait_device->address);
129                         _bt_audio_connect(wait_device->type, &wait_device_address);
130                         /* Now free the wait list */
131                         //_bt_rel_wait_data();
132                 }
133         }
134
135         /* DBUS Context return */
136         req_info = _bt_get_request_info_data(BT_AV_CONNECT, addr);
137         if (NULL == req_info) {
138                 BT_INFO("AV Connect request not found or possibly already replied");
139                 req_info = _bt_get_request_info_data(BT_AUDIO_CONNECT, addr);
140
141                 if (req_info == NULL) {
142                         BT_INFO("AV Connect request & Audio All connect not found or possibly already replied");
143                         return;
144                 } else {
145                         BT_INFO("Audio All connect request found for address [%s]", addr);
146                         /* TODO Delete the search info if present */
147                         data = _bt_get_pending_audio_conn_info(addr);
148                         if (data) {
149                                 BT_INFO("Audio Connect All request present and pending connect is also present, delete info");
150                                 _bt_cleanup_audio_pending_conn_info_and_reply_pending_req(data, BLUETOOTH_ERROR_NONE);
151                                 return;
152                         } else {
153                                 BT_ERR("Abnormal: Audio Connect All request present but pending connect absent");
154                         }
155                 }
156         } else {
157                 BT_INFO("AV Connect request found for [%s]", addr);
158         }
159
160         out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
161         g_array_append_vals(out_param, addr, BT_ADDRESS_STRING_SIZE);
162         _bt_service_method_return(req_info->context,
163                         out_param, result);
164         g_array_free(out_param, TRUE);
165         g_free(req_info->user_data);
166         _bt_free_info_from_invocation_list(req_info);
167         BT_INFO("-");
168 }
169
170 static void __bt_handle_av_disconnected_state(bluetooth_device_address_t *address)
171 {
172         char addr[BT_ADDRESS_STRING_SIZE] = { 0 };
173         int result = BLUETOOTH_ERROR_NONE;
174         GArray *out_param;
175         bt_headset_wait_t *wait_device;
176         bluetooth_device_address_t device_address;
177         bt_pending_audio_conn_t *data = NULL;
178         GVariant *param;
179         invocation_info_t *req_info = NULL;
180         ret_if(NULL == address);
181         BT_INFO("+");
182
183         _bt_convert_addr_type_to_string(addr, address->addr);
184
185         /* Set VCONF status for A2DP Disconnection */
186         _bt_set_device_values(FALSE, VCONFKEY_BT_DEVICE_A2DP_HEADSET_CONNECTED);
187
188         /* Remove data from the connected list */
189         _bt_remove_headset_from_list(BT_AUDIO_A2DP, addr);
190
191 #ifdef TIZEN_FEATURE_BT_AVC_TARGET
192         /* Send the information to Absolute Volume Controller */
193         _bt_audio_handle_a2dp_state_changed(addr, false);
194 #endif
195
196         req_info = _bt_get_request_info_data(BT_AV_DISCONNECT, addr);
197         BT_INFO("Address  of disconnected device[%s]", addr);
198
199         if (NULL == req_info) {
200                 BT_INFO("AV DisConnect request not found or possibly already replied");
201                 req_info = _bt_get_request_info_data(BT_AV_CONNECT, addr);
202                 if (NULL == req_info) {
203                         /* This means, AV Disconnect request has successfully passed, and real disconnect is completed */
204                         BT_INFO("Neither AV Connect or AV Disconnect request is found..means, AV Profile is disconnected");
205
206                         req_info = _bt_get_request_info_data(BT_AUDIO_CONNECT, addr);
207                         if (req_info == NULL) {
208                                 BT_INFO("Audio Connect All request is also Not found..");
209
210                                 /* Send A2DP(SRC Role) disconnected event to Application */
211                                 param = g_variant_new("(is)", result, addr);
212                                 _bt_send_event(BT_HEADSET_EVENT, BLUETOOTH_EVENT_AV_DISCONNECTED, param);
213
214                                 req_info = _bt_get_request_info_data(BT_AUDIO_DISCONNECT, addr);
215                                 if (req_info == NULL) {
216                                         BT_INFO("Audio DisConnect All request is also Not found..");
217                                 } else {
218                                         BT_INFO("Audio DisConnect All request is found..");
219                                         /* Check if HFP profile is also connected, if yes, disconnect it too */
220                                         _bt_audio_check_pending_disconnection(addr, BT_AUDIO_HSP);
221                                 }
222                         } else {
223                                 BT_INFO("Audio Connect All request is found..");
224                                 result = BLUETOOTH_ERROR_INTERNAL;
225                                 data = _bt_get_pending_audio_conn_info(addr);
226                                 if (data) {
227                                         BT_INFO("Pending connect is found, delete it..");
228                                         _bt_cleanup_audio_pending_conn_info_and_reply_pending_req(data, result);
229                                         req_info = NULL;
230                                 } else {
231                                         BT_INFO("Pending connect is Not found..");
232                                 }
233
234                                 /* Delete waiting device data if present for this device */
235                                 wait_device = _bt_get_audio_wait_data();
236                                 if (wait_device && strncasecmp(wait_device->address, addr, BT_ADDRESS_STRING_SIZE) == 0) {
237                                         _bt_rel_wait_data();
238                                         goto dbus_return;
239                                 }
240                         }
241                         goto check_wait_device;
242                 } else {
243                         BT_ERR("AV Connect request has failed.."); /* DBUS return needed */
244                         result = BLUETOOTH_ERROR_INTERNAL;
245                         /* Delete waiting device data if present for this device */
246                         wait_device = _bt_get_audio_wait_data();
247                         if (wait_device && strncasecmp(wait_device->address, addr, BT_ADDRESS_STRING_SIZE) == 0) {
248                                 _bt_rel_wait_data();
249                                 goto dbus_return;
250                         }
251
252                         goto check_wait_device;
253                 }
254         } else {
255                 BT_ERR("AV Disconnect request found for [%s], means disconnect request is successful", addr); /* DBUS return needed */
256                 /* Send A2DP(SRC Role) disconnected event to Application */
257                 param = g_variant_new("(is)", result, addr);
258                 _bt_send_event(BT_HEADSET_EVENT, BLUETOOTH_EVENT_AV_DISCONNECTED, param);
259                 goto check_wait_device;
260         }
261 check_wait_device:
262         wait_device = _bt_get_audio_wait_data();
263
264         if (wait_device == NULL)
265                 goto dbus_return;
266
267         BT_INFO("type: %d, ag_flag: %d, disconnection_type: %d", wait_device->type,
268                         wait_device->ag_flag, wait_device->disconnection_type);
269         if (((wait_device->type == BT_AUDIO_ALL) &&
270                                 (wait_device->ag_flag == TRUE)) ||
271                         (wait_device->type == BT_AUDIO_A2DP) ||
272                         (wait_device->disconnection_type & BT_AUDIO_A2DP)) {
273                 if (g_strcmp0(wait_device->address, addr) != 0) {
274                         BT_INFO("Trigger connect for the waiting device [%s], audio type [%d]",
275                                         wait_device->address, wait_device->type);
276                         _bt_convert_addr_string_to_type(device_address.addr,
277                                         wait_device->address);
278                         _bt_audio_connect(wait_device->type, &device_address);
279                         /* Now free the wait list */
280                         //_bt_rel_wait_data();
281                 }
282         }
283
284 dbus_return:
285         if (req_info) {
286                 out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
287                 g_array_append_vals(out_param, addr, BT_ADDRESS_STRING_SIZE);
288                 _bt_service_method_return(req_info->context,
289                                 out_param, result);
290                 g_array_free(out_param, TRUE);
291                 g_free(req_info->user_data);
292                 _bt_free_info_from_invocation_list(req_info);
293         }
294 }
295
296 static void __bt_handle_av_audio_stopped(bluetooth_device_address_t *address)
297 {
298         BT_INFO("Currently not handled..");
299 }
300
301 static void __bt_handle_av_audio_started(bluetooth_device_address_t *address)
302 {
303         BT_INFO("Currently not handled..");
304 }
305
306 void _bt_a2dp_source_event_handler(int oal_event, gpointer event_data)
307 {
308         BT_INFO("+");
309         bluetooth_device_address_t * bd_addr = (bluetooth_device_address_t*)event_data;
310
311         switch (oal_event) {
312         case OAL_EVENT_AUDIO_CONNECTING:
313                 BT_INFO("A2DP Profile connecting..Ignore this event, wait for connected event");
314                 break;
315         case OAL_EVENT_AUDIO_DISCONNECTING:
316                 BT_INFO("A2DP Profile Disconnecting..Ignore this event, wait for Disconnected event");
317                 break;
318         case OAL_EVENT_AUDIO_CONNECTED:
319                 BT_INFO("A2DP Audio Profile connected..");
320                 __bt_handle_av_connected_state(bd_addr);
321                 BT_PERMANENT_LOG("Connected A2DP src");
322                 break;
323         case OAL_EVENT_AUDIO_DISCONNECTED:
324                 BT_INFO("A2DP Audio Profile dissconnected..");
325                 __bt_handle_av_disconnected_state(bd_addr);
326                 BT_PERMANENT_LOG("Disconnected A2DP src");
327                 break;
328         case OAL_EVENT_AUDIO_STOPPED:
329                 BT_INFO("A2DP Audio Stream stopped..");
330                 __bt_handle_av_audio_stopped(bd_addr);
331                 break;
332         case OAL_EVENT_AUDIO_STARTED:
333                 BT_INFO("A2DP Audio Stream started..");
334                 __bt_handle_av_audio_started(bd_addr);
335                 break;
336         default:
337                 BT_INFO("Invalid Event = %d", oal_event);
338                 break;
339         }
340         BT_INFO("-");
341 }
342
343 void _bt_a2dp_src_handle_incoming_authorization(char *address, int service_id)
344 {
345         char connected_address[BT_ADDRESS_STRING_SIZE + 1];
346         gboolean connected;
347         bluetooth_device_address_t device_address;
348         oal_status_t res = OAL_STATUS_SUCCESS;
349         BT_INFO("+");
350
351         _bt_convert_addr_string_to_type(device_address.addr, address);
352
353         switch (service_id) {
354         case A2DP_SERVICE_ID:
355                 connected = _bt_is_headset_type_connected(BT_AUDIO_A2DP, connected_address);
356                 if (connected) {
357                         BT_INFO("A2DP is already connected..check which device..");
358                         if (g_strcmp0(connected_address, address) != 0) {
359                                 BT_INFO("Different device is connected[%s] reject current [%s] device authorization request",
360                                                 connected_address, address);
361                                 res = device_reply_auth_request((bt_address_t*)&device_address, service_id, FALSE, FALSE);
362                                 if (res != OAL_STATUS_SUCCESS)
363                                         BT_ERR("authorize_response: %d", res);
364                                 return;
365                         }
366                 } else {
367                         res = device_reply_auth_request((bt_address_t*)&device_address, service_id, TRUE, FALSE);
368                         if (res != OAL_STATUS_SUCCESS)
369                                 BT_ERR("authorize_response: %d", res);
370                 }
371                 break;
372         default:
373                 BT_ERR("Invalid Audio Service ID..");
374         }
375
376         BT_INFO("-");
377 }