1 /******************************************************************************
2 *
3 * Copyright (c) 2014 The Android Open Source Project
4 * Copyright (C) 2004-2012 Broadcom Corporation
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at:
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 ******************************************************************************/
19
20 /******************************************************************************
21 *
22 * This file contains the audio gateway functions controlling the RFCOMM
23 * connections.
24 *
25 ******************************************************************************/
26
27 #include <string.h>
28 #include "bta_api.h"
29 #include "bta_hf_client_int.h"
30 #include "port_api.h"
31 #include "bt_utils.h"
32
33 /*******************************************************************************
34 **
35 ** Function bta_hf_client_port_cback
36 **
37 ** Description RFCOMM Port callback
38 **
39 **
40 ** Returns void
41 **
42 *******************************************************************************/
bta_hf_client_port_cback(UINT32 code,UINT16 port_handle)43 static void bta_hf_client_port_cback(UINT32 code, UINT16 port_handle)
44 {
45 BT_HDR *p_buf;
46 UNUSED(code);
47
48 /* ignore port events for port handles other than connected handle */
49 if (port_handle != bta_hf_client_cb.scb.conn_handle)
50 {
51 APPL_TRACE_DEBUG("bta_hf_client_port_cback ignoring handle:%d conn_handle = %d",
52 port_handle, bta_hf_client_cb.scb.conn_handle);
53 return;
54 }
55
56 if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)
57 {
58 p_buf->event = BTA_HF_CLIENT_RFC_DATA_EVT;
59 bta_sys_sendmsg(p_buf);
60 }
61 }
62
63 /*******************************************************************************
64 **
65 ** Function bta_hf_client_mgmt_cback
66 **
67 ** Description RFCOMM management callback
68 **
69 **
70 ** Returns void
71 **
72 *******************************************************************************/
bta_hf_client_mgmt_cback(UINT32 code,UINT16 port_handle)73 static void bta_hf_client_mgmt_cback(UINT32 code, UINT16 port_handle)
74 {
75 tBTA_HF_CLIENT_RFC *p_buf;
76 UINT16 event;
77
78 APPL_TRACE_DEBUG("bta_hf_client_mgmt_cback : code = %d, port_handle = %d, conn_handle = %d, serv_handle = %d",
79 code, port_handle, bta_hf_client_cb.scb.conn_handle, bta_hf_client_cb.scb.serv_handle);
80
81 /* ignore close event for port handles other than connected handle */
82 if ((code != PORT_SUCCESS) && (port_handle != bta_hf_client_cb.scb.conn_handle))
83 {
84 APPL_TRACE_DEBUG("bta_hf_client_mgmt_cback ignoring handle:%d", port_handle);
85 return;
86 }
87
88 if (code == PORT_SUCCESS)
89 {
90 if ((bta_hf_client_cb.scb.conn_handle && (port_handle == bta_hf_client_cb.scb.conn_handle)) || /* outgoing connection */
91 (port_handle == bta_hf_client_cb.scb.serv_handle)) /* incoming connection */
92 {
93 event = BTA_HF_CLIENT_RFC_OPEN_EVT;
94 }
95 else
96 {
97 APPL_TRACE_ERROR ("bta_hf_client_mgmt_cback: PORT_SUCCESS, ignoring handle = %d", port_handle);
98 return;
99 }
100 }
101 /* distinguish server close events */
102 else if (port_handle == bta_hf_client_cb.scb.conn_handle)
103 {
104 event = BTA_HF_CLIENT_RFC_CLOSE_EVT;
105 }
106 else
107 {
108 event = BTA_HF_CLIENT_RFC_SRV_CLOSE_EVT;
109 }
110
111 if ((p_buf = (tBTA_HF_CLIENT_RFC *) GKI_getbuf(sizeof(tBTA_HF_CLIENT_RFC))) != NULL)
112 {
113 p_buf->hdr.event = event;
114 p_buf->port_handle = port_handle;
115 bta_sys_sendmsg(p_buf);
116 }
117 }
118
119 /*******************************************************************************
120 **
121 ** Function bta_hf_client_setup_port
122 **
123 ** Description Setup RFCOMM port for use by HF Client.
124 **
125 **
126 ** Returns void
127 **
128 *******************************************************************************/
bta_hf_client_setup_port(UINT16 handle)129 void bta_hf_client_setup_port(UINT16 handle)
130 {
131 PORT_SetEventMask(handle, PORT_EV_RXCHAR);
132 PORT_SetEventCallback(handle, bta_hf_client_port_cback);
133 }
134
135 /*******************************************************************************
136 **
137 ** Function bta_hf_client_start_server
138 **
139 ** Description Setup RFCOMM server for use by HF Client.
140 **
141 **
142 ** Returns void
143 **
144 *******************************************************************************/
bta_hf_client_start_server(void)145 void bta_hf_client_start_server(void)
146 {
147 int port_status;
148
149 if (bta_hf_client_cb.scb.serv_handle > 0)
150 {
151 APPL_TRACE_DEBUG("%s already started, handle: %d", __FUNCTION__, bta_hf_client_cb.scb.serv_handle);
152 return;
153 }
154
155 BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_HF_HANDSFREE, bta_hf_client_cb.scb.serv_sec_mask,
156 BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, bta_hf_client_cb.scn);
157
158 port_status = RFCOMM_CreateConnection(UUID_SERVCLASS_HF_HANDSFREE, bta_hf_client_cb.scn,
159 TRUE, BTA_HF_CLIENT_MTU, (UINT8 *) bd_addr_any, &(bta_hf_client_cb.scb.serv_handle),
160 bta_hf_client_mgmt_cback);
161
162 if (port_status == PORT_SUCCESS)
163 {
164 bta_hf_client_setup_port(bta_hf_client_cb.scb.serv_handle);
165 }
166 else
167 {
168 /* TODO: can we handle this better? */
169 APPL_TRACE_DEBUG("bta_hf_client_start_server: RFCOMM_CreateConnection returned error:%d", port_status);
170 }
171
172 APPL_TRACE_DEBUG("bta_hf_client_start_server handle: %d", bta_hf_client_cb.scb.serv_handle);
173 }
174
175 /*******************************************************************************
176 **
177 ** Function bta_hf_client_close_server
178 **
179 ** Description Close RFCOMM server port for use by HF Client.
180 **
181 **
182 ** Returns void
183 **
184 *******************************************************************************/
bta_hf_client_close_server(void)185 void bta_hf_client_close_server(void)
186 {
187 APPL_TRACE_DEBUG("%s %d", __FUNCTION__, bta_hf_client_cb.scb.serv_handle);
188
189 if (bta_hf_client_cb.scb.serv_handle == 0)
190 {
191 APPL_TRACE_DEBUG("%s already stopped", __FUNCTION__);
192 return;
193 }
194
195 RFCOMM_RemoveServer(bta_hf_client_cb.scb.serv_handle);
196 bta_hf_client_cb.scb.serv_handle = 0;
197 }
198
199 /*******************************************************************************
200 **
201 ** Function bta_hf_client_rfc_do_open
202 **
203 ** Description Open an RFCOMM connection to the peer device.
204 **
205 **
206 ** Returns void
207 **
208 *******************************************************************************/
bta_hf_client_rfc_do_open(tBTA_HF_CLIENT_DATA * p_data)209 void bta_hf_client_rfc_do_open(tBTA_HF_CLIENT_DATA *p_data)
210 {
211 BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_HF_HANDSFREE,
212 bta_hf_client_cb.scb.cli_sec_mask, BT_PSM_RFCOMM,
213 BTM_SEC_PROTO_RFCOMM, bta_hf_client_cb.scb.peer_scn);
214
215 if (RFCOMM_CreateConnection(UUID_SERVCLASS_HF_HANDSFREE, bta_hf_client_cb.scb.peer_scn,
216 FALSE, BTA_HF_CLIENT_MTU, bta_hf_client_cb.scb.peer_addr, &(bta_hf_client_cb.scb.conn_handle),
217 bta_hf_client_mgmt_cback) == PORT_SUCCESS)
218 {
219 bta_hf_client_setup_port(bta_hf_client_cb.scb.conn_handle);
220 APPL_TRACE_DEBUG("bta_hf_client_rfc_do_open : conn_handle = %d", bta_hf_client_cb.scb.conn_handle);
221 }
222 /* RFCOMM create connection failed; send ourselves RFCOMM close event */
223 else
224 {
225 bta_hf_client_sm_execute(BTA_HF_CLIENT_RFC_CLOSE_EVT, p_data);
226 }
227 }
228
229 /*******************************************************************************
230 **
231 ** Function bta_hf_client_rfc_do_close
232 **
233 ** Description Close RFCOMM connection.
234 **
235 **
236 ** Returns void
237 **
238 *******************************************************************************/
bta_hf_client_rfc_do_close(tBTA_HF_CLIENT_DATA * p_data)239 void bta_hf_client_rfc_do_close(tBTA_HF_CLIENT_DATA *p_data)
240 {
241 tBTA_HF_CLIENT_RFC *p_buf;
242 UNUSED(p_data);
243
244 if (bta_hf_client_cb.scb.conn_handle)
245 {
246 RFCOMM_RemoveConnection(bta_hf_client_cb.scb.conn_handle);
247 }
248 else
249 {
250 /* Close API was called while HF Client is in Opening state. */
251 /* Need to trigger the state machine to send callback to the app */
252 /* and move back to INIT state. */
253 if ((p_buf = (tBTA_HF_CLIENT_RFC *) GKI_getbuf(sizeof(tBTA_HF_CLIENT_RFC))) != NULL)
254 {
255 p_buf->hdr.event = BTA_HF_CLIENT_RFC_CLOSE_EVT;
256 bta_sys_sendmsg(p_buf);
257 }
258
259 /* Cancel SDP if it had been started. */
260 if(bta_hf_client_cb.scb.p_disc_db)
261 {
262 (void)SDP_CancelServiceSearch (bta_hf_client_cb.scb.p_disc_db);
263 bta_hf_client_free_db(NULL);
264 }
265 }
266 }
267