Simplify the logic to manage invocation list
[platform/core/connectivity/bluetooth-frwk.git] / bt-service-adaptation / services / audio / hf / bt-service-hf.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-manager.h"
30 #include "oal-audio-src.h"
31 #include "oal-hfp.h"
32 #include "oal-device-mgr.h"
33
34 #include <bt-service-a2dp-src.h>
35 #include <bt-service-hf.h>
36 #include <bt-service-event.h>
37
38 static void __bt_hf_handle_audio_disconnection_state(bt_address_t *address)
39 {
40         BT_DBG("+");
41         GVariant *param;
42         char addr[BT_ADDRESS_STRING_SIZE] = { 0 };
43         int result = BLUETOOTH_ERROR_NONE;
44         bt_headset_wait_t *wait_list;
45         bluetooth_device_address_t device_address;
46         ret_if(NULL == address);
47
48         _bt_convert_addr_type_to_string(addr, address->addr);
49
50         /* Send HF(AG Role) disconnected event to Application */
51         param = g_variant_new("(is)", result, addr);
52         _bt_send_event(BT_HEADSET_EVENT, BLUETOOTH_EVENT_AG_DISCONNECTED, param);
53
54         /*Handle Platform logics */
55         /* Remove data from the connected list */
56         _bt_remove_headset_from_list(BT_AUDIO_HSP, addr);
57
58         wait_list = _bt_get_audio_wait_data();
59         if (wait_list == NULL)
60                 return;
61         _bt_set_audio_wait_data_flag(TRUE);
62         _bt_convert_addr_string_to_type(device_address.addr,
63                         wait_list->address);
64         BT_INFO("Trigger connect for the waiting device [%s], audio type [%d]",
65                         wait_list->address, wait_list->type);
66         _bt_audio_connect(wait_list->type, &device_address);
67         _bt_rel_wait_data();
68
69         /*Handle Product logics */
70         BT_DBG("-");
71 }
72
73 static void __bt_reply_hf_disconnection_pending_request(bt_address_t *address)
74 {
75         char addr[BT_ADDRESS_STRING_SIZE] = { 0 };
76         bluetooth_device_address_t device_address;
77         GArray *out_param;
78         invocation_info_t *req_info;
79         bt_headset_wait_t *wait_list = NULL;
80         bt_pending_audio_conn_t* data = NULL;
81         int result = BLUETOOTH_ERROR_NONE;
82
83         ret_if(NULL == address);
84
85         memcpy(device_address.addr, address->addr, BLUETOOTH_ADDRESS_LENGTH);
86         _bt_convert_addr_type_to_string(addr, address->addr);
87
88         /* Remove data from the connected list */
89         _bt_remove_headset_from_list(BT_AUDIO_HSP, addr);
90
91         /* Find Async request information*/
92         req_info = _bt_get_request_info_data(BT_AG_DISCONNECT, addr);
93         if (NULL == req_info) {
94                 BT_DBG("AG DisConnect request not found or possibly already replied..");
95
96                 req_info = _bt_get_request_info_data(BT_AG_CONNECT, addr);
97                 if (req_info == NULL) {
98                         BT_DBG("AG Connect request also not found..");
99
100                         req_info = _bt_get_request_info_data(BT_AUDIO_DISCONNECT, addr);
101                         if (req_info == NULL) {
102                                 BT_DBG("AUDIO Disconnect request also not found..");
103
104                                 req_info = _bt_get_request_info_data(BT_AUDIO_CONNECT, addr);
105                                 if (req_info == NULL) {
106                                         BT_DBG("AUDIO Connect request also not found..");
107                                         return;
108                                 } else {
109                                         BT_DBG("AG Audio All Connect request found..");
110                                         result = BLUETOOTH_ERROR_INTERNAL;
111                                 }
112                         } else {
113                                 BT_DBG("Audio All DisConnect request found..");
114                         }
115                 } else {
116                         BT_DBG("AG Connect request found..");
117                         result = BLUETOOTH_ERROR_INTERNAL;
118                 }
119         } else {
120                 BT_DBG("AG DisConnect request found..");
121         }
122
123         /* Cleanup device service search info if Aysnc request was Audio Connect All */
124         if (req_info->service_function == BT_AUDIO_CONNECT) {
125                 /* Check if pending connect was present */
126                 data = _bt_get_pending_audio_conn_info(addr);
127                 if (data) {
128                         BT_DBG("HF Connection failed during Audio All connect, & pending connect present");
129                         _bt_cleanup_audio_pending_conn_info_and_reply_pending_req(data, BLUETOOTH_ERROR_INTERNAL);
130                         goto try_waiting_device;
131                 } else {
132                         BT_DBG("Abnormal:HF Connection failed during Audio All connect, but pending connect not present");
133                 }
134         }
135
136         /* In any of the above cases, reply DBUS context */
137         out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
138         g_array_append_vals(out_param, addr, BT_ADDRESS_STRING_SIZE);
139         _bt_service_method_return(req_info->context,
140                         out_param, result);
141         g_array_free(out_param, TRUE);
142         _bt_free_info_from_invocation_list(req_info);
143
144 try_waiting_device:
145         wait_list = _bt_get_audio_wait_data();
146         if (wait_list == NULL)
147                 return;
148         _bt_convert_addr_string_to_type(device_address.addr,
149                         wait_list->address);
150         BT_INFO("Trigger connect for the waiting device [%s], audio type [%d]",
151                         wait_list->address + 12, wait_list->type);
152         _bt_audio_connect(wait_list->type, &device_address);
153         _bt_rel_wait_data();
154 }
155
156 static void __bt_hf_handle_audio_connection_state(bt_address_t *bd_addr)
157 {
158         char address[BT_ADDRESS_STRING_SIZE] = { 0 };
159         bt_headset_wait_t *wait_list = NULL;
160         GArray *out_param;
161         unsigned int result = BLUETOOTH_ERROR_NONE;
162         invocation_info_t *req_info;
163         GVariant *param;
164
165         _bt_convert_addr_type_to_string(address, bd_addr->addr);
166         BT_INFO("HF(AG Role) Connected for address [%s]", address);
167
168         /* Send HF(AG Role) connected event to Application. Even though it is AG Audio
169            Connected, still send AG Connected event as per logic implemented in Tizen  */
170         param = g_variant_new("(is)", result, address);
171         _bt_send_event(BT_HEADSET_EVENT, BLUETOOTH_EVENT_AG_CONNECTED, param);
172
173         /* Add data to the connected list */
174         _bt_add_headset_to_list(BT_AUDIO_HSP,
175                         BT_STATE_CONNECTED, address);
176
177         wait_list = _bt_get_audio_wait_data();
178         if (wait_list != NULL &&
179                         (g_strcmp0(wait_list->address, address) == 0)) {
180                 BT_DBG("Same Device [%s] is under wait, connection type [%d], going to delete it",
181                                 wait_list->address, wait_list->type);
182                 _bt_rel_wait_data();
183         } else {
184                 if (wait_list != NULL)
185                         BT_DBG("Some Device [%s] is under wait, connection type [%d], ", wait_list->address, wait_list->type);
186         }
187
188         /* DBUS Context return */
189         req_info = _bt_get_request_info_data(BT_AUDIO_CONNECT, address);
190
191         if (NULL != req_info) {
192                 BT_DBG("Audio All Connect request found");
193                 goto check_pending_a2dp_connect;
194         } else {
195                 BT_DBG("Audio All Connect Request not found..");
196                 req_info = _bt_get_request_info_data(BT_AG_CONNECT, address);
197
198                 if (req_info) {
199                         BT_DBG("AG Connect Request found..");
200                         goto dbus_return;
201                 } else {
202                         BT_ERR("AG Connect Request also not found..Abnormal Case!!!");
203                         return;
204                 }
205         }
206
207 check_pending_a2dp_connect:
208         /* Check pending A2DP connection */
209         BT_DBG("Check A2DP pending connect");
210         if (_bt_audio_check_pending_connection(address) == TRUE) {
211                 BT_DBG("Pending A2DP connect is present..dont return DBUS for AUDIO_CONNECT_ALL");
212                 return;
213         }
214         BT_DBG("Pending A2DP connect is Not present..return DBUS for AUDIO_CONNECT_ALL");
215 dbus_return:
216         out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
217         g_array_append_vals(out_param, address, BT_ADDRESS_STRING_SIZE);
218         _bt_service_method_return(req_info->context,
219                         out_param, BLUETOOTH_ERROR_NONE);
220         g_array_free(out_param, TRUE);
221         _bt_free_info_from_invocation_list(req_info);
222 }
223
224 static void __bt_reply_hf_connection_pending_request(bt_address_t *address)
225 {
226         BT_DBG("+");
227 }
228
229 /* This event handler process events for HF (AG role) */
230 void _bt_hf_event_handler(int oal_event, gpointer event_data)
231 {
232         bt_address_t * bt_addr = event_data;
233
234         switch (oal_event) {
235         case OAL_EVENT_HFP_DISCONNECTED:
236                 /* Reply to async request for HF connect or disconnect request, if any */
237                 BT_INFO("HF Profile disconnected, reply pending DBUS request and check waiting device");
238                 __bt_reply_hf_disconnection_pending_request(bt_addr);
239                 BT_PERMANENT_LOG("Disconnected AG");
240                 break;
241         case OAL_EVENT_HFP_AUDIO_DISCONNECTED:
242                 /* Reply to async request for HF connect or disconnect request, if any */
243                 BT_INFO("HF SCO disconnected, reply pending request if any and send event");
244                 __bt_hf_handle_audio_disconnection_state(bt_addr);
245                 BT_PERMANENT_LOG("Disconnected SCO");
246                 break;
247         case OAL_EVENT_HFP_CONNECTED:
248                 BT_INFO("HFP Profile connected, Event & DBUS context will be handled at finalizing SCO connect..");
249                 __bt_reply_hf_connection_pending_request(bt_addr);
250                 BT_PERMANENT_LOG("Connected AG");
251                 break;
252         case OAL_EVENT_HFP_AUDIO_CONNECTED:
253                 BT_INFO("HFP SCO conencted, handle the event..");
254                 __bt_hf_handle_audio_connection_state(bt_addr);
255                 BT_PERMANENT_LOG("Connected SCO");
256                 break;
257         case OAL_EVENT_HFP_CONNECTING:
258                 BT_INFO("HFP Profile connection successful, wait for Audio connect..");
259                 break;
260         case OAL_EVENT_HFP_DISCONNECTING:
261                 BT_INFO("HFP Connecting or Disconnecting..No need to send event to app");
262                 break;
263         case OAL_EVENT_HFP_AUDIO_CONNECTING:
264         case OAL_EVENT_HFP_AUDIO_DISCONNECTING:
265                 BT_INFO("HFP SCO conencting or disconnecting, Not handled..");
266                 break;
267         default:
268                 break;
269         }
270 }
271
272 int _bt_connect_remote_hfp(bluetooth_device_address_t *device_address)
273 {
274         oal_status_t status = OAL_STATUS_SUCCESS;
275         int result = BLUETOOTH_ERROR_NONE;
276         BT_DBG("+");
277
278         status = hfp_connect((bt_address_t *)device_address);
279         if (status != OAL_STATUS_SUCCESS) {
280                 BT_ERR("Connection could not be established, err: [%d]", status);
281                 result = _bt_convert_oal_status_to_bt_error(status);
282         }
283         return result;
284 }
285
286 int _bt_disconnect_remote_hfp(bluetooth_device_address_t *device_address)
287 {
288         oal_status_t status = OAL_STATUS_SUCCESS;
289         int result = BLUETOOTH_ERROR_NONE;
290         BT_DBG("+");
291
292         status = hfp_disconnect((bt_address_t *)device_address);
293         if (status != OAL_STATUS_SUCCESS) {
294                 BT_ERR("DisConnection err: [%d]", status);
295                 result = _bt_convert_oal_status_to_bt_error(status);
296         }
297         return result;
298 }