3917a925cf4c8cac9edcf39bda3282903d8bc12a
[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         g_free(req_info->user_data);
143         _bt_free_info_from_invocation_list(req_info);
144
145 try_waiting_device:
146         wait_list = _bt_get_audio_wait_data();
147         if (wait_list == NULL)
148                 return;
149         _bt_convert_addr_string_to_type(device_address.addr,
150                         wait_list->address);
151         BT_INFO("Trigger connect for the waiting device [%s], audio type [%d]",
152                         wait_list->address + 12, wait_list->type);
153         _bt_audio_connect(wait_list->type, &device_address);
154         _bt_rel_wait_data();
155 }
156
157 static void __bt_hf_handle_audio_connection_state(bt_address_t *bd_addr)
158 {
159         char address[BT_ADDRESS_STRING_SIZE] = { 0 };
160         bt_headset_wait_t *wait_list = NULL;
161         GArray *out_param;
162         unsigned int result = BLUETOOTH_ERROR_NONE;
163         invocation_info_t *req_info;
164         GVariant *param;
165
166         _bt_convert_addr_type_to_string(address, bd_addr->addr);
167         BT_INFO("HF(AG Role) Connected for address [%s]", address);
168
169         /* Send HF(AG Role) connected event to Application. Even though it is AG Audio
170            Connected, still send AG Connected event as per logic implemented in Tizen  */
171         param = g_variant_new("(is)", result, address);
172         _bt_send_event(BT_HEADSET_EVENT, BLUETOOTH_EVENT_AG_CONNECTED, param);
173
174         /* Add data to the connected list */
175         _bt_add_headset_to_list(BT_AUDIO_HSP,
176                         BT_STATE_CONNECTED, address);
177
178         wait_list = _bt_get_audio_wait_data();
179         if (wait_list != NULL &&
180                         (g_strcmp0(wait_list->address, address) == 0)) {
181                 BT_DBG("Same Device [%s] is under wait, connection type [%d], going to delete it",
182                                 wait_list->address, wait_list->type);
183                 _bt_rel_wait_data();
184         } else {
185                 if (wait_list != NULL)
186                         BT_DBG("Some Device [%s] is under wait, connection type [%d], ", wait_list->address, wait_list->type);
187         }
188
189         /* DBUS Context return */
190         req_info = _bt_get_request_info_data(BT_AUDIO_CONNECT, address);
191
192         if (NULL != req_info) {
193                 BT_DBG("Audio All Connect request found");
194                 goto check_pending_a2dp_connect;
195         } else {
196                 BT_DBG("Audio All Connect Request not found..");
197                 req_info = _bt_get_request_info_data(BT_AG_CONNECT, address);
198
199                 if (req_info) {
200                         BT_DBG("AG Connect Request found..");
201                         goto dbus_return;
202                 } else {
203                         BT_ERR("AG Connect Request also not found..Abnormal Case!!!");
204                         return;
205                 }
206         }
207
208 check_pending_a2dp_connect:
209         /* Check pending A2DP connection */
210         BT_DBG("Check A2DP pending connect");
211         if (_bt_audio_check_pending_connection(address) == TRUE) {
212                 BT_DBG("Pending A2DP connect is present..dont return DBUS for AUDIO_CONNECT_ALL");
213                 return;
214         }
215         BT_DBG("Pending A2DP connect is Not present..return DBUS for AUDIO_CONNECT_ALL");
216 dbus_return:
217         out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
218         g_array_append_vals(out_param, address, BT_ADDRESS_STRING_SIZE);
219         _bt_service_method_return(req_info->context,
220                         out_param, BLUETOOTH_ERROR_NONE);
221         g_array_free(out_param, TRUE);
222         g_free(req_info->user_data);
223         _bt_free_info_from_invocation_list(req_info);
224 }
225
226 static void __bt_reply_hf_connection_pending_request(bt_address_t *address)
227 {
228         BT_DBG("+");
229 }
230
231 /* This event handler process events for HF (AG role) */
232 void _bt_hf_event_handler(int oal_event, gpointer event_data)
233 {
234         bt_address_t * bt_addr = event_data;
235
236         switch (oal_event) {
237         case OAL_EVENT_HFP_DISCONNECTED:
238                 /* Reply to async request for HF connect or disconnect request, if any */
239                 BT_INFO("HF Profile disconnected, reply pending DBUS request and check waiting device");
240                 __bt_reply_hf_disconnection_pending_request(bt_addr);
241                 BT_PERMANENT_LOG("Disconnected AG");
242                 break;
243         case OAL_EVENT_HFP_AUDIO_DISCONNECTED:
244                 /* Reply to async request for HF connect or disconnect request, if any */
245                 BT_INFO("HF SCO disconnected, reply pending request if any and send event");
246                 __bt_hf_handle_audio_disconnection_state(bt_addr);
247                 BT_PERMANENT_LOG("Disconnected SCO");
248                 break;
249         case OAL_EVENT_HFP_CONNECTED:
250                 BT_INFO("HFP Profile connected, Event & DBUS context will be handled at finalizing SCO connect..");
251                 __bt_reply_hf_connection_pending_request(bt_addr);
252                 BT_PERMANENT_LOG("Connected AG");
253                 break;
254         case OAL_EVENT_HFP_AUDIO_CONNECTED:
255                 BT_INFO("HFP SCO conencted, handle the event..");
256                 __bt_hf_handle_audio_connection_state(bt_addr);
257                 BT_PERMANENT_LOG("Connected SCO");
258                 break;
259         case OAL_EVENT_HFP_CONNECTING:
260                 BT_INFO("HFP Profile connection successful, wait for Audio connect..");
261                 break;
262         case OAL_EVENT_HFP_DISCONNECTING:
263                 BT_INFO("HFP Connecting or Disconnecting..No need to send event to app");
264                 break;
265         case OAL_EVENT_HFP_AUDIO_CONNECTING:
266         case OAL_EVENT_HFP_AUDIO_DISCONNECTING:
267                 BT_INFO("HFP SCO conencting or disconnecting, Not handled..");
268                 break;
269         default:
270                 break;
271         }
272 }
273
274 int _bt_connect_remote_hfp(bluetooth_device_address_t *device_address)
275 {
276         oal_status_t status = OAL_STATUS_SUCCESS;
277         int result = BLUETOOTH_ERROR_NONE;
278         BT_DBG("+");
279
280         status = hfp_connect((bt_address_t *)device_address);
281         if (status != OAL_STATUS_SUCCESS) {
282                 BT_ERR("Connection could not be established, err: [%d]", status);
283                 result = _bt_convert_oal_status_to_bt_error(status);
284         }
285         return result;
286 }
287
288 int _bt_disconnect_remote_hfp(bluetooth_device_address_t *device_address)
289 {
290         oal_status_t status = OAL_STATUS_SUCCESS;
291         int result = BLUETOOTH_ERROR_NONE;
292         BT_DBG("+");
293
294         status = hfp_disconnect((bt_address_t *)device_address);
295         if (status != OAL_STATUS_SUCCESS) {
296                 BT_ERR("DisConnection err: [%d]", status);
297                 result = _bt_convert_oal_status_to_bt_error(status);
298         }
299         return result;
300 }