xref: /btstack/src/classic/hfp_ag.c (revision 3deb3ec68039c68a16974dffc53343233662f909)
1*3deb3ec6SMatthias Ringwald /*
2*3deb3ec6SMatthias Ringwald  * Copyright (C) 2014 BlueKitchen GmbH
3*3deb3ec6SMatthias Ringwald  *
4*3deb3ec6SMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
5*3deb3ec6SMatthias Ringwald  * modification, are permitted provided that the following conditions
6*3deb3ec6SMatthias Ringwald  * are met:
7*3deb3ec6SMatthias Ringwald  *
8*3deb3ec6SMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
9*3deb3ec6SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
10*3deb3ec6SMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11*3deb3ec6SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
12*3deb3ec6SMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
13*3deb3ec6SMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
14*3deb3ec6SMatthias Ringwald  *    contributors may be used to endorse or promote products derived
15*3deb3ec6SMatthias Ringwald  *    from this software without specific prior written permission.
16*3deb3ec6SMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
17*3deb3ec6SMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
18*3deb3ec6SMatthias Ringwald  *    monetary gain.
19*3deb3ec6SMatthias Ringwald  *
20*3deb3ec6SMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21*3deb3ec6SMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*3deb3ec6SMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*3deb3ec6SMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24*3deb3ec6SMatthias Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25*3deb3ec6SMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26*3deb3ec6SMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27*3deb3ec6SMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28*3deb3ec6SMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29*3deb3ec6SMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30*3deb3ec6SMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*3deb3ec6SMatthias Ringwald  * SUCH DAMAGE.
32*3deb3ec6SMatthias Ringwald  *
33*3deb3ec6SMatthias Ringwald  * Please inquire about commercial licensing options at
34*3deb3ec6SMatthias Ringwald  * [email protected]
35*3deb3ec6SMatthias Ringwald  *
36*3deb3ec6SMatthias Ringwald  */
37*3deb3ec6SMatthias Ringwald 
38*3deb3ec6SMatthias Ringwald // *****************************************************************************
39*3deb3ec6SMatthias Ringwald //
40*3deb3ec6SMatthias Ringwald // Minimal setup for HFP Audio Gateway (AG) unit (!! UNDER DEVELOPMENT !!)
41*3deb3ec6SMatthias Ringwald //
42*3deb3ec6SMatthias Ringwald // *****************************************************************************
43*3deb3ec6SMatthias Ringwald 
44*3deb3ec6SMatthias Ringwald #include "btstack-config.h"
45*3deb3ec6SMatthias Ringwald 
46*3deb3ec6SMatthias Ringwald #include <stdint.h>
47*3deb3ec6SMatthias Ringwald #include <stdio.h>
48*3deb3ec6SMatthias Ringwald #include <stdlib.h>
49*3deb3ec6SMatthias Ringwald #include <string.h>
50*3deb3ec6SMatthias Ringwald 
51*3deb3ec6SMatthias Ringwald #include "hci_cmds.h"
52*3deb3ec6SMatthias Ringwald #include "run_loop.h"
53*3deb3ec6SMatthias Ringwald 
54*3deb3ec6SMatthias Ringwald #include "hci.h"
55*3deb3ec6SMatthias Ringwald #include "btstack_memory.h"
56*3deb3ec6SMatthias Ringwald #include "hci_dump.h"
57*3deb3ec6SMatthias Ringwald #include "l2cap.h"
58*3deb3ec6SMatthias Ringwald #include "sdp_query_rfcomm.h"
59*3deb3ec6SMatthias Ringwald #include "sdp.h"
60*3deb3ec6SMatthias Ringwald #include "debug.h"
61*3deb3ec6SMatthias Ringwald #include "hfp.h"
62*3deb3ec6SMatthias Ringwald #include "hfp_ag.h"
63*3deb3ec6SMatthias Ringwald 
64*3deb3ec6SMatthias Ringwald static const char default_hfp_ag_service_name[] = "Voice gateway";
65*3deb3ec6SMatthias Ringwald static uint16_t hfp_supported_features = HFP_DEFAULT_AG_SUPPORTED_FEATURES;
66*3deb3ec6SMatthias Ringwald static uint8_t hfp_codecs_nr = 0;
67*3deb3ec6SMatthias Ringwald static uint8_t hfp_codecs[HFP_MAX_NUM_CODECS];
68*3deb3ec6SMatthias Ringwald 
69*3deb3ec6SMatthias Ringwald static int  hfp_ag_indicators_nr = 0;
70*3deb3ec6SMatthias Ringwald static hfp_ag_indicator_t hfp_ag_indicators[HFP_MAX_NUM_AG_INDICATORS];
71*3deb3ec6SMatthias Ringwald 
72*3deb3ec6SMatthias Ringwald static int  hfp_ag_call_hold_services_nr = 0;
73*3deb3ec6SMatthias Ringwald static char *hfp_ag_call_hold_services[6];
74*3deb3ec6SMatthias Ringwald static hfp_callback_t hfp_callback;
75*3deb3ec6SMatthias Ringwald 
76*3deb3ec6SMatthias Ringwald static void packet_handler(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
77*3deb3ec6SMatthias Ringwald 
78*3deb3ec6SMatthias Ringwald hfp_generic_status_indicator_t * get_hfp_generic_status_indicators();
79*3deb3ec6SMatthias Ringwald int get_hfp_generic_status_indicators_nr();
80*3deb3ec6SMatthias Ringwald void set_hfp_generic_status_indicators(hfp_generic_status_indicator_t * indicators, int indicator_nr);
81*3deb3ec6SMatthias Ringwald void set_hfp_ag_indicators(hfp_ag_indicator_t * indicators, int indicator_nr);
82*3deb3ec6SMatthias Ringwald int get_hfp_ag_indicators_nr(hfp_connection_t * context);
83*3deb3ec6SMatthias Ringwald hfp_ag_indicator_t * get_hfp_ag_indicators(hfp_connection_t * context);
84*3deb3ec6SMatthias Ringwald 
85*3deb3ec6SMatthias Ringwald 
86*3deb3ec6SMatthias Ringwald hfp_ag_indicator_t * get_hfp_ag_indicators(hfp_connection_t * context){
87*3deb3ec6SMatthias Ringwald     // TODO: save only value, and value changed in the context?
88*3deb3ec6SMatthias Ringwald     if (context->ag_indicators_nr != hfp_ag_indicators_nr){
89*3deb3ec6SMatthias Ringwald         context->ag_indicators_nr = hfp_ag_indicators_nr;
90*3deb3ec6SMatthias Ringwald         memcpy(context->ag_indicators, hfp_ag_indicators, hfp_ag_indicators_nr * sizeof(hfp_ag_indicator_t));
91*3deb3ec6SMatthias Ringwald     }
92*3deb3ec6SMatthias Ringwald     return (hfp_ag_indicator_t *)&(context->ag_indicators);
93*3deb3ec6SMatthias Ringwald }
94*3deb3ec6SMatthias Ringwald 
95*3deb3ec6SMatthias Ringwald void set_hfp_ag_indicators(hfp_ag_indicator_t * indicators, int indicator_nr){
96*3deb3ec6SMatthias Ringwald     memcpy(hfp_ag_indicators, indicators, indicator_nr * sizeof(hfp_ag_indicator_t));
97*3deb3ec6SMatthias Ringwald     hfp_ag_indicators_nr = indicator_nr;
98*3deb3ec6SMatthias Ringwald }
99*3deb3ec6SMatthias Ringwald 
100*3deb3ec6SMatthias Ringwald int get_hfp_ag_indicators_nr(hfp_connection_t * context){
101*3deb3ec6SMatthias Ringwald     if (context->ag_indicators_nr != hfp_ag_indicators_nr){
102*3deb3ec6SMatthias Ringwald         context->ag_indicators_nr = hfp_ag_indicators_nr;
103*3deb3ec6SMatthias Ringwald         memcpy(context->ag_indicators, hfp_ag_indicators, hfp_ag_indicators_nr * sizeof(hfp_ag_indicator_t));
104*3deb3ec6SMatthias Ringwald     }
105*3deb3ec6SMatthias Ringwald     return context->ag_indicators_nr;
106*3deb3ec6SMatthias Ringwald }
107*3deb3ec6SMatthias Ringwald 
108*3deb3ec6SMatthias Ringwald 
109*3deb3ec6SMatthias Ringwald void hfp_ag_register_packet_handler(hfp_callback_t callback){
110*3deb3ec6SMatthias Ringwald     if (callback == NULL){
111*3deb3ec6SMatthias Ringwald         log_error("hfp_ag_register_packet_handler called with NULL callback");
112*3deb3ec6SMatthias Ringwald         return;
113*3deb3ec6SMatthias Ringwald     }
114*3deb3ec6SMatthias Ringwald     hfp_callback = callback;
115*3deb3ec6SMatthias Ringwald }
116*3deb3ec6SMatthias Ringwald 
117*3deb3ec6SMatthias Ringwald static uint8_t hfp_get_indicator_index_by_name(hfp_connection_t * context, const char * name){
118*3deb3ec6SMatthias Ringwald     int i;
119*3deb3ec6SMatthias Ringwald     for (i=0; i<context->ag_indicators_nr; i++){
120*3deb3ec6SMatthias Ringwald         if (strcmp(context->ag_indicators[i].name, name) == 0){
121*3deb3ec6SMatthias Ringwald             return i;
122*3deb3ec6SMatthias Ringwald         }
123*3deb3ec6SMatthias Ringwald     }
124*3deb3ec6SMatthias Ringwald     return 0xFF;
125*3deb3ec6SMatthias Ringwald }
126*3deb3ec6SMatthias Ringwald 
127*3deb3ec6SMatthias Ringwald static void hfp_ag_update_indicator_status(hfp_connection_t * context, const char * indicator_name, uint8_t status){
128*3deb3ec6SMatthias Ringwald     int index = hfp_get_indicator_index_by_name(context, indicator_name);
129*3deb3ec6SMatthias Ringwald     if (index == 0xFF) return;
130*3deb3ec6SMatthias Ringwald     if (context->ag_indicators[index].status == status) return;
131*3deb3ec6SMatthias Ringwald     context->ag_indicators[index].status = status;
132*3deb3ec6SMatthias Ringwald     context->ag_indicators[index].status_changed = 1;
133*3deb3ec6SMatthias Ringwald }
134*3deb3ec6SMatthias Ringwald 
135*3deb3ec6SMatthias Ringwald static int has_codec_negotiation_feature(hfp_connection_t * connection){
136*3deb3ec6SMatthias Ringwald     int hf = get_bit(connection->remote_supported_features, HFP_HFSF_CODEC_NEGOTIATION);
137*3deb3ec6SMatthias Ringwald     int ag = get_bit(hfp_supported_features, HFP_AGSF_CODEC_NEGOTIATION);
138*3deb3ec6SMatthias Ringwald     return hf && ag;
139*3deb3ec6SMatthias Ringwald }
140*3deb3ec6SMatthias Ringwald 
141*3deb3ec6SMatthias Ringwald static int has_call_waiting_and_3way_calling_feature(hfp_connection_t * connection){
142*3deb3ec6SMatthias Ringwald     int hf = get_bit(connection->remote_supported_features, HFP_HFSF_THREE_WAY_CALLING);
143*3deb3ec6SMatthias Ringwald     int ag = get_bit(hfp_supported_features, HFP_AGSF_THREE_WAY_CALLING);
144*3deb3ec6SMatthias Ringwald     return hf && ag;
145*3deb3ec6SMatthias Ringwald }
146*3deb3ec6SMatthias Ringwald 
147*3deb3ec6SMatthias Ringwald static int has_hf_indicators_feature(hfp_connection_t * connection){
148*3deb3ec6SMatthias Ringwald     int hf = get_bit(connection->remote_supported_features, HFP_HFSF_HF_INDICATORS);
149*3deb3ec6SMatthias Ringwald     int ag = get_bit(hfp_supported_features, HFP_AGSF_HF_INDICATORS);
150*3deb3ec6SMatthias Ringwald     return hf && ag;
151*3deb3ec6SMatthias Ringwald }
152*3deb3ec6SMatthias Ringwald 
153*3deb3ec6SMatthias Ringwald void hfp_ag_create_sdp_record(uint8_t * service, int rfcomm_channel_nr, const char * name, uint8_t ability_to_reject_call, uint16_t supported_features){
154*3deb3ec6SMatthias Ringwald     if (!name){
155*3deb3ec6SMatthias Ringwald         name = default_hfp_ag_service_name;
156*3deb3ec6SMatthias Ringwald     }
157*3deb3ec6SMatthias Ringwald     hfp_create_sdp_record(service, SDP_HandsfreeAudioGateway, rfcomm_channel_nr, name, supported_features);
158*3deb3ec6SMatthias Ringwald 
159*3deb3ec6SMatthias Ringwald     // Network
160*3deb3ec6SMatthias Ringwald     de_add_number(service, DE_UINT, DE_SIZE_8, ability_to_reject_call);
161*3deb3ec6SMatthias Ringwald     /*
162*3deb3ec6SMatthias Ringwald      * 0x01 – Ability to reject a call
163*3deb3ec6SMatthias Ringwald      * 0x00 – No ability to reject a call
164*3deb3ec6SMatthias Ringwald      */
165*3deb3ec6SMatthias Ringwald }
166*3deb3ec6SMatthias Ringwald 
167*3deb3ec6SMatthias Ringwald static int hfp_ag_exchange_supported_features_cmd(uint16_t cid){
168*3deb3ec6SMatthias Ringwald     char buffer[40];
169*3deb3ec6SMatthias Ringwald     sprintf(buffer, "\r\n%s:%d\r\n\r\nOK\r\n", HFP_SUPPORTED_FEATURES, hfp_supported_features);
170*3deb3ec6SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
171*3deb3ec6SMatthias Ringwald }
172*3deb3ec6SMatthias Ringwald 
173*3deb3ec6SMatthias Ringwald static int hfp_ag_ok(uint16_t cid){
174*3deb3ec6SMatthias Ringwald     char buffer[10];
175*3deb3ec6SMatthias Ringwald     sprintf(buffer, "\r\nOK\r\n");
176*3deb3ec6SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
177*3deb3ec6SMatthias Ringwald }
178*3deb3ec6SMatthias Ringwald 
179*3deb3ec6SMatthias Ringwald static int hfp_ag_error(uint16_t cid){
180*3deb3ec6SMatthias Ringwald     char buffer[10];
181*3deb3ec6SMatthias Ringwald     sprintf(buffer, "\r\nERROR\r\n");
182*3deb3ec6SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
183*3deb3ec6SMatthias Ringwald }
184*3deb3ec6SMatthias Ringwald 
185*3deb3ec6SMatthias Ringwald static int hfp_ag_report_extended_audio_gateway_error(uint16_t cid, uint8_t error){
186*3deb3ec6SMatthias Ringwald     char buffer[20];
187*3deb3ec6SMatthias Ringwald     sprintf(buffer, "\r\n%s=%d\r\n", HFP_EXTENDED_AUDIO_GATEWAY_ERROR, error);
188*3deb3ec6SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
189*3deb3ec6SMatthias Ringwald }
190*3deb3ec6SMatthias Ringwald 
191*3deb3ec6SMatthias Ringwald static int hfp_ag_retrieve_codec_cmd(uint16_t cid){
192*3deb3ec6SMatthias Ringwald     return hfp_ag_ok(cid);
193*3deb3ec6SMatthias Ringwald }
194*3deb3ec6SMatthias Ringwald 
195*3deb3ec6SMatthias Ringwald static int hfp_ag_indicators_join(char * buffer, int buffer_size, hfp_connection_t * context){
196*3deb3ec6SMatthias Ringwald     if (buffer_size < get_hfp_ag_indicators_nr(context) * (1 + sizeof(hfp_ag_indicator_t))) return 0;
197*3deb3ec6SMatthias Ringwald     int i;
198*3deb3ec6SMatthias Ringwald     int offset = 0;
199*3deb3ec6SMatthias Ringwald     for (i = 0; i < get_hfp_ag_indicators_nr(context)-1; i++) {
200*3deb3ec6SMatthias Ringwald         offset += snprintf(buffer+offset, buffer_size-offset, "(\"%s\",(%d,%d)),",
201*3deb3ec6SMatthias Ringwald             get_hfp_ag_indicators(context)[i].name,
202*3deb3ec6SMatthias Ringwald             get_hfp_ag_indicators(context)[i].min_range,
203*3deb3ec6SMatthias Ringwald             get_hfp_ag_indicators(context)[i].max_range);
204*3deb3ec6SMatthias Ringwald     }
205*3deb3ec6SMatthias Ringwald     if ( i < get_hfp_ag_indicators_nr(context)){
206*3deb3ec6SMatthias Ringwald         offset += snprintf(buffer+offset, buffer_size-offset, "(\"%s\",(%d,%d))",
207*3deb3ec6SMatthias Ringwald             get_hfp_ag_indicators(context)[i].name,
208*3deb3ec6SMatthias Ringwald             get_hfp_ag_indicators(context)[i].min_range,
209*3deb3ec6SMatthias Ringwald             get_hfp_ag_indicators(context)[i].max_range);
210*3deb3ec6SMatthias Ringwald     }
211*3deb3ec6SMatthias Ringwald     return offset;
212*3deb3ec6SMatthias Ringwald }
213*3deb3ec6SMatthias Ringwald 
214*3deb3ec6SMatthias Ringwald static int hfp_hf_indicators_join(char * buffer, int buffer_size){
215*3deb3ec6SMatthias Ringwald     if (buffer_size < hfp_ag_indicators_nr * 3) return 0;
216*3deb3ec6SMatthias Ringwald     int i;
217*3deb3ec6SMatthias Ringwald     int offset = 0;
218*3deb3ec6SMatthias Ringwald     for (i = 0; i < get_hfp_generic_status_indicators_nr()-1; i++) {
219*3deb3ec6SMatthias Ringwald         offset += snprintf(buffer+offset, buffer_size-offset, "%d,", get_hfp_generic_status_indicators()[i].uuid);
220*3deb3ec6SMatthias Ringwald     }
221*3deb3ec6SMatthias Ringwald     if (i < get_hfp_generic_status_indicators_nr()){
222*3deb3ec6SMatthias Ringwald         offset += snprintf(buffer+offset, buffer_size-offset, "%d,", get_hfp_generic_status_indicators()[i].uuid);
223*3deb3ec6SMatthias Ringwald     }
224*3deb3ec6SMatthias Ringwald     return offset;
225*3deb3ec6SMatthias Ringwald }
226*3deb3ec6SMatthias Ringwald 
227*3deb3ec6SMatthias Ringwald static int hfp_hf_indicators_initial_status_join(char * buffer, int buffer_size){
228*3deb3ec6SMatthias Ringwald     if (buffer_size < get_hfp_generic_status_indicators_nr() * 3) return 0;
229*3deb3ec6SMatthias Ringwald     int i;
230*3deb3ec6SMatthias Ringwald     int offset = 0;
231*3deb3ec6SMatthias Ringwald     for (i = 0; i < get_hfp_generic_status_indicators_nr(); i++) {
232*3deb3ec6SMatthias Ringwald         offset += snprintf(buffer+offset, buffer_size-offset, "\r\n%s:%d,%d\r\n", HFP_GENERIC_STATUS_INDICATOR, get_hfp_generic_status_indicators()[i].uuid, get_hfp_generic_status_indicators()[i].state);
233*3deb3ec6SMatthias Ringwald     }
234*3deb3ec6SMatthias Ringwald     return offset;
235*3deb3ec6SMatthias Ringwald }
236*3deb3ec6SMatthias Ringwald 
237*3deb3ec6SMatthias Ringwald static int hfp_ag_indicators_status_join(char * buffer, int buffer_size){
238*3deb3ec6SMatthias Ringwald     if (buffer_size < hfp_ag_indicators_nr * 3) return 0;
239*3deb3ec6SMatthias Ringwald     int i;
240*3deb3ec6SMatthias Ringwald     int offset = 0;
241*3deb3ec6SMatthias Ringwald     for (i = 0; i < hfp_ag_indicators_nr-1; i++) {
242*3deb3ec6SMatthias Ringwald         offset += snprintf(buffer+offset, buffer_size-offset, "%d,", hfp_ag_indicators[i].status);
243*3deb3ec6SMatthias Ringwald     }
244*3deb3ec6SMatthias Ringwald     if (i<hfp_ag_indicators_nr){
245*3deb3ec6SMatthias Ringwald         offset += snprintf(buffer+offset, buffer_size-offset, "%d", hfp_ag_indicators[i].status);
246*3deb3ec6SMatthias Ringwald     }
247*3deb3ec6SMatthias Ringwald     return offset;
248*3deb3ec6SMatthias Ringwald }
249*3deb3ec6SMatthias Ringwald 
250*3deb3ec6SMatthias Ringwald static int hfp_ag_call_services_join(char * buffer, int buffer_size){
251*3deb3ec6SMatthias Ringwald     if (buffer_size < hfp_ag_call_hold_services_nr * 3) return 0;
252*3deb3ec6SMatthias Ringwald     int i;
253*3deb3ec6SMatthias Ringwald     int offset = snprintf(buffer, buffer_size, "(");
254*3deb3ec6SMatthias Ringwald     for (i = 0; i < hfp_ag_call_hold_services_nr-1; i++) {
255*3deb3ec6SMatthias Ringwald         offset += snprintf(buffer+offset, buffer_size-offset, "%s,", hfp_ag_call_hold_services[i]);
256*3deb3ec6SMatthias Ringwald     }
257*3deb3ec6SMatthias Ringwald     if (i<hfp_ag_call_hold_services_nr){
258*3deb3ec6SMatthias Ringwald         offset += snprintf(buffer+offset, buffer_size-offset, "%s)", hfp_ag_call_hold_services[i]);
259*3deb3ec6SMatthias Ringwald     }
260*3deb3ec6SMatthias Ringwald     return offset;
261*3deb3ec6SMatthias Ringwald }
262*3deb3ec6SMatthias Ringwald 
263*3deb3ec6SMatthias Ringwald static int hfp_ag_retrieve_indicators_cmd(uint16_t cid, hfp_connection_t * context){
264*3deb3ec6SMatthias Ringwald     char buffer[250];
265*3deb3ec6SMatthias Ringwald     int offset = snprintf(buffer, sizeof(buffer), "\r\n%s:", HFP_INDICATOR);
266*3deb3ec6SMatthias Ringwald     offset += hfp_ag_indicators_join(buffer+offset, sizeof(buffer)-offset, context);
267*3deb3ec6SMatthias Ringwald 
268*3deb3ec6SMatthias Ringwald     buffer[offset] = 0;
269*3deb3ec6SMatthias Ringwald 
270*3deb3ec6SMatthias Ringwald     offset += snprintf(buffer+offset, sizeof(buffer)-offset, "\r\n\r\nOK\r\n");
271*3deb3ec6SMatthias Ringwald     buffer[offset] = 0;
272*3deb3ec6SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
273*3deb3ec6SMatthias Ringwald }
274*3deb3ec6SMatthias Ringwald 
275*3deb3ec6SMatthias Ringwald static int hfp_ag_retrieve_indicators_status_cmd(uint16_t cid){
276*3deb3ec6SMatthias Ringwald     char buffer[40];
277*3deb3ec6SMatthias Ringwald     int offset = snprintf(buffer, sizeof(buffer), "\r\n%s:", HFP_INDICATOR);
278*3deb3ec6SMatthias Ringwald     offset += hfp_ag_indicators_status_join(buffer+offset, sizeof(buffer)-offset);
279*3deb3ec6SMatthias Ringwald 
280*3deb3ec6SMatthias Ringwald     buffer[offset] = 0;
281*3deb3ec6SMatthias Ringwald 
282*3deb3ec6SMatthias Ringwald     offset += snprintf(buffer+offset, sizeof(buffer)-offset, "\r\n\r\nOK\r\n");
283*3deb3ec6SMatthias Ringwald     buffer[offset] = 0;
284*3deb3ec6SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
285*3deb3ec6SMatthias Ringwald }
286*3deb3ec6SMatthias Ringwald 
287*3deb3ec6SMatthias Ringwald static int hfp_ag_set_indicator_status_update_cmd(uint16_t cid, uint8_t activate){
288*3deb3ec6SMatthias Ringwald     // AT\r\n%s:3,0,0,%d\r\n
289*3deb3ec6SMatthias Ringwald     return hfp_ag_ok(cid);
290*3deb3ec6SMatthias Ringwald }
291*3deb3ec6SMatthias Ringwald 
292*3deb3ec6SMatthias Ringwald 
293*3deb3ec6SMatthias Ringwald static int hfp_ag_retrieve_can_hold_call_cmd(uint16_t cid){
294*3deb3ec6SMatthias Ringwald     char buffer[100];
295*3deb3ec6SMatthias Ringwald     int offset = snprintf(buffer, sizeof(buffer), "\r\n%s:", HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES);
296*3deb3ec6SMatthias Ringwald     offset += hfp_ag_call_services_join(buffer+offset, sizeof(buffer)-offset);
297*3deb3ec6SMatthias Ringwald 
298*3deb3ec6SMatthias Ringwald     buffer[offset] = 0;
299*3deb3ec6SMatthias Ringwald 
300*3deb3ec6SMatthias Ringwald     offset += snprintf(buffer+offset, sizeof(buffer)-offset, "\r\n\r\nOK\r\n");
301*3deb3ec6SMatthias Ringwald     buffer[offset] = 0;
302*3deb3ec6SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
303*3deb3ec6SMatthias Ringwald }
304*3deb3ec6SMatthias Ringwald 
305*3deb3ec6SMatthias Ringwald 
306*3deb3ec6SMatthias Ringwald static int hfp_ag_list_supported_generic_status_indicators_cmd(uint16_t cid){
307*3deb3ec6SMatthias Ringwald     return hfp_ag_ok(cid);
308*3deb3ec6SMatthias Ringwald }
309*3deb3ec6SMatthias Ringwald 
310*3deb3ec6SMatthias Ringwald static int hfp_ag_retrieve_supported_generic_status_indicators_cmd(uint16_t cid){
311*3deb3ec6SMatthias Ringwald     char buffer[40];
312*3deb3ec6SMatthias Ringwald     int offset = snprintf(buffer, sizeof(buffer), "\r\n%s:", HFP_GENERIC_STATUS_INDICATOR);
313*3deb3ec6SMatthias Ringwald     offset += hfp_hf_indicators_join(buffer+offset, sizeof(buffer)-offset);
314*3deb3ec6SMatthias Ringwald 
315*3deb3ec6SMatthias Ringwald     buffer[offset] = 0;
316*3deb3ec6SMatthias Ringwald 
317*3deb3ec6SMatthias Ringwald     offset += snprintf(buffer+offset, sizeof(buffer)-offset, "\r\n\r\nOK\r\n");
318*3deb3ec6SMatthias Ringwald     buffer[offset] = 0;
319*3deb3ec6SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
320*3deb3ec6SMatthias Ringwald }
321*3deb3ec6SMatthias Ringwald 
322*3deb3ec6SMatthias Ringwald static int hfp_ag_retrieve_initital_supported_generic_status_indicators_cmd(uint16_t cid){
323*3deb3ec6SMatthias Ringwald     char buffer[40];
324*3deb3ec6SMatthias Ringwald     int offset = hfp_hf_indicators_initial_status_join(buffer, sizeof(buffer));
325*3deb3ec6SMatthias Ringwald 
326*3deb3ec6SMatthias Ringwald     buffer[offset] = 0;
327*3deb3ec6SMatthias Ringwald     offset += snprintf(buffer+offset, sizeof(buffer)-offset, "\r\nOK\r\n");
328*3deb3ec6SMatthias Ringwald     buffer[offset] = 0;
329*3deb3ec6SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
330*3deb3ec6SMatthias Ringwald }
331*3deb3ec6SMatthias Ringwald 
332*3deb3ec6SMatthias Ringwald static int hfp_ag_transfer_ag_indicators_status_cmd(uint16_t cid, hfp_ag_indicator_t indicator){
333*3deb3ec6SMatthias Ringwald     char buffer[20];
334*3deb3ec6SMatthias Ringwald     sprintf(buffer, "\r\n%s:%d,%d\r\n\r\nOK\r\n", HFP_TRANSFER_AG_INDICATOR_STATUS, indicator.index, indicator.status);
335*3deb3ec6SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
336*3deb3ec6SMatthias Ringwald }
337*3deb3ec6SMatthias Ringwald 
338*3deb3ec6SMatthias Ringwald static int hfp_ag_report_network_operator_name_cmd(uint16_t cid, hfp_network_opearator_t op){
339*3deb3ec6SMatthias Ringwald     char buffer[40];
340*3deb3ec6SMatthias Ringwald     if (strlen(op.name) == 0){
341*3deb3ec6SMatthias Ringwald         sprintf(buffer, "\r\n%s:%d,,\r\n\r\nOK\r\n", HFP_QUERY_OPERATOR_SELECTION, op.mode);
342*3deb3ec6SMatthias Ringwald     } else {
343*3deb3ec6SMatthias Ringwald         sprintf(buffer, "\r\n%s:%d,%d,%s\r\n\r\nOK\r\n", HFP_QUERY_OPERATOR_SELECTION, op.mode, op.format, op.name);
344*3deb3ec6SMatthias Ringwald     }
345*3deb3ec6SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
346*3deb3ec6SMatthias Ringwald }
347*3deb3ec6SMatthias Ringwald 
348*3deb3ec6SMatthias Ringwald 
349*3deb3ec6SMatthias Ringwald static int hfp_ag_cmd_suggest_codec(uint16_t cid, uint8_t codec){
350*3deb3ec6SMatthias Ringwald     char buffer[30];
351*3deb3ec6SMatthias Ringwald     sprintf(buffer, "\r\n%s:%d\r\n", HFP_CONFIRM_COMMON_CODEC, codec);
352*3deb3ec6SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
353*3deb3ec6SMatthias Ringwald }
354*3deb3ec6SMatthias Ringwald 
355*3deb3ec6SMatthias Ringwald static uint8_t hfp_ag_suggest_codec(hfp_connection_t *context){
356*3deb3ec6SMatthias Ringwald     int i,j;
357*3deb3ec6SMatthias Ringwald     uint8_t codec = 0;
358*3deb3ec6SMatthias Ringwald     for (i = 0; i < hfp_codecs_nr; i++){
359*3deb3ec6SMatthias Ringwald         for (j = 0; j < context->remote_codecs_nr; j++){
360*3deb3ec6SMatthias Ringwald             if (context->remote_codecs[j] == hfp_codecs[i]){
361*3deb3ec6SMatthias Ringwald                 codec = context->remote_codecs[j];
362*3deb3ec6SMatthias Ringwald                 continue;
363*3deb3ec6SMatthias Ringwald             }
364*3deb3ec6SMatthias Ringwald         }
365*3deb3ec6SMatthias Ringwald     }
366*3deb3ec6SMatthias Ringwald     return codec;
367*3deb3ec6SMatthias Ringwald }
368*3deb3ec6SMatthias Ringwald 
369*3deb3ec6SMatthias Ringwald 
370*3deb3ec6SMatthias Ringwald static int hfp_ag_run_for_context_service_level_connection(hfp_connection_t * context){
371*3deb3ec6SMatthias Ringwald     if (context->state >= HFP_CODECS_CONNECTION_ESTABLISHED) return 0;
372*3deb3ec6SMatthias Ringwald     //printf(" AG run for context_service_level_connection \n");
373*3deb3ec6SMatthias Ringwald     int done = 0;
374*3deb3ec6SMatthias Ringwald 
375*3deb3ec6SMatthias Ringwald     switch(context->command){
376*3deb3ec6SMatthias Ringwald         case HFP_CMD_SUPPORTED_FEATURES:
377*3deb3ec6SMatthias Ringwald             switch(context->state){
378*3deb3ec6SMatthias Ringwald                 case HFP_W4_EXCHANGE_SUPPORTED_FEATURES:
379*3deb3ec6SMatthias Ringwald                     hfp_ag_exchange_supported_features_cmd(context->rfcomm_cid);
380*3deb3ec6SMatthias Ringwald                     done = 1;
381*3deb3ec6SMatthias Ringwald                     if (has_codec_negotiation_feature(context)){
382*3deb3ec6SMatthias Ringwald                         context->state = HFP_W4_NOTIFY_ON_CODECS;
383*3deb3ec6SMatthias Ringwald                         break;
384*3deb3ec6SMatthias Ringwald                     }
385*3deb3ec6SMatthias Ringwald                     context->state = HFP_W4_RETRIEVE_INDICATORS;
386*3deb3ec6SMatthias Ringwald                     break;
387*3deb3ec6SMatthias Ringwald                 default:
388*3deb3ec6SMatthias Ringwald                     break;
389*3deb3ec6SMatthias Ringwald             }
390*3deb3ec6SMatthias Ringwald             break;
391*3deb3ec6SMatthias Ringwald         case HFP_CMD_AVAILABLE_CODECS:
392*3deb3ec6SMatthias Ringwald             switch(context->state){
393*3deb3ec6SMatthias Ringwald                 case HFP_W4_NOTIFY_ON_CODECS:
394*3deb3ec6SMatthias Ringwald                     hfp_ag_retrieve_codec_cmd(context->rfcomm_cid);
395*3deb3ec6SMatthias Ringwald                     done = 1;
396*3deb3ec6SMatthias Ringwald                     context->state = HFP_W4_RETRIEVE_INDICATORS;
397*3deb3ec6SMatthias Ringwald                     break;
398*3deb3ec6SMatthias Ringwald                 case HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED:
399*3deb3ec6SMatthias Ringwald                     context->suggested_codec = hfp_ag_suggest_codec(context);
400*3deb3ec6SMatthias Ringwald                     //printf("received BAC == new HF codecs, suggested codec %d\n", context->suggested_codec);
401*3deb3ec6SMatthias Ringwald                     hfp_ag_ok(context->rfcomm_cid);
402*3deb3ec6SMatthias Ringwald                     done = 1;
403*3deb3ec6SMatthias Ringwald                     break;
404*3deb3ec6SMatthias Ringwald 
405*3deb3ec6SMatthias Ringwald                 default:
406*3deb3ec6SMatthias Ringwald                     break;
407*3deb3ec6SMatthias Ringwald             }
408*3deb3ec6SMatthias Ringwald             break;
409*3deb3ec6SMatthias Ringwald         case HFP_CMD_INDICATOR:
410*3deb3ec6SMatthias Ringwald             switch(context->state){
411*3deb3ec6SMatthias Ringwald                 case HFP_W4_RETRIEVE_INDICATORS:
412*3deb3ec6SMatthias Ringwald                     if (context->retrieve_ag_indicators == 0) break;
413*3deb3ec6SMatthias Ringwald                     hfp_ag_retrieve_indicators_cmd(context->rfcomm_cid, context);
414*3deb3ec6SMatthias Ringwald                     done = 1;
415*3deb3ec6SMatthias Ringwald                     context->state = HFP_W4_RETRIEVE_INDICATORS_STATUS;
416*3deb3ec6SMatthias Ringwald                     break;
417*3deb3ec6SMatthias Ringwald                 case HFP_W4_RETRIEVE_INDICATORS_STATUS:
418*3deb3ec6SMatthias Ringwald                     if (context->retrieve_ag_indicators_status == 0) break;
419*3deb3ec6SMatthias Ringwald                     hfp_ag_retrieve_indicators_status_cmd(context->rfcomm_cid);
420*3deb3ec6SMatthias Ringwald                     done = 1;
421*3deb3ec6SMatthias Ringwald                     context->state = HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE;
422*3deb3ec6SMatthias Ringwald                     break;
423*3deb3ec6SMatthias Ringwald                 default:
424*3deb3ec6SMatthias Ringwald                     break;
425*3deb3ec6SMatthias Ringwald             }
426*3deb3ec6SMatthias Ringwald             break;
427*3deb3ec6SMatthias Ringwald         case HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE:
428*3deb3ec6SMatthias Ringwald             switch(context->state){
429*3deb3ec6SMatthias Ringwald                 case HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE:
430*3deb3ec6SMatthias Ringwald                     hfp_ag_set_indicator_status_update_cmd(context->rfcomm_cid, 1);
431*3deb3ec6SMatthias Ringwald                     done = 1;
432*3deb3ec6SMatthias Ringwald                     if (has_call_waiting_and_3way_calling_feature(context)){
433*3deb3ec6SMatthias Ringwald                         context->state = HFP_W4_RETRIEVE_CAN_HOLD_CALL;
434*3deb3ec6SMatthias Ringwald                         break;
435*3deb3ec6SMatthias Ringwald                     }
436*3deb3ec6SMatthias Ringwald                     if (has_hf_indicators_feature(context)){
437*3deb3ec6SMatthias Ringwald                         context->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS;
438*3deb3ec6SMatthias Ringwald                         break;
439*3deb3ec6SMatthias Ringwald                     }
440*3deb3ec6SMatthias Ringwald                     context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
441*3deb3ec6SMatthias Ringwald                     hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0);
442*3deb3ec6SMatthias Ringwald                     break;
443*3deb3ec6SMatthias Ringwald                 default:
444*3deb3ec6SMatthias Ringwald                     break;
445*3deb3ec6SMatthias Ringwald             }
446*3deb3ec6SMatthias Ringwald             break;
447*3deb3ec6SMatthias Ringwald         case HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES:
448*3deb3ec6SMatthias Ringwald             switch(context->state){
449*3deb3ec6SMatthias Ringwald                 case HFP_W4_RETRIEVE_CAN_HOLD_CALL:
450*3deb3ec6SMatthias Ringwald                     hfp_ag_retrieve_can_hold_call_cmd(context->rfcomm_cid);
451*3deb3ec6SMatthias Ringwald                     done = 1;
452*3deb3ec6SMatthias Ringwald                     if (has_hf_indicators_feature(context)){
453*3deb3ec6SMatthias Ringwald                         context->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS;
454*3deb3ec6SMatthias Ringwald                         break;
455*3deb3ec6SMatthias Ringwald                     }
456*3deb3ec6SMatthias Ringwald                     context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
457*3deb3ec6SMatthias Ringwald                     hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0);
458*3deb3ec6SMatthias Ringwald                     break;
459*3deb3ec6SMatthias Ringwald                 default:
460*3deb3ec6SMatthias Ringwald                     break;
461*3deb3ec6SMatthias Ringwald             }
462*3deb3ec6SMatthias Ringwald             break;
463*3deb3ec6SMatthias Ringwald         case HFP_CMD_GENERIC_STATUS_INDICATOR:
464*3deb3ec6SMatthias Ringwald             switch(context->state){
465*3deb3ec6SMatthias Ringwald                 case HFP_W4_LIST_GENERIC_STATUS_INDICATORS:
466*3deb3ec6SMatthias Ringwald                     if (context->list_generic_status_indicators == 0) break;
467*3deb3ec6SMatthias Ringwald                     hfp_ag_list_supported_generic_status_indicators_cmd(context->rfcomm_cid);
468*3deb3ec6SMatthias Ringwald                     done = 1;
469*3deb3ec6SMatthias Ringwald                     context->state = HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS;
470*3deb3ec6SMatthias Ringwald                     context->list_generic_status_indicators = 0;
471*3deb3ec6SMatthias Ringwald                     break;
472*3deb3ec6SMatthias Ringwald                 case HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS:
473*3deb3ec6SMatthias Ringwald                     if (context->retrieve_generic_status_indicators == 0) break;
474*3deb3ec6SMatthias Ringwald                     hfp_ag_retrieve_supported_generic_status_indicators_cmd(context->rfcomm_cid);
475*3deb3ec6SMatthias Ringwald                     done = 1;
476*3deb3ec6SMatthias Ringwald                     context->state = HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS;
477*3deb3ec6SMatthias Ringwald                     context->retrieve_generic_status_indicators = 0;
478*3deb3ec6SMatthias Ringwald                     break;
479*3deb3ec6SMatthias Ringwald                 case HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS:
480*3deb3ec6SMatthias Ringwald                     if (context->retrieve_generic_status_indicators_state == 0) break;
481*3deb3ec6SMatthias Ringwald                     hfp_ag_retrieve_initital_supported_generic_status_indicators_cmd(context->rfcomm_cid);
482*3deb3ec6SMatthias Ringwald                     done = 1;
483*3deb3ec6SMatthias Ringwald                     context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
484*3deb3ec6SMatthias Ringwald                     context->retrieve_generic_status_indicators_state = 0;
485*3deb3ec6SMatthias Ringwald                     hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0);
486*3deb3ec6SMatthias Ringwald                     break;
487*3deb3ec6SMatthias Ringwald                 default:
488*3deb3ec6SMatthias Ringwald                     break;
489*3deb3ec6SMatthias Ringwald             }
490*3deb3ec6SMatthias Ringwald             break;
491*3deb3ec6SMatthias Ringwald 
492*3deb3ec6SMatthias Ringwald         default:
493*3deb3ec6SMatthias Ringwald             break;
494*3deb3ec6SMatthias Ringwald     }
495*3deb3ec6SMatthias Ringwald     return done;
496*3deb3ec6SMatthias Ringwald }
497*3deb3ec6SMatthias Ringwald 
498*3deb3ec6SMatthias Ringwald static int hfp_ag_run_for_context_service_level_connection_queries(hfp_connection_t * context){
499*3deb3ec6SMatthias Ringwald     if (context->state != HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return 0;
500*3deb3ec6SMatthias Ringwald     int done = 0;
501*3deb3ec6SMatthias Ringwald     //printf("    SLC queries: ");
502*3deb3ec6SMatthias Ringwald 
503*3deb3ec6SMatthias Ringwald     switch(context->command){
504*3deb3ec6SMatthias Ringwald         case HFP_CMD_AVAILABLE_CODECS:
505*3deb3ec6SMatthias Ringwald             context->suggested_codec = hfp_ag_suggest_codec(context);
506*3deb3ec6SMatthias Ringwald             //printf("received BAC == new HF codecs, suggested codec %d\n", context->suggested_codec);
507*3deb3ec6SMatthias Ringwald             hfp_ag_ok(context->rfcomm_cid);
508*3deb3ec6SMatthias Ringwald             done = 1;
509*3deb3ec6SMatthias Ringwald             break;
510*3deb3ec6SMatthias Ringwald 
511*3deb3ec6SMatthias Ringwald         case HFP_CMD_QUERY_OPERATOR_SELECTION:
512*3deb3ec6SMatthias Ringwald             if (context->operator_name_format == 1){
513*3deb3ec6SMatthias Ringwald                 if (context->network_operator.format != 0){
514*3deb3ec6SMatthias Ringwald                     hfp_ag_error(context->rfcomm_cid);
515*3deb3ec6SMatthias Ringwald                     done = 1;
516*3deb3ec6SMatthias Ringwald                     break;
517*3deb3ec6SMatthias Ringwald                 }
518*3deb3ec6SMatthias Ringwald                 hfp_ag_ok(context->rfcomm_cid);
519*3deb3ec6SMatthias Ringwald                 done = 1;
520*3deb3ec6SMatthias Ringwald                 context->operator_name_format = 0;
521*3deb3ec6SMatthias Ringwald                 break;
522*3deb3ec6SMatthias Ringwald             }
523*3deb3ec6SMatthias Ringwald             if (context->operator_name == 1){
524*3deb3ec6SMatthias Ringwald                 hfp_ag_report_network_operator_name_cmd(context->rfcomm_cid, context->network_operator);
525*3deb3ec6SMatthias Ringwald                 context->operator_name = 0;
526*3deb3ec6SMatthias Ringwald                 done = 1;
527*3deb3ec6SMatthias Ringwald                 break;
528*3deb3ec6SMatthias Ringwald             }
529*3deb3ec6SMatthias Ringwald             break;
530*3deb3ec6SMatthias Ringwald         case HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE:{
531*3deb3ec6SMatthias Ringwald                 int i;
532*3deb3ec6SMatthias Ringwald                 for (i = 0; i < context->ag_indicators_nr; i++){
533*3deb3ec6SMatthias Ringwald                     if (context->ag_indicators[i].enabled == 0) continue;
534*3deb3ec6SMatthias Ringwald                     if (context->ag_indicators[i].status_changed == 0) continue;
535*3deb3ec6SMatthias Ringwald                     hfp_ag_transfer_ag_indicators_status_cmd(context->rfcomm_cid, context->ag_indicators[i]);
536*3deb3ec6SMatthias Ringwald                     done = 1;
537*3deb3ec6SMatthias Ringwald                     context->ag_indicators[i].status_changed = 0;
538*3deb3ec6SMatthias Ringwald                     return done;
539*3deb3ec6SMatthias Ringwald                 }
540*3deb3ec6SMatthias Ringwald                 break;
541*3deb3ec6SMatthias Ringwald             }
542*3deb3ec6SMatthias Ringwald         case HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP:
543*3deb3ec6SMatthias Ringwald             if (context->hf_trigger_codec_connection_setup){ // received BCC
544*3deb3ec6SMatthias Ringwald                 //printf(" received BCC \n");
545*3deb3ec6SMatthias Ringwald                 context->hf_trigger_codec_connection_setup = 0;
546*3deb3ec6SMatthias Ringwald                 context->ag_trigger_codec_connection_setup = 1;
547*3deb3ec6SMatthias Ringwald                 context->state = HFP_SLE_W2_EXCHANGE_COMMON_CODEC;
548*3deb3ec6SMatthias Ringwald                 hfp_ag_ok(context->rfcomm_cid);
549*3deb3ec6SMatthias Ringwald                 done = 1;
550*3deb3ec6SMatthias Ringwald                 return done;
551*3deb3ec6SMatthias Ringwald             }
552*3deb3ec6SMatthias Ringwald 
553*3deb3ec6SMatthias Ringwald             if (context->ag_trigger_codec_connection_setup){ // received BCS
554*3deb3ec6SMatthias Ringwald                 //printf(" send BCS \n");
555*3deb3ec6SMatthias Ringwald                 context->ag_trigger_codec_connection_setup = 0;
556*3deb3ec6SMatthias Ringwald                 context->state = HFP_SLE_W4_EXCHANGE_COMMON_CODEC;
557*3deb3ec6SMatthias Ringwald                 context->suggested_codec = hfp_ag_suggest_codec(context);
558*3deb3ec6SMatthias Ringwald                 hfp_ag_cmd_suggest_codec(context->rfcomm_cid, context->suggested_codec);
559*3deb3ec6SMatthias Ringwald                 done = 1;
560*3deb3ec6SMatthias Ringwald                 return done;
561*3deb3ec6SMatthias Ringwald             }
562*3deb3ec6SMatthias Ringwald             break;
563*3deb3ec6SMatthias Ringwald         case HFP_CMD_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR:
564*3deb3ec6SMatthias Ringwald             if (context->extended_audio_gateway_error){
565*3deb3ec6SMatthias Ringwald                 hfp_ag_report_extended_audio_gateway_error(context->rfcomm_cid, context->extended_audio_gateway_error);
566*3deb3ec6SMatthias Ringwald                 context->extended_audio_gateway_error = 0;
567*3deb3ec6SMatthias Ringwald                 done = 1;
568*3deb3ec6SMatthias Ringwald                 break;
569*3deb3ec6SMatthias Ringwald             }
570*3deb3ec6SMatthias Ringwald         case HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE:
571*3deb3ec6SMatthias Ringwald             printf("TODO\n");
572*3deb3ec6SMatthias Ringwald             break;
573*3deb3ec6SMatthias Ringwald         default:
574*3deb3ec6SMatthias Ringwald             break;
575*3deb3ec6SMatthias Ringwald     }
576*3deb3ec6SMatthias Ringwald     return done;
577*3deb3ec6SMatthias Ringwald }
578*3deb3ec6SMatthias Ringwald 
579*3deb3ec6SMatthias Ringwald 
580*3deb3ec6SMatthias Ringwald static int hfp_ag_run_for_context_codecs_connection(hfp_connection_t * context){
581*3deb3ec6SMatthias Ringwald     if (context->state <= HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED ||
582*3deb3ec6SMatthias Ringwald         context->state > HFP_CODECS_CONNECTION_ESTABLISHED) return 0;
583*3deb3ec6SMatthias Ringwald 
584*3deb3ec6SMatthias Ringwald     int done = 0;
585*3deb3ec6SMatthias Ringwald     //printf(" AG run for context_codecs_connection: ");
586*3deb3ec6SMatthias Ringwald     switch (context->state){
587*3deb3ec6SMatthias Ringwald         case HFP_SLE_W2_EXCHANGE_COMMON_CODEC:
588*3deb3ec6SMatthias Ringwald             if (context->ag_trigger_codec_connection_setup){ // received BCS
589*3deb3ec6SMatthias Ringwald                 //printf(" send BCS \n");
590*3deb3ec6SMatthias Ringwald                 context->ag_trigger_codec_connection_setup = 0;
591*3deb3ec6SMatthias Ringwald                 context->state = HFP_SLE_W4_EXCHANGE_COMMON_CODEC;
592*3deb3ec6SMatthias Ringwald                 context->suggested_codec = hfp_ag_suggest_codec(context);
593*3deb3ec6SMatthias Ringwald                 hfp_ag_cmd_suggest_codec(context->rfcomm_cid, context->suggested_codec);
594*3deb3ec6SMatthias Ringwald                 done = 1;
595*3deb3ec6SMatthias Ringwald                 break;
596*3deb3ec6SMatthias Ringwald             }
597*3deb3ec6SMatthias Ringwald             break;
598*3deb3ec6SMatthias Ringwald         case HFP_SLE_W4_EXCHANGE_COMMON_CODEC:
599*3deb3ec6SMatthias Ringwald             switch(context->command){
600*3deb3ec6SMatthias Ringwald                 case HFP_CMD_AVAILABLE_CODECS:
601*3deb3ec6SMatthias Ringwald                     if (context->notify_ag_on_new_codecs){ // received BAC
602*3deb3ec6SMatthias Ringwald                         //printf(" received BAC\n");
603*3deb3ec6SMatthias Ringwald                         context->notify_ag_on_new_codecs = 0;
604*3deb3ec6SMatthias Ringwald                         if (context->suggested_codec != hfp_ag_suggest_codec(context)){
605*3deb3ec6SMatthias Ringwald                             context->suggested_codec = hfp_ag_suggest_codec(context);
606*3deb3ec6SMatthias Ringwald                             context->state = HFP_SLE_W2_EXCHANGE_COMMON_CODEC;
607*3deb3ec6SMatthias Ringwald                             context->ag_trigger_codec_connection_setup = 1;
608*3deb3ec6SMatthias Ringwald                         }
609*3deb3ec6SMatthias Ringwald                         hfp_ag_ok(context->rfcomm_cid);
610*3deb3ec6SMatthias Ringwald                         done = 1;
611*3deb3ec6SMatthias Ringwald                         break;
612*3deb3ec6SMatthias Ringwald                     }
613*3deb3ec6SMatthias Ringwald                     break;
614*3deb3ec6SMatthias Ringwald                 case HFP_CMD_HF_CONFIRMED_CODEC:
615*3deb3ec6SMatthias Ringwald                     //printf(" received AT+BCS\n");
616*3deb3ec6SMatthias Ringwald                     if (context->codec_confirmed != context->suggested_codec){
617*3deb3ec6SMatthias Ringwald                         context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
618*3deb3ec6SMatthias Ringwald                         hfp_ag_error(context->rfcomm_cid);
619*3deb3ec6SMatthias Ringwald                         done = 1;
620*3deb3ec6SMatthias Ringwald                         break;
621*3deb3ec6SMatthias Ringwald                     }
622*3deb3ec6SMatthias Ringwald                     context->negotiated_codec = context->codec_confirmed;
623*3deb3ec6SMatthias Ringwald                     context->state = HFP_CODECS_CONNECTION_ESTABLISHED;
624*3deb3ec6SMatthias Ringwald                     hfp_emit_event(hfp_callback, HFP_SUBEVENT_CODECS_CONNECTION_COMPLETE, 0);
625*3deb3ec6SMatthias Ringwald                     hfp_ag_ok(context->rfcomm_cid);
626*3deb3ec6SMatthias Ringwald                     done = 1;
627*3deb3ec6SMatthias Ringwald                     break;
628*3deb3ec6SMatthias Ringwald                 default:
629*3deb3ec6SMatthias Ringwald                     break;
630*3deb3ec6SMatthias Ringwald             }
631*3deb3ec6SMatthias Ringwald             break;
632*3deb3ec6SMatthias Ringwald 
633*3deb3ec6SMatthias Ringwald         case HFP_CODECS_CONNECTION_ESTABLISHED:
634*3deb3ec6SMatthias Ringwald             switch(context->command){
635*3deb3ec6SMatthias Ringwald                 case HFP_CMD_AVAILABLE_CODECS:
636*3deb3ec6SMatthias Ringwald 
637*3deb3ec6SMatthias Ringwald                     if (context->notify_ag_on_new_codecs){ // received BAC
638*3deb3ec6SMatthias Ringwald                         context->notify_ag_on_new_codecs = 0;
639*3deb3ec6SMatthias Ringwald                         if (context->suggested_codec != hfp_ag_suggest_codec(context)){
640*3deb3ec6SMatthias Ringwald                             context->suggested_codec = hfp_ag_suggest_codec(context);
641*3deb3ec6SMatthias Ringwald                             context->state = HFP_SLE_W4_EXCHANGE_COMMON_CODEC;
642*3deb3ec6SMatthias Ringwald                         }
643*3deb3ec6SMatthias Ringwald                         hfp_ag_ok(context->rfcomm_cid);
644*3deb3ec6SMatthias Ringwald                         done = 1;
645*3deb3ec6SMatthias Ringwald                         break;
646*3deb3ec6SMatthias Ringwald                     }
647*3deb3ec6SMatthias Ringwald                     break;
648*3deb3ec6SMatthias Ringwald                 case HFP_CMD_AG_SUGGESTED_CODEC:
649*3deb3ec6SMatthias Ringwald                     if (context->ag_trigger_codec_connection_setup){
650*3deb3ec6SMatthias Ringwald                         context->ag_trigger_codec_connection_setup = 0;
651*3deb3ec6SMatthias Ringwald                         if (context->negotiated_codec != hfp_ag_suggest_codec(context)){
652*3deb3ec6SMatthias Ringwald                             context->state = HFP_SLE_W4_EXCHANGE_COMMON_CODEC;
653*3deb3ec6SMatthias Ringwald                             context->suggested_codec = hfp_ag_suggest_codec(context);
654*3deb3ec6SMatthias Ringwald                             hfp_ag_cmd_suggest_codec(context->rfcomm_cid, context->suggested_codec);
655*3deb3ec6SMatthias Ringwald                             done = 1;
656*3deb3ec6SMatthias Ringwald                             break;
657*3deb3ec6SMatthias Ringwald                         }
658*3deb3ec6SMatthias Ringwald                     }
659*3deb3ec6SMatthias Ringwald                     break;
660*3deb3ec6SMatthias Ringwald                 default:
661*3deb3ec6SMatthias Ringwald                     break;
662*3deb3ec6SMatthias Ringwald             }
663*3deb3ec6SMatthias Ringwald 
664*3deb3ec6SMatthias Ringwald         default:
665*3deb3ec6SMatthias Ringwald             break;
666*3deb3ec6SMatthias Ringwald     }
667*3deb3ec6SMatthias Ringwald     return done;
668*3deb3ec6SMatthias Ringwald }
669*3deb3ec6SMatthias Ringwald 
670*3deb3ec6SMatthias Ringwald static void hfp_run_for_context(hfp_connection_t *context){
671*3deb3ec6SMatthias Ringwald     if (!context) return;
672*3deb3ec6SMatthias Ringwald 
673*3deb3ec6SMatthias Ringwald     if (!rfcomm_can_send_packet_now(context->rfcomm_cid)) return;
674*3deb3ec6SMatthias Ringwald 
675*3deb3ec6SMatthias Ringwald     // printf("AG hfp_run_for_context 1 state %d, command %d\n", context->state, context->command);
676*3deb3ec6SMatthias Ringwald     if (context->send_ok){
677*3deb3ec6SMatthias Ringwald         hfp_ag_ok(context->rfcomm_cid);
678*3deb3ec6SMatthias Ringwald         context->send_ok = 0;
679*3deb3ec6SMatthias Ringwald         context->command = HFP_CMD_NONE;
680*3deb3ec6SMatthias Ringwald         return;
681*3deb3ec6SMatthias Ringwald     }
682*3deb3ec6SMatthias Ringwald 
683*3deb3ec6SMatthias Ringwald     if (context->send_error){
684*3deb3ec6SMatthias Ringwald         hfp_ag_error(context->rfcomm_cid);
685*3deb3ec6SMatthias Ringwald         context->send_error = 0;
686*3deb3ec6SMatthias Ringwald         context->command = HFP_CMD_NONE;
687*3deb3ec6SMatthias Ringwald         return;
688*3deb3ec6SMatthias Ringwald     }
689*3deb3ec6SMatthias Ringwald 
690*3deb3ec6SMatthias Ringwald     int done = hfp_ag_run_for_context_service_level_connection(context);
691*3deb3ec6SMatthias Ringwald 
692*3deb3ec6SMatthias Ringwald     if (rfcomm_can_send_packet_now(context->rfcomm_cid) && !done){
693*3deb3ec6SMatthias Ringwald         done = hfp_ag_run_for_context_service_level_connection_queries(context);
694*3deb3ec6SMatthias Ringwald         if (rfcomm_can_send_packet_now(context->rfcomm_cid) && !done){
695*3deb3ec6SMatthias Ringwald             done = hfp_ag_run_for_context_codecs_connection(context);
696*3deb3ec6SMatthias Ringwald         }
697*3deb3ec6SMatthias Ringwald     }
698*3deb3ec6SMatthias Ringwald 
699*3deb3ec6SMatthias Ringwald 
700*3deb3ec6SMatthias Ringwald     if (context->command == HFP_CMD_NONE && !done){
701*3deb3ec6SMatthias Ringwald         switch(context->state){
702*3deb3ec6SMatthias Ringwald             case HFP_W2_DISCONNECT_RFCOMM:
703*3deb3ec6SMatthias Ringwald                 context->state = HFP_W4_RFCOMM_DISCONNECTED;
704*3deb3ec6SMatthias Ringwald                 rfcomm_disconnect_internal(context->rfcomm_cid);
705*3deb3ec6SMatthias Ringwald                 break;
706*3deb3ec6SMatthias Ringwald             default:
707*3deb3ec6SMatthias Ringwald                 break;
708*3deb3ec6SMatthias Ringwald         }
709*3deb3ec6SMatthias Ringwald     }
710*3deb3ec6SMatthias Ringwald     if (done){
711*3deb3ec6SMatthias Ringwald         context->command = HFP_CMD_NONE;
712*3deb3ec6SMatthias Ringwald     }
713*3deb3ec6SMatthias Ringwald }
714*3deb3ec6SMatthias Ringwald 
715*3deb3ec6SMatthias Ringwald static void hfp_handle_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
716*3deb3ec6SMatthias Ringwald     hfp_connection_t * context = get_hfp_connection_context_for_rfcomm_cid(channel);
717*3deb3ec6SMatthias Ringwald     if (!context) return;
718*3deb3ec6SMatthias Ringwald 
719*3deb3ec6SMatthias Ringwald     if (context->state == HFP_EXCHANGE_SUPPORTED_FEATURES){
720*3deb3ec6SMatthias Ringwald         context->state = HFP_W4_EXCHANGE_SUPPORTED_FEATURES;
721*3deb3ec6SMatthias Ringwald     }
722*3deb3ec6SMatthias Ringwald 
723*3deb3ec6SMatthias Ringwald     packet[size] = 0;
724*3deb3ec6SMatthias Ringwald     int pos;
725*3deb3ec6SMatthias Ringwald     for (pos = 0; pos < size ; pos++){
726*3deb3ec6SMatthias Ringwald         hfp_parse(context, packet[pos]);
727*3deb3ec6SMatthias Ringwald 
728*3deb3ec6SMatthias Ringwald         // trigger next action after CMD received
729*3deb3ec6SMatthias Ringwald         if (context->command == HFP_CMD_NONE) continue;
730*3deb3ec6SMatthias Ringwald         //hfp_run_for_context(context);
731*3deb3ec6SMatthias Ringwald     }
732*3deb3ec6SMatthias Ringwald }
733*3deb3ec6SMatthias Ringwald 
734*3deb3ec6SMatthias Ringwald static void hfp_run(){
735*3deb3ec6SMatthias Ringwald     linked_list_iterator_t it;
736*3deb3ec6SMatthias Ringwald     linked_list_iterator_init(&it, hfp_get_connections());
737*3deb3ec6SMatthias Ringwald     while (linked_list_iterator_has_next(&it)){
738*3deb3ec6SMatthias Ringwald         hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it);
739*3deb3ec6SMatthias Ringwald         hfp_run_for_context(connection);
740*3deb3ec6SMatthias Ringwald     }
741*3deb3ec6SMatthias Ringwald }
742*3deb3ec6SMatthias Ringwald 
743*3deb3ec6SMatthias Ringwald static void packet_handler(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
744*3deb3ec6SMatthias Ringwald     switch (packet_type){
745*3deb3ec6SMatthias Ringwald         case RFCOMM_DATA_PACKET:
746*3deb3ec6SMatthias Ringwald             hfp_handle_rfcomm_event(packet_type, channel, packet, size);
747*3deb3ec6SMatthias Ringwald             break;
748*3deb3ec6SMatthias Ringwald         case HCI_EVENT_PACKET:
749*3deb3ec6SMatthias Ringwald             hfp_handle_hci_event(hfp_callback, packet_type, packet, size);
750*3deb3ec6SMatthias Ringwald             return;
751*3deb3ec6SMatthias Ringwald         default:
752*3deb3ec6SMatthias Ringwald             break;
753*3deb3ec6SMatthias Ringwald     }
754*3deb3ec6SMatthias Ringwald 
755*3deb3ec6SMatthias Ringwald     hfp_run();
756*3deb3ec6SMatthias Ringwald }
757*3deb3ec6SMatthias Ringwald 
758*3deb3ec6SMatthias Ringwald void hfp_ag_init(uint16_t rfcomm_channel_nr, uint32_t supported_features,
759*3deb3ec6SMatthias Ringwald     uint8_t * codecs, int codecs_nr,
760*3deb3ec6SMatthias Ringwald     hfp_ag_indicator_t * ag_indicators, int ag_indicators_nr,
761*3deb3ec6SMatthias Ringwald     hfp_generic_status_indicator_t * hf_indicators, int hf_indicators_nr,
762*3deb3ec6SMatthias Ringwald     const char *call_hold_services[], int call_hold_services_nr){
763*3deb3ec6SMatthias Ringwald     if (codecs_nr > HFP_MAX_NUM_CODECS){
764*3deb3ec6SMatthias Ringwald         log_error("hfp_init: codecs_nr (%d) > HFP_MAX_NUM_CODECS (%d)", codecs_nr, HFP_MAX_NUM_CODECS);
765*3deb3ec6SMatthias Ringwald         return;
766*3deb3ec6SMatthias Ringwald     }
767*3deb3ec6SMatthias Ringwald     rfcomm_register_packet_handler(packet_handler);
768*3deb3ec6SMatthias Ringwald     hfp_init(rfcomm_channel_nr);
769*3deb3ec6SMatthias Ringwald 
770*3deb3ec6SMatthias Ringwald     hfp_supported_features = supported_features;
771*3deb3ec6SMatthias Ringwald     hfp_codecs_nr = codecs_nr;
772*3deb3ec6SMatthias Ringwald 
773*3deb3ec6SMatthias Ringwald     int i;
774*3deb3ec6SMatthias Ringwald     for (i=0; i<codecs_nr; i++){
775*3deb3ec6SMatthias Ringwald         hfp_codecs[i] = codecs[i];
776*3deb3ec6SMatthias Ringwald     }
777*3deb3ec6SMatthias Ringwald 
778*3deb3ec6SMatthias Ringwald     hfp_ag_indicators_nr = ag_indicators_nr;
779*3deb3ec6SMatthias Ringwald     memcpy(hfp_ag_indicators, ag_indicators, ag_indicators_nr * sizeof(hfp_ag_indicator_t));
780*3deb3ec6SMatthias Ringwald     for (i=0; i<hfp_ag_indicators_nr; i++){
781*3deb3ec6SMatthias Ringwald         printf("ag ind %s\n", hfp_ag_indicators[i].name);
782*3deb3ec6SMatthias Ringwald     }
783*3deb3ec6SMatthias Ringwald 
784*3deb3ec6SMatthias Ringwald     set_hfp_generic_status_indicators(hf_indicators, hf_indicators_nr);
785*3deb3ec6SMatthias Ringwald 
786*3deb3ec6SMatthias Ringwald     hfp_ag_call_hold_services_nr = call_hold_services_nr;
787*3deb3ec6SMatthias Ringwald     memcpy(hfp_ag_call_hold_services, call_hold_services, call_hold_services_nr * sizeof(char *));
788*3deb3ec6SMatthias Ringwald }
789*3deb3ec6SMatthias Ringwald 
790*3deb3ec6SMatthias Ringwald void hfp_ag_establish_service_level_connection(bd_addr_t bd_addr){
791*3deb3ec6SMatthias Ringwald     hfp_establish_service_level_connection(bd_addr, SDP_Handsfree);
792*3deb3ec6SMatthias Ringwald }
793*3deb3ec6SMatthias Ringwald 
794*3deb3ec6SMatthias Ringwald void hfp_ag_release_service_level_connection(bd_addr_t bd_addr){
795*3deb3ec6SMatthias Ringwald     hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
796*3deb3ec6SMatthias Ringwald     hfp_release_service_level_connection(connection);
797*3deb3ec6SMatthias Ringwald     hfp_run_for_context(connection);
798*3deb3ec6SMatthias Ringwald }
799*3deb3ec6SMatthias Ringwald 
800*3deb3ec6SMatthias Ringwald void hfp_ag_report_extended_audio_gateway_error_result_code(bd_addr_t bd_addr, hfp_cme_error_t error){
801*3deb3ec6SMatthias Ringwald     hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
802*3deb3ec6SMatthias Ringwald     if (!connection){
803*3deb3ec6SMatthias Ringwald         log_error("HFP HF: connection doesn't exist.");
804*3deb3ec6SMatthias Ringwald         return;
805*3deb3ec6SMatthias Ringwald     }
806*3deb3ec6SMatthias Ringwald     connection->extended_audio_gateway_error = 0;
807*3deb3ec6SMatthias Ringwald     if (!connection->enable_extended_audio_gateway_error_report){
808*3deb3ec6SMatthias Ringwald         return;
809*3deb3ec6SMatthias Ringwald     }
810*3deb3ec6SMatthias Ringwald     connection->extended_audio_gateway_error = error;
811*3deb3ec6SMatthias Ringwald     hfp_run_for_context(connection);
812*3deb3ec6SMatthias Ringwald }
813*3deb3ec6SMatthias Ringwald 
814*3deb3ec6SMatthias Ringwald void hfp_ag_transfer_call_status(bd_addr_t bd_addr, hfp_call_status_t status){
815*3deb3ec6SMatthias Ringwald     hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
816*3deb3ec6SMatthias Ringwald     if (!connection){
817*3deb3ec6SMatthias Ringwald         log_error("HFP HF: connection doesn't exist.");
818*3deb3ec6SMatthias Ringwald         return;
819*3deb3ec6SMatthias Ringwald     }
820*3deb3ec6SMatthias Ringwald     if (!connection->enable_status_update_for_ag_indicators) return;
821*3deb3ec6SMatthias Ringwald     hfp_ag_update_indicator_status(connection, (char *)"call", status);
822*3deb3ec6SMatthias Ringwald }
823*3deb3ec6SMatthias Ringwald 
824*3deb3ec6SMatthias Ringwald void hfp_ag_transfer_callsetup_status(bd_addr_t bd_addr, hfp_callsetup_status_t status){
825*3deb3ec6SMatthias Ringwald     hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
826*3deb3ec6SMatthias Ringwald     if (!connection){
827*3deb3ec6SMatthias Ringwald         log_error("HFP HF: connection doesn't exist.");
828*3deb3ec6SMatthias Ringwald         return;
829*3deb3ec6SMatthias Ringwald     }
830*3deb3ec6SMatthias Ringwald     if (!connection->enable_status_update_for_ag_indicators) return;
831*3deb3ec6SMatthias Ringwald     hfp_ag_update_indicator_status(connection, (char *)"callsetup", status);
832*3deb3ec6SMatthias Ringwald }
833*3deb3ec6SMatthias Ringwald 
834*3deb3ec6SMatthias Ringwald void hfp_ag_transfer_callheld_status(bd_addr_t bd_addr, hfp_callheld_status_t status){
835*3deb3ec6SMatthias Ringwald     hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
836*3deb3ec6SMatthias Ringwald     if (!connection){
837*3deb3ec6SMatthias Ringwald         log_error("HFP AG: connection doesn't exist.");
838*3deb3ec6SMatthias Ringwald         return;
839*3deb3ec6SMatthias Ringwald     }
840*3deb3ec6SMatthias Ringwald     if (!connection->enable_status_update_for_ag_indicators) return;
841*3deb3ec6SMatthias Ringwald     hfp_ag_update_indicator_status(connection, (char *)"callheld", status);
842*3deb3ec6SMatthias Ringwald     hfp_run_for_context(connection);
843*3deb3ec6SMatthias Ringwald }
844*3deb3ec6SMatthias Ringwald 
845*3deb3ec6SMatthias Ringwald #if 0
846*3deb3ec6SMatthias Ringwald static void hfp_ag_codec_connection_setup(hfp_connection_t * connection){
847*3deb3ec6SMatthias Ringwald     if (!connection){
848*3deb3ec6SMatthias Ringwald         log_error("HFP AG: connection doesn't exist.");
849*3deb3ec6SMatthias Ringwald         return;
850*3deb3ec6SMatthias Ringwald     }
851*3deb3ec6SMatthias Ringwald     // TODO:
852*3deb3ec6SMatthias Ringwald     hfp_run_for_context(connection);
853*3deb3ec6SMatthias Ringwald }
854*3deb3ec6SMatthias Ringwald #endif
855*3deb3ec6SMatthias Ringwald 
856*3deb3ec6SMatthias Ringwald /**
857*3deb3ec6SMatthias Ringwald  * @param handle
858*3deb3ec6SMatthias Ringwald  * @param transmit_bandwidth 8000(64kbps)
859*3deb3ec6SMatthias Ringwald  * @param receive_bandwidth  8000(64kbps)
860*3deb3ec6SMatthias Ringwald  * @param max_latency        >= 7ms for eSCO, 0xFFFF do not care
861*3deb3ec6SMatthias Ringwald  * @param voice_settings     e.g. CVSD, Input Coding: Linear, Input Data Format: 2’s complement, data 16bit: 00011000000 == 0x60
862*3deb3ec6SMatthias Ringwald  * @param retransmission_effort  e.g. 0xFF do not care
863*3deb3ec6SMatthias Ringwald  * @param packet_type        at least EV3 for eSCO
864*3deb3ec6SMatthias Ringwald 
865*3deb3ec6SMatthias Ringwald  hci_send_cmd(&hci_setup_synchronous_connection, rfcomm_handle, 8000, 8000, 0xFFFF, 0x0060, 0xFF, 0x003F);
866*3deb3ec6SMatthias Ringwald 
867*3deb3ec6SMatthias Ringwald  */
868*3deb3ec6SMatthias Ringwald 
869*3deb3ec6SMatthias Ringwald #if 0
870*3deb3ec6SMatthias Ringwald static void hfp_ag_negotiate_codecs(bd_addr_t bd_addr){
871*3deb3ec6SMatthias Ringwald     hfp_ag_establish_service_level_connection(bd_addr);
872*3deb3ec6SMatthias Ringwald     hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
873*3deb3ec6SMatthias Ringwald     if (!has_codec_negotiation_feature(connection)) return;
874*3deb3ec6SMatthias Ringwald     if (connection->remote_codecs_nr == 0) return;
875*3deb3ec6SMatthias Ringwald 
876*3deb3ec6SMatthias Ringwald     if (connection->state >= HFP_W2_DISCONNECT_SCO) return;
877*3deb3ec6SMatthias Ringwald 
878*3deb3ec6SMatthias Ringwald     if (connection->state != HFP_SLE_W2_EXCHANGE_COMMON_CODEC &&
879*3deb3ec6SMatthias Ringwald         connection->state != HFP_SLE_W4_EXCHANGE_COMMON_CODEC){
880*3deb3ec6SMatthias Ringwald         connection->ag_trigger_codec_connection_setup = 1;
881*3deb3ec6SMatthias Ringwald     }
882*3deb3ec6SMatthias Ringwald 
883*3deb3ec6SMatthias Ringwald     hfp_run_for_context(connection);
884*3deb3ec6SMatthias Ringwald }
885*3deb3ec6SMatthias Ringwald #endif
886*3deb3ec6SMatthias Ringwald 
887*3deb3ec6SMatthias Ringwald void hfp_ag_establish_audio_connection(bd_addr_t bd_addr){
888*3deb3ec6SMatthias Ringwald     hfp_ag_establish_service_level_connection(bd_addr);
889*3deb3ec6SMatthias Ringwald     hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
890*3deb3ec6SMatthias Ringwald     if (!has_codec_negotiation_feature(connection)) return;
891*3deb3ec6SMatthias Ringwald     connection->establish_audio_connection = 0;
892*3deb3ec6SMatthias Ringwald     if (connection->state == HFP_AUDIO_CONNECTION_ESTABLISHED) return;
893*3deb3ec6SMatthias Ringwald     if (connection->state >= HFP_W2_DISCONNECT_SCO) return;
894*3deb3ec6SMatthias Ringwald 
895*3deb3ec6SMatthias Ringwald     connection->establish_audio_connection = 1;
896*3deb3ec6SMatthias Ringwald     if (connection->state < HFP_SLE_W4_EXCHANGE_COMMON_CODEC){
897*3deb3ec6SMatthias Ringwald         connection->ag_trigger_codec_connection_setup = 1;
898*3deb3ec6SMatthias Ringwald     }
899*3deb3ec6SMatthias Ringwald     hfp_run_for_context(connection);
900*3deb3ec6SMatthias Ringwald }
901*3deb3ec6SMatthias Ringwald 
902*3deb3ec6SMatthias Ringwald void hfp_ag_release_audio_connection(bd_addr_t bd_addr){
903*3deb3ec6SMatthias Ringwald     hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
904*3deb3ec6SMatthias Ringwald     hfp_release_audio_connection(connection);
905*3deb3ec6SMatthias Ringwald     hfp_run_for_context(connection);
906*3deb3ec6SMatthias Ringwald }
907