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 "common/bt_defs.h"
29 #include "bta/bta_api.h"
30 #include "bta_hf_client_int.h"
31 #include "stack/port_api.h"
32 #include "osi/allocator.h"
33
34 #if (BTA_HF_INCLUDED == TRUE)
35 /*******************************************************************************
36 **
37 ** Function bta_hf_client_port_cback
38 **
39 ** Description RFCOMM Port callback
40 **
41 **
42 ** Returns void
43 **
44 *******************************************************************************/
bta_hf_client_port_cback(UINT32 code,UINT16 port_handle)45 static void bta_hf_client_port_cback(UINT32 code, UINT16 port_handle)
46 {
47 BT_HDR *p_buf;
48 UNUSED(code);
49
50 /* ignore port events for port handles other than connected handle */
51 if (port_handle != bta_hf_client_cb.scb.conn_handle) {
52 APPL_TRACE_DEBUG("bta_hf_client_port_cback ignoring handle:%d conn_handle = %d",
53 port_handle, bta_hf_client_cb.scb.conn_handle);
54 return;
55 }
56
57 if ((p_buf = (BT_HDR *) osi_malloc(sizeof(BT_HDR))) != NULL) {
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,void * data)73 static void bta_hf_client_mgmt_cback(UINT32 code, UINT16 port_handle, void* data)
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 APPL_TRACE_DEBUG("bta_hf_client_mgmt_cback ignoring handle:%d", port_handle);
84 return;
85 }
86
87 if (code == PORT_SUCCESS) {
88 if ((bta_hf_client_cb.scb.conn_handle && (port_handle == bta_hf_client_cb.scb.conn_handle)) || /* outgoing connection */
89 (port_handle == bta_hf_client_cb.scb.serv_handle)) { /* incoming connection */
90 event = BTA_HF_CLIENT_RFC_OPEN_EVT;
91 } else {
92 APPL_TRACE_ERROR ("bta_hf_client_mgmt_cback: PORT_SUCCESS, ignoring handle = %d", port_handle);
93 return;
94 }
95 }
96 /* distinguish server close events */
97 else if (port_handle == bta_hf_client_cb.scb.conn_handle) {
98 event = BTA_HF_CLIENT_RFC_CLOSE_EVT;
99 } else {
100 event = BTA_HF_CLIENT_RFC_SRV_CLOSE_EVT;
101 }
102
103 if ((p_buf = (tBTA_HF_CLIENT_RFC *) osi_malloc(sizeof(tBTA_HF_CLIENT_RFC))) != NULL) {
104 p_buf->hdr.event = event;
105 p_buf->port_handle = port_handle;
106 bta_sys_sendmsg(p_buf);
107 }
108 }
109
110 /*******************************************************************************
111 **
112 ** Function bta_hf_client_setup_port
113 **
114 ** Description Setup RFCOMM port for use by HF Client.
115 **
116 **
117 ** Returns void
118 **
119 *******************************************************************************/
bta_hf_client_setup_port(UINT16 handle)120 void bta_hf_client_setup_port(UINT16 handle)
121 {
122 PORT_SetEventMask(handle, PORT_EV_RXCHAR);
123 PORT_SetEventCallback(handle, bta_hf_client_port_cback);
124 }
125
126 /*******************************************************************************
127 **
128 ** Function bta_hf_client_start_server
129 **
130 ** Description Setup RFCOMM server for use by HF Client.
131 **
132 **
133 ** Returns void
134 **
135 *******************************************************************************/
bta_hf_client_start_server(void)136 void bta_hf_client_start_server(void)
137 {
138 int port_status;
139
140 if (bta_hf_client_cb.scb.serv_handle > 0) {
141 APPL_TRACE_DEBUG("%s already started, handle: %d", __FUNCTION__, bta_hf_client_cb.scb.serv_handle);
142 return;
143 }
144
145 BTM_SetSecurityLevel(FALSE, "", BTM_SEC_SERVICE_HF_HANDSFREE, bta_hf_client_cb.scb.serv_sec_mask,
146 BT_PSM_RFCOMM, BTM_SEC_PROTO_RFCOMM, bta_hf_client_cb.scn);
147
148 port_status = RFCOMM_CreateConnection(UUID_SERVCLASS_HF_HANDSFREE, bta_hf_client_cb.scn,
149 TRUE, BTA_HF_CLIENT_MTU, (UINT8 *) bd_addr_any, &(bta_hf_client_cb.scb.serv_handle),
150 bta_hf_client_mgmt_cback);
151
152 if (port_status == PORT_SUCCESS) {
153 bta_hf_client_setup_port(bta_hf_client_cb.scb.serv_handle);
154 } else {
155 /* TODO: can we handle this better? */
156 APPL_TRACE_DEBUG("bta_hf_client_start_server: RFCOMM_CreateConnection returned error:%d", port_status);
157 }
158
159 APPL_TRACE_DEBUG("bta_hf_client_start_server handle: %d", bta_hf_client_cb.scb.serv_handle);
160 }
161
162 /*******************************************************************************
163 **
164 ** Function bta_hf_client_close_server
165 **
166 ** Description Close RFCOMM server port for use by HF Client.
167 **
168 **
169 ** Returns void
170 **
171 *******************************************************************************/
bta_hf_client_close_server(void)172 void bta_hf_client_close_server(void)
173 {
174 APPL_TRACE_DEBUG("%s %d", __FUNCTION__, bta_hf_client_cb.scb.serv_handle);
175
176 if (bta_hf_client_cb.scb.serv_handle == 0) {
177 APPL_TRACE_DEBUG("%s already stopped", __FUNCTION__);
178 return;
179 }
180
181 RFCOMM_RemoveServer(bta_hf_client_cb.scb.serv_handle);
182 bta_hf_client_cb.scb.serv_handle = 0;
183 }
184
185 /*******************************************************************************
186 **
187 ** Function bta_hf_client_rfc_do_open
188 **
189 ** Description Open an RFCOMM connection to the peer device.
190 **
191 **
192 ** Returns void
193 **
194 *******************************************************************************/
bta_hf_client_rfc_do_open(tBTA_HF_CLIENT_DATA * p_data)195 void bta_hf_client_rfc_do_open(tBTA_HF_CLIENT_DATA *p_data)
196 {
197 BTM_SetSecurityLevel(TRUE, "", BTM_SEC_SERVICE_HF_HANDSFREE,
198 bta_hf_client_cb.scb.cli_sec_mask, BT_PSM_RFCOMM,
199 BTM_SEC_PROTO_RFCOMM, bta_hf_client_cb.scb.peer_scn);
200
201 if (RFCOMM_CreateConnection(UUID_SERVCLASS_HF_HANDSFREE, bta_hf_client_cb.scb.peer_scn,
202 FALSE, BTA_HF_CLIENT_MTU, bta_hf_client_cb.scb.peer_addr, &(bta_hf_client_cb.scb.conn_handle),
203 bta_hf_client_mgmt_cback) == PORT_SUCCESS) {
204 bta_hf_client_setup_port(bta_hf_client_cb.scb.conn_handle);
205 APPL_TRACE_DEBUG("bta_hf_client_rfc_do_open : conn_handle = %d", bta_hf_client_cb.scb.conn_handle);
206 }
207 /* RFCOMM create connection failed; send ourselves RFCOMM close event */
208 else {
209 bta_hf_client_sm_execute(BTA_HF_CLIENT_RFC_CLOSE_EVT, p_data);
210 }
211 }
212
213 /*******************************************************************************
214 **
215 ** Function bta_hf_client_rfc_do_close
216 **
217 ** Description Close RFCOMM connection.
218 **
219 **
220 ** Returns void
221 **
222 *******************************************************************************/
bta_hf_client_rfc_do_close(tBTA_HF_CLIENT_DATA * p_data)223 void bta_hf_client_rfc_do_close(tBTA_HF_CLIENT_DATA *p_data)
224 {
225 tBTA_HF_CLIENT_RFC *p_buf;
226 UNUSED(p_data);
227
228 if (bta_hf_client_cb.scb.conn_handle) {
229 RFCOMM_RemoveConnection(bta_hf_client_cb.scb.conn_handle);
230 } else {
231 /* Close API was called while HF Client is in Opening state. */
232 /* Need to trigger the state machine to send callback to the app */
233 /* and move back to INIT state. */
234 if ((p_buf = (tBTA_HF_CLIENT_RFC *) osi_malloc(sizeof(tBTA_HF_CLIENT_RFC))) != NULL) {
235 p_buf->hdr.event = BTA_HF_CLIENT_RFC_CLOSE_EVT;
236 bta_sys_sendmsg(p_buf);
237 }
238
239 /* Cancel SDP if it had been started. */
240 if (bta_hf_client_cb.scb.p_disc_db) {
241 (void)SDP_CancelServiceSearch (bta_hf_client_cb.scb.p_disc_db);
242 bta_hf_client_free_db(NULL);
243 }
244 }
245 }
246 #endif /* #if (BTA_HF_INCLUDED == TRUE) */
247