xref: /btstack/src/classic/hfp_ag.c (revision ffbf82013e3f511bf1169fb051dfccdcd45664b0)
13deb3ec6SMatthias Ringwald /*
23deb3ec6SMatthias Ringwald  * Copyright (C) 2014 BlueKitchen GmbH
33deb3ec6SMatthias Ringwald  *
43deb3ec6SMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
53deb3ec6SMatthias Ringwald  * modification, are permitted provided that the following conditions
63deb3ec6SMatthias Ringwald  * are met:
73deb3ec6SMatthias Ringwald  *
83deb3ec6SMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
93deb3ec6SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
103deb3ec6SMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
113deb3ec6SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
123deb3ec6SMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
133deb3ec6SMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
143deb3ec6SMatthias Ringwald  *    contributors may be used to endorse or promote products derived
153deb3ec6SMatthias Ringwald  *    from this software without specific prior written permission.
163deb3ec6SMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
173deb3ec6SMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
183deb3ec6SMatthias Ringwald  *    monetary gain.
193deb3ec6SMatthias Ringwald  *
203deb3ec6SMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
213deb3ec6SMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
223deb3ec6SMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
233deb3ec6SMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
243deb3ec6SMatthias Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
253deb3ec6SMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
263deb3ec6SMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
273deb3ec6SMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
283deb3ec6SMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
293deb3ec6SMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
303deb3ec6SMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
313deb3ec6SMatthias Ringwald  * SUCH DAMAGE.
323deb3ec6SMatthias Ringwald  *
333deb3ec6SMatthias Ringwald  * Please inquire about commercial licensing options at
343deb3ec6SMatthias Ringwald  * [email protected]
353deb3ec6SMatthias Ringwald  *
363deb3ec6SMatthias Ringwald  */
373deb3ec6SMatthias Ringwald 
383deb3ec6SMatthias Ringwald // *****************************************************************************
393deb3ec6SMatthias Ringwald //
403deb3ec6SMatthias Ringwald // Minimal setup for HFP Audio Gateway (AG) unit (!! UNDER DEVELOPMENT !!)
413deb3ec6SMatthias Ringwald //
423deb3ec6SMatthias Ringwald // *****************************************************************************
433deb3ec6SMatthias Ringwald 
443deb3ec6SMatthias Ringwald #include "btstack-config.h"
453deb3ec6SMatthias Ringwald 
463deb3ec6SMatthias Ringwald #include <stdint.h>
473deb3ec6SMatthias Ringwald #include <stdio.h>
483deb3ec6SMatthias Ringwald #include <stdlib.h>
493deb3ec6SMatthias Ringwald #include <string.h>
503deb3ec6SMatthias Ringwald 
513deb3ec6SMatthias Ringwald #include "hci_cmds.h"
523deb3ec6SMatthias Ringwald #include "run_loop.h"
533deb3ec6SMatthias Ringwald 
543deb3ec6SMatthias Ringwald #include "hci.h"
553deb3ec6SMatthias Ringwald #include "btstack_memory.h"
563deb3ec6SMatthias Ringwald #include "hci_dump.h"
573deb3ec6SMatthias Ringwald #include "l2cap.h"
583edc84c5SMatthias Ringwald #include "classic/sdp_query_rfcomm.h"
593edc84c5SMatthias Ringwald #include "classic/sdp.h"
603deb3ec6SMatthias Ringwald #include "debug.h"
613edc84c5SMatthias Ringwald #include "classic/hfp.h"
623edc84c5SMatthias Ringwald #include "classic/hfp_ag.h"
633deb3ec6SMatthias Ringwald 
643deb3ec6SMatthias Ringwald static const char default_hfp_ag_service_name[] = "Voice gateway";
653deb3ec6SMatthias Ringwald static uint16_t hfp_supported_features = HFP_DEFAULT_AG_SUPPORTED_FEATURES;
663deb3ec6SMatthias Ringwald static uint8_t hfp_codecs_nr = 0;
673deb3ec6SMatthias Ringwald static uint8_t hfp_codecs[HFP_MAX_NUM_CODECS];
683deb3ec6SMatthias Ringwald 
693deb3ec6SMatthias Ringwald static int  hfp_ag_indicators_nr = 0;
703deb3ec6SMatthias Ringwald static hfp_ag_indicator_t hfp_ag_indicators[HFP_MAX_NUM_AG_INDICATORS];
713deb3ec6SMatthias Ringwald 
723deb3ec6SMatthias Ringwald static int  hfp_ag_call_hold_services_nr = 0;
733deb3ec6SMatthias Ringwald static char *hfp_ag_call_hold_services[6];
743deb3ec6SMatthias Ringwald static hfp_callback_t hfp_callback;
753deb3ec6SMatthias Ringwald 
76*ffbf8201SMatthias Ringwald static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
773deb3ec6SMatthias Ringwald 
783deb3ec6SMatthias Ringwald hfp_generic_status_indicator_t * get_hfp_generic_status_indicators();
793deb3ec6SMatthias Ringwald int get_hfp_generic_status_indicators_nr();
803deb3ec6SMatthias Ringwald void set_hfp_generic_status_indicators(hfp_generic_status_indicator_t * indicators, int indicator_nr);
813deb3ec6SMatthias Ringwald void set_hfp_ag_indicators(hfp_ag_indicator_t * indicators, int indicator_nr);
823deb3ec6SMatthias Ringwald int get_hfp_ag_indicators_nr(hfp_connection_t * context);
833deb3ec6SMatthias Ringwald hfp_ag_indicator_t * get_hfp_ag_indicators(hfp_connection_t * context);
843deb3ec6SMatthias Ringwald 
853deb3ec6SMatthias Ringwald 
863deb3ec6SMatthias Ringwald hfp_ag_indicator_t * get_hfp_ag_indicators(hfp_connection_t * context){
873deb3ec6SMatthias Ringwald     // TODO: save only value, and value changed in the context?
883deb3ec6SMatthias Ringwald     if (context->ag_indicators_nr != hfp_ag_indicators_nr){
893deb3ec6SMatthias Ringwald         context->ag_indicators_nr = hfp_ag_indicators_nr;
903deb3ec6SMatthias Ringwald         memcpy(context->ag_indicators, hfp_ag_indicators, hfp_ag_indicators_nr * sizeof(hfp_ag_indicator_t));
913deb3ec6SMatthias Ringwald     }
923deb3ec6SMatthias Ringwald     return (hfp_ag_indicator_t *)&(context->ag_indicators);
933deb3ec6SMatthias Ringwald }
943deb3ec6SMatthias Ringwald 
953deb3ec6SMatthias Ringwald void set_hfp_ag_indicators(hfp_ag_indicator_t * indicators, int indicator_nr){
963deb3ec6SMatthias Ringwald     memcpy(hfp_ag_indicators, indicators, indicator_nr * sizeof(hfp_ag_indicator_t));
973deb3ec6SMatthias Ringwald     hfp_ag_indicators_nr = indicator_nr;
983deb3ec6SMatthias Ringwald }
993deb3ec6SMatthias Ringwald 
1003deb3ec6SMatthias Ringwald int get_hfp_ag_indicators_nr(hfp_connection_t * context){
1013deb3ec6SMatthias Ringwald     if (context->ag_indicators_nr != hfp_ag_indicators_nr){
1023deb3ec6SMatthias Ringwald         context->ag_indicators_nr = hfp_ag_indicators_nr;
1033deb3ec6SMatthias Ringwald         memcpy(context->ag_indicators, hfp_ag_indicators, hfp_ag_indicators_nr * sizeof(hfp_ag_indicator_t));
1043deb3ec6SMatthias Ringwald     }
1053deb3ec6SMatthias Ringwald     return context->ag_indicators_nr;
1063deb3ec6SMatthias Ringwald }
1073deb3ec6SMatthias Ringwald 
1083deb3ec6SMatthias Ringwald 
1093deb3ec6SMatthias Ringwald void hfp_ag_register_packet_handler(hfp_callback_t callback){
1103deb3ec6SMatthias Ringwald     if (callback == NULL){
1113deb3ec6SMatthias Ringwald         log_error("hfp_ag_register_packet_handler called with NULL callback");
1123deb3ec6SMatthias Ringwald         return;
1133deb3ec6SMatthias Ringwald     }
1143deb3ec6SMatthias Ringwald     hfp_callback = callback;
1153deb3ec6SMatthias Ringwald }
1163deb3ec6SMatthias Ringwald 
1173deb3ec6SMatthias Ringwald static uint8_t hfp_get_indicator_index_by_name(hfp_connection_t * context, const char * name){
1183deb3ec6SMatthias Ringwald     int i;
1193deb3ec6SMatthias Ringwald     for (i=0; i<context->ag_indicators_nr; i++){
1203deb3ec6SMatthias Ringwald         if (strcmp(context->ag_indicators[i].name, name) == 0){
1213deb3ec6SMatthias Ringwald             return i;
1223deb3ec6SMatthias Ringwald         }
1233deb3ec6SMatthias Ringwald     }
1243deb3ec6SMatthias Ringwald     return 0xFF;
1253deb3ec6SMatthias Ringwald }
1263deb3ec6SMatthias Ringwald 
1273deb3ec6SMatthias Ringwald static void hfp_ag_update_indicator_status(hfp_connection_t * context, const char * indicator_name, uint8_t status){
1283deb3ec6SMatthias Ringwald     int index = hfp_get_indicator_index_by_name(context, indicator_name);
1293deb3ec6SMatthias Ringwald     if (index == 0xFF) return;
1303deb3ec6SMatthias Ringwald     if (context->ag_indicators[index].status == status) return;
1313deb3ec6SMatthias Ringwald     context->ag_indicators[index].status = status;
1323deb3ec6SMatthias Ringwald     context->ag_indicators[index].status_changed = 1;
1333deb3ec6SMatthias Ringwald }
1343deb3ec6SMatthias Ringwald 
1353deb3ec6SMatthias Ringwald static int has_codec_negotiation_feature(hfp_connection_t * connection){
1363deb3ec6SMatthias Ringwald     int hf = get_bit(connection->remote_supported_features, HFP_HFSF_CODEC_NEGOTIATION);
1373deb3ec6SMatthias Ringwald     int ag = get_bit(hfp_supported_features, HFP_AGSF_CODEC_NEGOTIATION);
1383deb3ec6SMatthias Ringwald     return hf && ag;
1393deb3ec6SMatthias Ringwald }
1403deb3ec6SMatthias Ringwald 
1413deb3ec6SMatthias Ringwald static int has_call_waiting_and_3way_calling_feature(hfp_connection_t * connection){
1423deb3ec6SMatthias Ringwald     int hf = get_bit(connection->remote_supported_features, HFP_HFSF_THREE_WAY_CALLING);
1433deb3ec6SMatthias Ringwald     int ag = get_bit(hfp_supported_features, HFP_AGSF_THREE_WAY_CALLING);
1443deb3ec6SMatthias Ringwald     return hf && ag;
1453deb3ec6SMatthias Ringwald }
1463deb3ec6SMatthias Ringwald 
1473deb3ec6SMatthias Ringwald static int has_hf_indicators_feature(hfp_connection_t * connection){
1483deb3ec6SMatthias Ringwald     int hf = get_bit(connection->remote_supported_features, HFP_HFSF_HF_INDICATORS);
1493deb3ec6SMatthias Ringwald     int ag = get_bit(hfp_supported_features, HFP_AGSF_HF_INDICATORS);
1503deb3ec6SMatthias Ringwald     return hf && ag;
1513deb3ec6SMatthias Ringwald }
1523deb3ec6SMatthias Ringwald 
1533deb3ec6SMatthias 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){
1543deb3ec6SMatthias Ringwald     if (!name){
1553deb3ec6SMatthias Ringwald         name = default_hfp_ag_service_name;
1563deb3ec6SMatthias Ringwald     }
1573deb3ec6SMatthias Ringwald     hfp_create_sdp_record(service, SDP_HandsfreeAudioGateway, rfcomm_channel_nr, name, supported_features);
1583deb3ec6SMatthias Ringwald 
1593deb3ec6SMatthias Ringwald     // Network
1603deb3ec6SMatthias Ringwald     de_add_number(service, DE_UINT, DE_SIZE_8, ability_to_reject_call);
1613deb3ec6SMatthias Ringwald     /*
1623deb3ec6SMatthias Ringwald      * 0x01 – Ability to reject a call
1633deb3ec6SMatthias Ringwald      * 0x00 – No ability to reject a call
1643deb3ec6SMatthias Ringwald      */
1653deb3ec6SMatthias Ringwald }
1663deb3ec6SMatthias Ringwald 
1673deb3ec6SMatthias Ringwald static int hfp_ag_exchange_supported_features_cmd(uint16_t cid){
1683deb3ec6SMatthias Ringwald     char buffer[40];
1693deb3ec6SMatthias Ringwald     sprintf(buffer, "\r\n%s:%d\r\n\r\nOK\r\n", HFP_SUPPORTED_FEATURES, hfp_supported_features);
1703deb3ec6SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
1713deb3ec6SMatthias Ringwald }
1723deb3ec6SMatthias Ringwald 
1733deb3ec6SMatthias Ringwald static int hfp_ag_ok(uint16_t cid){
1743deb3ec6SMatthias Ringwald     char buffer[10];
1753deb3ec6SMatthias Ringwald     sprintf(buffer, "\r\nOK\r\n");
1763deb3ec6SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
1773deb3ec6SMatthias Ringwald }
1783deb3ec6SMatthias Ringwald 
1793deb3ec6SMatthias Ringwald static int hfp_ag_error(uint16_t cid){
1803deb3ec6SMatthias Ringwald     char buffer[10];
1813deb3ec6SMatthias Ringwald     sprintf(buffer, "\r\nERROR\r\n");
1823deb3ec6SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
1833deb3ec6SMatthias Ringwald }
1843deb3ec6SMatthias Ringwald 
1853deb3ec6SMatthias Ringwald static int hfp_ag_report_extended_audio_gateway_error(uint16_t cid, uint8_t error){
1863deb3ec6SMatthias Ringwald     char buffer[20];
1873deb3ec6SMatthias Ringwald     sprintf(buffer, "\r\n%s=%d\r\n", HFP_EXTENDED_AUDIO_GATEWAY_ERROR, error);
1883deb3ec6SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
1893deb3ec6SMatthias Ringwald }
1903deb3ec6SMatthias Ringwald 
1913deb3ec6SMatthias Ringwald static int hfp_ag_retrieve_codec_cmd(uint16_t cid){
1923deb3ec6SMatthias Ringwald     return hfp_ag_ok(cid);
1933deb3ec6SMatthias Ringwald }
1943deb3ec6SMatthias Ringwald 
1953deb3ec6SMatthias Ringwald static int hfp_ag_indicators_join(char * buffer, int buffer_size, hfp_connection_t * context){
1963deb3ec6SMatthias Ringwald     if (buffer_size < get_hfp_ag_indicators_nr(context) * (1 + sizeof(hfp_ag_indicator_t))) return 0;
1973deb3ec6SMatthias Ringwald     int i;
1983deb3ec6SMatthias Ringwald     int offset = 0;
1993deb3ec6SMatthias Ringwald     for (i = 0; i < get_hfp_ag_indicators_nr(context)-1; i++) {
2003deb3ec6SMatthias Ringwald         offset += snprintf(buffer+offset, buffer_size-offset, "(\"%s\",(%d,%d)),",
2013deb3ec6SMatthias Ringwald             get_hfp_ag_indicators(context)[i].name,
2023deb3ec6SMatthias Ringwald             get_hfp_ag_indicators(context)[i].min_range,
2033deb3ec6SMatthias Ringwald             get_hfp_ag_indicators(context)[i].max_range);
2043deb3ec6SMatthias Ringwald     }
2053deb3ec6SMatthias Ringwald     if ( i < get_hfp_ag_indicators_nr(context)){
2063deb3ec6SMatthias Ringwald         offset += snprintf(buffer+offset, buffer_size-offset, "(\"%s\",(%d,%d))",
2073deb3ec6SMatthias Ringwald             get_hfp_ag_indicators(context)[i].name,
2083deb3ec6SMatthias Ringwald             get_hfp_ag_indicators(context)[i].min_range,
2093deb3ec6SMatthias Ringwald             get_hfp_ag_indicators(context)[i].max_range);
2103deb3ec6SMatthias Ringwald     }
2113deb3ec6SMatthias Ringwald     return offset;
2123deb3ec6SMatthias Ringwald }
2133deb3ec6SMatthias Ringwald 
2143deb3ec6SMatthias Ringwald static int hfp_hf_indicators_join(char * buffer, int buffer_size){
2153deb3ec6SMatthias Ringwald     if (buffer_size < hfp_ag_indicators_nr * 3) return 0;
2163deb3ec6SMatthias Ringwald     int i;
2173deb3ec6SMatthias Ringwald     int offset = 0;
2183deb3ec6SMatthias Ringwald     for (i = 0; i < get_hfp_generic_status_indicators_nr()-1; i++) {
2193deb3ec6SMatthias Ringwald         offset += snprintf(buffer+offset, buffer_size-offset, "%d,", get_hfp_generic_status_indicators()[i].uuid);
2203deb3ec6SMatthias Ringwald     }
2213deb3ec6SMatthias Ringwald     if (i < get_hfp_generic_status_indicators_nr()){
2223deb3ec6SMatthias Ringwald         offset += snprintf(buffer+offset, buffer_size-offset, "%d,", get_hfp_generic_status_indicators()[i].uuid);
2233deb3ec6SMatthias Ringwald     }
2243deb3ec6SMatthias Ringwald     return offset;
2253deb3ec6SMatthias Ringwald }
2263deb3ec6SMatthias Ringwald 
2273deb3ec6SMatthias Ringwald static int hfp_hf_indicators_initial_status_join(char * buffer, int buffer_size){
2283deb3ec6SMatthias Ringwald     if (buffer_size < get_hfp_generic_status_indicators_nr() * 3) return 0;
2293deb3ec6SMatthias Ringwald     int i;
2303deb3ec6SMatthias Ringwald     int offset = 0;
2313deb3ec6SMatthias Ringwald     for (i = 0; i < get_hfp_generic_status_indicators_nr(); i++) {
2323deb3ec6SMatthias 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);
2333deb3ec6SMatthias Ringwald     }
2343deb3ec6SMatthias Ringwald     return offset;
2353deb3ec6SMatthias Ringwald }
2363deb3ec6SMatthias Ringwald 
2373deb3ec6SMatthias Ringwald static int hfp_ag_indicators_status_join(char * buffer, int buffer_size){
2383deb3ec6SMatthias Ringwald     if (buffer_size < hfp_ag_indicators_nr * 3) return 0;
2393deb3ec6SMatthias Ringwald     int i;
2403deb3ec6SMatthias Ringwald     int offset = 0;
2413deb3ec6SMatthias Ringwald     for (i = 0; i < hfp_ag_indicators_nr-1; i++) {
2423deb3ec6SMatthias Ringwald         offset += snprintf(buffer+offset, buffer_size-offset, "%d,", hfp_ag_indicators[i].status);
2433deb3ec6SMatthias Ringwald     }
2443deb3ec6SMatthias Ringwald     if (i<hfp_ag_indicators_nr){
2453deb3ec6SMatthias Ringwald         offset += snprintf(buffer+offset, buffer_size-offset, "%d", hfp_ag_indicators[i].status);
2463deb3ec6SMatthias Ringwald     }
2473deb3ec6SMatthias Ringwald     return offset;
2483deb3ec6SMatthias Ringwald }
2493deb3ec6SMatthias Ringwald 
2503deb3ec6SMatthias Ringwald static int hfp_ag_call_services_join(char * buffer, int buffer_size){
2513deb3ec6SMatthias Ringwald     if (buffer_size < hfp_ag_call_hold_services_nr * 3) return 0;
2523deb3ec6SMatthias Ringwald     int i;
2533deb3ec6SMatthias Ringwald     int offset = snprintf(buffer, buffer_size, "(");
2543deb3ec6SMatthias Ringwald     for (i = 0; i < hfp_ag_call_hold_services_nr-1; i++) {
2553deb3ec6SMatthias Ringwald         offset += snprintf(buffer+offset, buffer_size-offset, "%s,", hfp_ag_call_hold_services[i]);
2563deb3ec6SMatthias Ringwald     }
2573deb3ec6SMatthias Ringwald     if (i<hfp_ag_call_hold_services_nr){
2583deb3ec6SMatthias Ringwald         offset += snprintf(buffer+offset, buffer_size-offset, "%s)", hfp_ag_call_hold_services[i]);
2593deb3ec6SMatthias Ringwald     }
2603deb3ec6SMatthias Ringwald     return offset;
2613deb3ec6SMatthias Ringwald }
2623deb3ec6SMatthias Ringwald 
2633deb3ec6SMatthias Ringwald static int hfp_ag_retrieve_indicators_cmd(uint16_t cid, hfp_connection_t * context){
2643deb3ec6SMatthias Ringwald     char buffer[250];
2653deb3ec6SMatthias Ringwald     int offset = snprintf(buffer, sizeof(buffer), "\r\n%s:", HFP_INDICATOR);
2663deb3ec6SMatthias Ringwald     offset += hfp_ag_indicators_join(buffer+offset, sizeof(buffer)-offset, context);
2673deb3ec6SMatthias Ringwald 
2683deb3ec6SMatthias Ringwald     buffer[offset] = 0;
2693deb3ec6SMatthias Ringwald 
2703deb3ec6SMatthias Ringwald     offset += snprintf(buffer+offset, sizeof(buffer)-offset, "\r\n\r\nOK\r\n");
2713deb3ec6SMatthias Ringwald     buffer[offset] = 0;
2723deb3ec6SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
2733deb3ec6SMatthias Ringwald }
2743deb3ec6SMatthias Ringwald 
2753deb3ec6SMatthias Ringwald static int hfp_ag_retrieve_indicators_status_cmd(uint16_t cid){
2763deb3ec6SMatthias Ringwald     char buffer[40];
2773deb3ec6SMatthias Ringwald     int offset = snprintf(buffer, sizeof(buffer), "\r\n%s:", HFP_INDICATOR);
2783deb3ec6SMatthias Ringwald     offset += hfp_ag_indicators_status_join(buffer+offset, sizeof(buffer)-offset);
2793deb3ec6SMatthias Ringwald 
2803deb3ec6SMatthias Ringwald     buffer[offset] = 0;
2813deb3ec6SMatthias Ringwald 
2823deb3ec6SMatthias Ringwald     offset += snprintf(buffer+offset, sizeof(buffer)-offset, "\r\n\r\nOK\r\n");
2833deb3ec6SMatthias Ringwald     buffer[offset] = 0;
2843deb3ec6SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
2853deb3ec6SMatthias Ringwald }
2863deb3ec6SMatthias Ringwald 
2873deb3ec6SMatthias Ringwald static int hfp_ag_set_indicator_status_update_cmd(uint16_t cid, uint8_t activate){
2883deb3ec6SMatthias Ringwald     // AT\r\n%s:3,0,0,%d\r\n
2893deb3ec6SMatthias Ringwald     return hfp_ag_ok(cid);
2903deb3ec6SMatthias Ringwald }
2913deb3ec6SMatthias Ringwald 
2923deb3ec6SMatthias Ringwald 
2933deb3ec6SMatthias Ringwald static int hfp_ag_retrieve_can_hold_call_cmd(uint16_t cid){
2943deb3ec6SMatthias Ringwald     char buffer[100];
2953deb3ec6SMatthias Ringwald     int offset = snprintf(buffer, sizeof(buffer), "\r\n%s:", HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES);
2963deb3ec6SMatthias Ringwald     offset += hfp_ag_call_services_join(buffer+offset, sizeof(buffer)-offset);
2973deb3ec6SMatthias Ringwald 
2983deb3ec6SMatthias Ringwald     buffer[offset] = 0;
2993deb3ec6SMatthias Ringwald 
3003deb3ec6SMatthias Ringwald     offset += snprintf(buffer+offset, sizeof(buffer)-offset, "\r\n\r\nOK\r\n");
3013deb3ec6SMatthias Ringwald     buffer[offset] = 0;
3023deb3ec6SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
3033deb3ec6SMatthias Ringwald }
3043deb3ec6SMatthias Ringwald 
3053deb3ec6SMatthias Ringwald 
3063deb3ec6SMatthias Ringwald static int hfp_ag_list_supported_generic_status_indicators_cmd(uint16_t cid){
3073deb3ec6SMatthias Ringwald     return hfp_ag_ok(cid);
3083deb3ec6SMatthias Ringwald }
3093deb3ec6SMatthias Ringwald 
3103deb3ec6SMatthias Ringwald static int hfp_ag_retrieve_supported_generic_status_indicators_cmd(uint16_t cid){
3113deb3ec6SMatthias Ringwald     char buffer[40];
3123deb3ec6SMatthias Ringwald     int offset = snprintf(buffer, sizeof(buffer), "\r\n%s:", HFP_GENERIC_STATUS_INDICATOR);
3133deb3ec6SMatthias Ringwald     offset += hfp_hf_indicators_join(buffer+offset, sizeof(buffer)-offset);
3143deb3ec6SMatthias Ringwald 
3153deb3ec6SMatthias Ringwald     buffer[offset] = 0;
3163deb3ec6SMatthias Ringwald 
3173deb3ec6SMatthias Ringwald     offset += snprintf(buffer+offset, sizeof(buffer)-offset, "\r\n\r\nOK\r\n");
3183deb3ec6SMatthias Ringwald     buffer[offset] = 0;
3193deb3ec6SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
3203deb3ec6SMatthias Ringwald }
3213deb3ec6SMatthias Ringwald 
3223deb3ec6SMatthias Ringwald static int hfp_ag_retrieve_initital_supported_generic_status_indicators_cmd(uint16_t cid){
3233deb3ec6SMatthias Ringwald     char buffer[40];
3243deb3ec6SMatthias Ringwald     int offset = hfp_hf_indicators_initial_status_join(buffer, sizeof(buffer));
3253deb3ec6SMatthias Ringwald 
3263deb3ec6SMatthias Ringwald     buffer[offset] = 0;
3273deb3ec6SMatthias Ringwald     offset += snprintf(buffer+offset, sizeof(buffer)-offset, "\r\nOK\r\n");
3283deb3ec6SMatthias Ringwald     buffer[offset] = 0;
3293deb3ec6SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
3303deb3ec6SMatthias Ringwald }
3313deb3ec6SMatthias Ringwald 
3323deb3ec6SMatthias Ringwald static int hfp_ag_transfer_ag_indicators_status_cmd(uint16_t cid, hfp_ag_indicator_t indicator){
3333deb3ec6SMatthias Ringwald     char buffer[20];
3343deb3ec6SMatthias Ringwald     sprintf(buffer, "\r\n%s:%d,%d\r\n\r\nOK\r\n", HFP_TRANSFER_AG_INDICATOR_STATUS, indicator.index, indicator.status);
3353deb3ec6SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
3363deb3ec6SMatthias Ringwald }
3373deb3ec6SMatthias Ringwald 
3383deb3ec6SMatthias Ringwald static int hfp_ag_report_network_operator_name_cmd(uint16_t cid, hfp_network_opearator_t op){
3393deb3ec6SMatthias Ringwald     char buffer[40];
3403deb3ec6SMatthias Ringwald     if (strlen(op.name) == 0){
3413deb3ec6SMatthias Ringwald         sprintf(buffer, "\r\n%s:%d,,\r\n\r\nOK\r\n", HFP_QUERY_OPERATOR_SELECTION, op.mode);
3423deb3ec6SMatthias Ringwald     } else {
3433deb3ec6SMatthias 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);
3443deb3ec6SMatthias Ringwald     }
3453deb3ec6SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
3463deb3ec6SMatthias Ringwald }
3473deb3ec6SMatthias Ringwald 
3483deb3ec6SMatthias Ringwald 
3493deb3ec6SMatthias Ringwald static int hfp_ag_cmd_suggest_codec(uint16_t cid, uint8_t codec){
3503deb3ec6SMatthias Ringwald     char buffer[30];
3513deb3ec6SMatthias Ringwald     sprintf(buffer, "\r\n%s:%d\r\n", HFP_CONFIRM_COMMON_CODEC, codec);
3523deb3ec6SMatthias Ringwald     return send_str_over_rfcomm(cid, buffer);
3533deb3ec6SMatthias Ringwald }
3543deb3ec6SMatthias Ringwald 
3553deb3ec6SMatthias Ringwald static uint8_t hfp_ag_suggest_codec(hfp_connection_t *context){
3563deb3ec6SMatthias Ringwald     int i,j;
3573deb3ec6SMatthias Ringwald     uint8_t codec = 0;
3583deb3ec6SMatthias Ringwald     for (i = 0; i < hfp_codecs_nr; i++){
3593deb3ec6SMatthias Ringwald         for (j = 0; j < context->remote_codecs_nr; j++){
3603deb3ec6SMatthias Ringwald             if (context->remote_codecs[j] == hfp_codecs[i]){
3613deb3ec6SMatthias Ringwald                 codec = context->remote_codecs[j];
3623deb3ec6SMatthias Ringwald                 continue;
3633deb3ec6SMatthias Ringwald             }
3643deb3ec6SMatthias Ringwald         }
3653deb3ec6SMatthias Ringwald     }
3663deb3ec6SMatthias Ringwald     return codec;
3673deb3ec6SMatthias Ringwald }
3683deb3ec6SMatthias Ringwald 
3693deb3ec6SMatthias Ringwald 
3703deb3ec6SMatthias Ringwald static int hfp_ag_run_for_context_service_level_connection(hfp_connection_t * context){
3713deb3ec6SMatthias Ringwald     if (context->state >= HFP_CODECS_CONNECTION_ESTABLISHED) return 0;
3723deb3ec6SMatthias Ringwald     //printf(" AG run for context_service_level_connection \n");
3733deb3ec6SMatthias Ringwald     int done = 0;
3743deb3ec6SMatthias Ringwald 
3753deb3ec6SMatthias Ringwald     switch(context->command){
3763deb3ec6SMatthias Ringwald         case HFP_CMD_SUPPORTED_FEATURES:
3773deb3ec6SMatthias Ringwald             switch(context->state){
3783deb3ec6SMatthias Ringwald                 case HFP_W4_EXCHANGE_SUPPORTED_FEATURES:
3793deb3ec6SMatthias Ringwald                     hfp_ag_exchange_supported_features_cmd(context->rfcomm_cid);
3803deb3ec6SMatthias Ringwald                     done = 1;
3813deb3ec6SMatthias Ringwald                     if (has_codec_negotiation_feature(context)){
3823deb3ec6SMatthias Ringwald                         context->state = HFP_W4_NOTIFY_ON_CODECS;
3833deb3ec6SMatthias Ringwald                         break;
3843deb3ec6SMatthias Ringwald                     }
3853deb3ec6SMatthias Ringwald                     context->state = HFP_W4_RETRIEVE_INDICATORS;
3863deb3ec6SMatthias Ringwald                     break;
3873deb3ec6SMatthias Ringwald                 default:
3883deb3ec6SMatthias Ringwald                     break;
3893deb3ec6SMatthias Ringwald             }
3903deb3ec6SMatthias Ringwald             break;
3913deb3ec6SMatthias Ringwald         case HFP_CMD_AVAILABLE_CODECS:
3923deb3ec6SMatthias Ringwald             switch(context->state){
3933deb3ec6SMatthias Ringwald                 case HFP_W4_NOTIFY_ON_CODECS:
3943deb3ec6SMatthias Ringwald                     hfp_ag_retrieve_codec_cmd(context->rfcomm_cid);
3953deb3ec6SMatthias Ringwald                     done = 1;
3963deb3ec6SMatthias Ringwald                     context->state = HFP_W4_RETRIEVE_INDICATORS;
3973deb3ec6SMatthias Ringwald                     break;
3983deb3ec6SMatthias Ringwald                 case HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED:
3993deb3ec6SMatthias Ringwald                     context->suggested_codec = hfp_ag_suggest_codec(context);
4003deb3ec6SMatthias Ringwald                     //printf("received BAC == new HF codecs, suggested codec %d\n", context->suggested_codec);
4013deb3ec6SMatthias Ringwald                     hfp_ag_ok(context->rfcomm_cid);
4023deb3ec6SMatthias Ringwald                     done = 1;
4033deb3ec6SMatthias Ringwald                     break;
4043deb3ec6SMatthias Ringwald 
4053deb3ec6SMatthias Ringwald                 default:
4063deb3ec6SMatthias Ringwald                     break;
4073deb3ec6SMatthias Ringwald             }
4083deb3ec6SMatthias Ringwald             break;
4093deb3ec6SMatthias Ringwald         case HFP_CMD_INDICATOR:
4103deb3ec6SMatthias Ringwald             switch(context->state){
4113deb3ec6SMatthias Ringwald                 case HFP_W4_RETRIEVE_INDICATORS:
4123deb3ec6SMatthias Ringwald                     if (context->retrieve_ag_indicators == 0) break;
4133deb3ec6SMatthias Ringwald                     hfp_ag_retrieve_indicators_cmd(context->rfcomm_cid, context);
4143deb3ec6SMatthias Ringwald                     done = 1;
4153deb3ec6SMatthias Ringwald                     context->state = HFP_W4_RETRIEVE_INDICATORS_STATUS;
4163deb3ec6SMatthias Ringwald                     break;
4173deb3ec6SMatthias Ringwald                 case HFP_W4_RETRIEVE_INDICATORS_STATUS:
4183deb3ec6SMatthias Ringwald                     if (context->retrieve_ag_indicators_status == 0) break;
4193deb3ec6SMatthias Ringwald                     hfp_ag_retrieve_indicators_status_cmd(context->rfcomm_cid);
4203deb3ec6SMatthias Ringwald                     done = 1;
4213deb3ec6SMatthias Ringwald                     context->state = HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE;
4223deb3ec6SMatthias Ringwald                     break;
4233deb3ec6SMatthias Ringwald                 default:
4243deb3ec6SMatthias Ringwald                     break;
4253deb3ec6SMatthias Ringwald             }
4263deb3ec6SMatthias Ringwald             break;
4273deb3ec6SMatthias Ringwald         case HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE:
4283deb3ec6SMatthias Ringwald             switch(context->state){
4293deb3ec6SMatthias Ringwald                 case HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE:
4303deb3ec6SMatthias Ringwald                     hfp_ag_set_indicator_status_update_cmd(context->rfcomm_cid, 1);
4313deb3ec6SMatthias Ringwald                     done = 1;
4323deb3ec6SMatthias Ringwald                     if (has_call_waiting_and_3way_calling_feature(context)){
4333deb3ec6SMatthias Ringwald                         context->state = HFP_W4_RETRIEVE_CAN_HOLD_CALL;
4343deb3ec6SMatthias Ringwald                         break;
4353deb3ec6SMatthias Ringwald                     }
4363deb3ec6SMatthias Ringwald                     if (has_hf_indicators_feature(context)){
4373deb3ec6SMatthias Ringwald                         context->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS;
4383deb3ec6SMatthias Ringwald                         break;
4393deb3ec6SMatthias Ringwald                     }
4403deb3ec6SMatthias Ringwald                     context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
4413deb3ec6SMatthias Ringwald                     hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0);
4423deb3ec6SMatthias Ringwald                     break;
4433deb3ec6SMatthias Ringwald                 default:
4443deb3ec6SMatthias Ringwald                     break;
4453deb3ec6SMatthias Ringwald             }
4463deb3ec6SMatthias Ringwald             break;
4473deb3ec6SMatthias Ringwald         case HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES:
4483deb3ec6SMatthias Ringwald             switch(context->state){
4493deb3ec6SMatthias Ringwald                 case HFP_W4_RETRIEVE_CAN_HOLD_CALL:
4503deb3ec6SMatthias Ringwald                     hfp_ag_retrieve_can_hold_call_cmd(context->rfcomm_cid);
4513deb3ec6SMatthias Ringwald                     done = 1;
4523deb3ec6SMatthias Ringwald                     if (has_hf_indicators_feature(context)){
4533deb3ec6SMatthias Ringwald                         context->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS;
4543deb3ec6SMatthias Ringwald                         break;
4553deb3ec6SMatthias Ringwald                     }
4563deb3ec6SMatthias Ringwald                     context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
4573deb3ec6SMatthias Ringwald                     hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0);
4583deb3ec6SMatthias Ringwald                     break;
4593deb3ec6SMatthias Ringwald                 default:
4603deb3ec6SMatthias Ringwald                     break;
4613deb3ec6SMatthias Ringwald             }
4623deb3ec6SMatthias Ringwald             break;
4633deb3ec6SMatthias Ringwald         case HFP_CMD_GENERIC_STATUS_INDICATOR:
4643deb3ec6SMatthias Ringwald             switch(context->state){
4653deb3ec6SMatthias Ringwald                 case HFP_W4_LIST_GENERIC_STATUS_INDICATORS:
4663deb3ec6SMatthias Ringwald                     if (context->list_generic_status_indicators == 0) break;
4673deb3ec6SMatthias Ringwald                     hfp_ag_list_supported_generic_status_indicators_cmd(context->rfcomm_cid);
4683deb3ec6SMatthias Ringwald                     done = 1;
4693deb3ec6SMatthias Ringwald                     context->state = HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS;
4703deb3ec6SMatthias Ringwald                     context->list_generic_status_indicators = 0;
4713deb3ec6SMatthias Ringwald                     break;
4723deb3ec6SMatthias Ringwald                 case HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS:
4733deb3ec6SMatthias Ringwald                     if (context->retrieve_generic_status_indicators == 0) break;
4743deb3ec6SMatthias Ringwald                     hfp_ag_retrieve_supported_generic_status_indicators_cmd(context->rfcomm_cid);
4753deb3ec6SMatthias Ringwald                     done = 1;
4763deb3ec6SMatthias Ringwald                     context->state = HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS;
4773deb3ec6SMatthias Ringwald                     context->retrieve_generic_status_indicators = 0;
4783deb3ec6SMatthias Ringwald                     break;
4793deb3ec6SMatthias Ringwald                 case HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS:
4803deb3ec6SMatthias Ringwald                     if (context->retrieve_generic_status_indicators_state == 0) break;
4813deb3ec6SMatthias Ringwald                     hfp_ag_retrieve_initital_supported_generic_status_indicators_cmd(context->rfcomm_cid);
4823deb3ec6SMatthias Ringwald                     done = 1;
4833deb3ec6SMatthias Ringwald                     context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
4843deb3ec6SMatthias Ringwald                     context->retrieve_generic_status_indicators_state = 0;
4853deb3ec6SMatthias Ringwald                     hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0);
4863deb3ec6SMatthias Ringwald                     break;
4873deb3ec6SMatthias Ringwald                 default:
4883deb3ec6SMatthias Ringwald                     break;
4893deb3ec6SMatthias Ringwald             }
4903deb3ec6SMatthias Ringwald             break;
4913deb3ec6SMatthias Ringwald 
4923deb3ec6SMatthias Ringwald         default:
4933deb3ec6SMatthias Ringwald             break;
4943deb3ec6SMatthias Ringwald     }
4953deb3ec6SMatthias Ringwald     return done;
4963deb3ec6SMatthias Ringwald }
4973deb3ec6SMatthias Ringwald 
4983deb3ec6SMatthias Ringwald static int hfp_ag_run_for_context_service_level_connection_queries(hfp_connection_t * context){
4993deb3ec6SMatthias Ringwald     if (context->state != HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return 0;
5003deb3ec6SMatthias Ringwald     int done = 0;
5013deb3ec6SMatthias Ringwald     //printf("    SLC queries: ");
5023deb3ec6SMatthias Ringwald 
5033deb3ec6SMatthias Ringwald     switch(context->command){
5043deb3ec6SMatthias Ringwald         case HFP_CMD_AVAILABLE_CODECS:
5053deb3ec6SMatthias Ringwald             context->suggested_codec = hfp_ag_suggest_codec(context);
5063deb3ec6SMatthias Ringwald             //printf("received BAC == new HF codecs, suggested codec %d\n", context->suggested_codec);
5073deb3ec6SMatthias Ringwald             hfp_ag_ok(context->rfcomm_cid);
5083deb3ec6SMatthias Ringwald             done = 1;
5093deb3ec6SMatthias Ringwald             break;
5103deb3ec6SMatthias Ringwald 
5113deb3ec6SMatthias Ringwald         case HFP_CMD_QUERY_OPERATOR_SELECTION:
5123deb3ec6SMatthias Ringwald             if (context->operator_name_format == 1){
5133deb3ec6SMatthias Ringwald                 if (context->network_operator.format != 0){
5143deb3ec6SMatthias Ringwald                     hfp_ag_error(context->rfcomm_cid);
5153deb3ec6SMatthias Ringwald                     done = 1;
5163deb3ec6SMatthias Ringwald                     break;
5173deb3ec6SMatthias Ringwald                 }
5183deb3ec6SMatthias Ringwald                 hfp_ag_ok(context->rfcomm_cid);
5193deb3ec6SMatthias Ringwald                 done = 1;
5203deb3ec6SMatthias Ringwald                 context->operator_name_format = 0;
5213deb3ec6SMatthias Ringwald                 break;
5223deb3ec6SMatthias Ringwald             }
5233deb3ec6SMatthias Ringwald             if (context->operator_name == 1){
5243deb3ec6SMatthias Ringwald                 hfp_ag_report_network_operator_name_cmd(context->rfcomm_cid, context->network_operator);
5253deb3ec6SMatthias Ringwald                 context->operator_name = 0;
5263deb3ec6SMatthias Ringwald                 done = 1;
5273deb3ec6SMatthias Ringwald                 break;
5283deb3ec6SMatthias Ringwald             }
5293deb3ec6SMatthias Ringwald             break;
5303deb3ec6SMatthias Ringwald         case HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE:{
5313deb3ec6SMatthias Ringwald                 int i;
5323deb3ec6SMatthias Ringwald                 for (i = 0; i < context->ag_indicators_nr; i++){
5333deb3ec6SMatthias Ringwald                     if (context->ag_indicators[i].enabled == 0) continue;
5343deb3ec6SMatthias Ringwald                     if (context->ag_indicators[i].status_changed == 0) continue;
5353deb3ec6SMatthias Ringwald                     hfp_ag_transfer_ag_indicators_status_cmd(context->rfcomm_cid, context->ag_indicators[i]);
5363deb3ec6SMatthias Ringwald                     done = 1;
5373deb3ec6SMatthias Ringwald                     context->ag_indicators[i].status_changed = 0;
5383deb3ec6SMatthias Ringwald                     return done;
5393deb3ec6SMatthias Ringwald                 }
5403deb3ec6SMatthias Ringwald                 break;
5413deb3ec6SMatthias Ringwald             }
5423deb3ec6SMatthias Ringwald         case HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP:
5433deb3ec6SMatthias Ringwald             if (context->hf_trigger_codec_connection_setup){ // received BCC
5443deb3ec6SMatthias Ringwald                 //printf(" received BCC \n");
5453deb3ec6SMatthias Ringwald                 context->hf_trigger_codec_connection_setup = 0;
5463deb3ec6SMatthias Ringwald                 context->ag_trigger_codec_connection_setup = 1;
5473deb3ec6SMatthias Ringwald                 context->state = HFP_SLE_W2_EXCHANGE_COMMON_CODEC;
5483deb3ec6SMatthias Ringwald                 hfp_ag_ok(context->rfcomm_cid);
5493deb3ec6SMatthias Ringwald                 done = 1;
5503deb3ec6SMatthias Ringwald                 return done;
5513deb3ec6SMatthias Ringwald             }
5523deb3ec6SMatthias Ringwald 
5533deb3ec6SMatthias Ringwald             if (context->ag_trigger_codec_connection_setup){ // received BCS
5543deb3ec6SMatthias Ringwald                 //printf(" send BCS \n");
5553deb3ec6SMatthias Ringwald                 context->ag_trigger_codec_connection_setup = 0;
5563deb3ec6SMatthias Ringwald                 context->state = HFP_SLE_W4_EXCHANGE_COMMON_CODEC;
5573deb3ec6SMatthias Ringwald                 context->suggested_codec = hfp_ag_suggest_codec(context);
5583deb3ec6SMatthias Ringwald                 hfp_ag_cmd_suggest_codec(context->rfcomm_cid, context->suggested_codec);
5593deb3ec6SMatthias Ringwald                 done = 1;
5603deb3ec6SMatthias Ringwald                 return done;
5613deb3ec6SMatthias Ringwald             }
5623deb3ec6SMatthias Ringwald             break;
5633deb3ec6SMatthias Ringwald         case HFP_CMD_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR:
5643deb3ec6SMatthias Ringwald             if (context->extended_audio_gateway_error){
5653deb3ec6SMatthias Ringwald                 hfp_ag_report_extended_audio_gateway_error(context->rfcomm_cid, context->extended_audio_gateway_error);
5663deb3ec6SMatthias Ringwald                 context->extended_audio_gateway_error = 0;
5673deb3ec6SMatthias Ringwald                 done = 1;
5683deb3ec6SMatthias Ringwald                 break;
5693deb3ec6SMatthias Ringwald             }
5703deb3ec6SMatthias Ringwald         case HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE:
5713deb3ec6SMatthias Ringwald             printf("TODO\n");
5723deb3ec6SMatthias Ringwald             break;
5733deb3ec6SMatthias Ringwald         default:
5743deb3ec6SMatthias Ringwald             break;
5753deb3ec6SMatthias Ringwald     }
5763deb3ec6SMatthias Ringwald     return done;
5773deb3ec6SMatthias Ringwald }
5783deb3ec6SMatthias Ringwald 
5793deb3ec6SMatthias Ringwald 
5803deb3ec6SMatthias Ringwald static int hfp_ag_run_for_context_codecs_connection(hfp_connection_t * context){
5813deb3ec6SMatthias Ringwald     if (context->state <= HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED ||
5823deb3ec6SMatthias Ringwald         context->state > HFP_CODECS_CONNECTION_ESTABLISHED) return 0;
5833deb3ec6SMatthias Ringwald 
5843deb3ec6SMatthias Ringwald     int done = 0;
5853deb3ec6SMatthias Ringwald     //printf(" AG run for context_codecs_connection: ");
5863deb3ec6SMatthias Ringwald     switch (context->state){
5873deb3ec6SMatthias Ringwald         case HFP_SLE_W2_EXCHANGE_COMMON_CODEC:
5883deb3ec6SMatthias Ringwald             if (context->ag_trigger_codec_connection_setup){ // received BCS
5893deb3ec6SMatthias Ringwald                 //printf(" send BCS \n");
5903deb3ec6SMatthias Ringwald                 context->ag_trigger_codec_connection_setup = 0;
5913deb3ec6SMatthias Ringwald                 context->state = HFP_SLE_W4_EXCHANGE_COMMON_CODEC;
5923deb3ec6SMatthias Ringwald                 context->suggested_codec = hfp_ag_suggest_codec(context);
5933deb3ec6SMatthias Ringwald                 hfp_ag_cmd_suggest_codec(context->rfcomm_cid, context->suggested_codec);
5943deb3ec6SMatthias Ringwald                 done = 1;
5953deb3ec6SMatthias Ringwald                 break;
5963deb3ec6SMatthias Ringwald             }
5973deb3ec6SMatthias Ringwald             break;
5983deb3ec6SMatthias Ringwald         case HFP_SLE_W4_EXCHANGE_COMMON_CODEC:
5993deb3ec6SMatthias Ringwald             switch(context->command){
6003deb3ec6SMatthias Ringwald                 case HFP_CMD_AVAILABLE_CODECS:
6013deb3ec6SMatthias Ringwald                     if (context->notify_ag_on_new_codecs){ // received BAC
6023deb3ec6SMatthias Ringwald                         //printf(" received BAC\n");
6033deb3ec6SMatthias Ringwald                         context->notify_ag_on_new_codecs = 0;
6043deb3ec6SMatthias Ringwald                         if (context->suggested_codec != hfp_ag_suggest_codec(context)){
6053deb3ec6SMatthias Ringwald                             context->suggested_codec = hfp_ag_suggest_codec(context);
6063deb3ec6SMatthias Ringwald                             context->state = HFP_SLE_W2_EXCHANGE_COMMON_CODEC;
6073deb3ec6SMatthias Ringwald                             context->ag_trigger_codec_connection_setup = 1;
6083deb3ec6SMatthias Ringwald                         }
6093deb3ec6SMatthias Ringwald                         hfp_ag_ok(context->rfcomm_cid);
6103deb3ec6SMatthias Ringwald                         done = 1;
6113deb3ec6SMatthias Ringwald                         break;
6123deb3ec6SMatthias Ringwald                     }
6133deb3ec6SMatthias Ringwald                     break;
6143deb3ec6SMatthias Ringwald                 case HFP_CMD_HF_CONFIRMED_CODEC:
6153deb3ec6SMatthias Ringwald                     //printf(" received AT+BCS\n");
6163deb3ec6SMatthias Ringwald                     if (context->codec_confirmed != context->suggested_codec){
6173deb3ec6SMatthias Ringwald                         context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED;
6183deb3ec6SMatthias Ringwald                         hfp_ag_error(context->rfcomm_cid);
6193deb3ec6SMatthias Ringwald                         done = 1;
6203deb3ec6SMatthias Ringwald                         break;
6213deb3ec6SMatthias Ringwald                     }
6223deb3ec6SMatthias Ringwald                     context->negotiated_codec = context->codec_confirmed;
6233deb3ec6SMatthias Ringwald                     context->state = HFP_CODECS_CONNECTION_ESTABLISHED;
6243deb3ec6SMatthias Ringwald                     hfp_emit_event(hfp_callback, HFP_SUBEVENT_CODECS_CONNECTION_COMPLETE, 0);
6253deb3ec6SMatthias Ringwald                     hfp_ag_ok(context->rfcomm_cid);
6263deb3ec6SMatthias Ringwald                     done = 1;
6273deb3ec6SMatthias Ringwald                     break;
6283deb3ec6SMatthias Ringwald                 default:
6293deb3ec6SMatthias Ringwald                     break;
6303deb3ec6SMatthias Ringwald             }
6313deb3ec6SMatthias Ringwald             break;
6323deb3ec6SMatthias Ringwald 
6333deb3ec6SMatthias Ringwald         case HFP_CODECS_CONNECTION_ESTABLISHED:
6343deb3ec6SMatthias Ringwald             switch(context->command){
6353deb3ec6SMatthias Ringwald                 case HFP_CMD_AVAILABLE_CODECS:
6363deb3ec6SMatthias Ringwald 
6373deb3ec6SMatthias Ringwald                     if (context->notify_ag_on_new_codecs){ // received BAC
6383deb3ec6SMatthias Ringwald                         context->notify_ag_on_new_codecs = 0;
6393deb3ec6SMatthias Ringwald                         if (context->suggested_codec != hfp_ag_suggest_codec(context)){
6403deb3ec6SMatthias Ringwald                             context->suggested_codec = hfp_ag_suggest_codec(context);
6413deb3ec6SMatthias Ringwald                             context->state = HFP_SLE_W4_EXCHANGE_COMMON_CODEC;
6423deb3ec6SMatthias Ringwald                         }
6433deb3ec6SMatthias Ringwald                         hfp_ag_ok(context->rfcomm_cid);
6443deb3ec6SMatthias Ringwald                         done = 1;
6453deb3ec6SMatthias Ringwald                         break;
6463deb3ec6SMatthias Ringwald                     }
6473deb3ec6SMatthias Ringwald                     break;
6483deb3ec6SMatthias Ringwald                 case HFP_CMD_AG_SUGGESTED_CODEC:
6493deb3ec6SMatthias Ringwald                     if (context->ag_trigger_codec_connection_setup){
6503deb3ec6SMatthias Ringwald                         context->ag_trigger_codec_connection_setup = 0;
6513deb3ec6SMatthias Ringwald                         if (context->negotiated_codec != hfp_ag_suggest_codec(context)){
6523deb3ec6SMatthias Ringwald                             context->state = HFP_SLE_W4_EXCHANGE_COMMON_CODEC;
6533deb3ec6SMatthias Ringwald                             context->suggested_codec = hfp_ag_suggest_codec(context);
6543deb3ec6SMatthias Ringwald                             hfp_ag_cmd_suggest_codec(context->rfcomm_cid, context->suggested_codec);
6553deb3ec6SMatthias Ringwald                             done = 1;
6563deb3ec6SMatthias Ringwald                             break;
6573deb3ec6SMatthias Ringwald                         }
6583deb3ec6SMatthias Ringwald                     }
6593deb3ec6SMatthias Ringwald                     break;
6603deb3ec6SMatthias Ringwald                 default:
6613deb3ec6SMatthias Ringwald                     break;
6623deb3ec6SMatthias Ringwald             }
6633deb3ec6SMatthias Ringwald 
6643deb3ec6SMatthias Ringwald         default:
6653deb3ec6SMatthias Ringwald             break;
6663deb3ec6SMatthias Ringwald     }
6673deb3ec6SMatthias Ringwald     return done;
6683deb3ec6SMatthias Ringwald }
6693deb3ec6SMatthias Ringwald 
6703deb3ec6SMatthias Ringwald static void hfp_run_for_context(hfp_connection_t *context){
6713deb3ec6SMatthias Ringwald     if (!context) return;
6723deb3ec6SMatthias Ringwald 
6733deb3ec6SMatthias Ringwald     if (!rfcomm_can_send_packet_now(context->rfcomm_cid)) return;
6743deb3ec6SMatthias Ringwald 
6753deb3ec6SMatthias Ringwald     // printf("AG hfp_run_for_context 1 state %d, command %d\n", context->state, context->command);
6763deb3ec6SMatthias Ringwald     if (context->send_ok){
6773deb3ec6SMatthias Ringwald         hfp_ag_ok(context->rfcomm_cid);
6783deb3ec6SMatthias Ringwald         context->send_ok = 0;
6793deb3ec6SMatthias Ringwald         context->command = HFP_CMD_NONE;
6803deb3ec6SMatthias Ringwald         return;
6813deb3ec6SMatthias Ringwald     }
6823deb3ec6SMatthias Ringwald 
6833deb3ec6SMatthias Ringwald     if (context->send_error){
6843deb3ec6SMatthias Ringwald         hfp_ag_error(context->rfcomm_cid);
6853deb3ec6SMatthias Ringwald         context->send_error = 0;
6863deb3ec6SMatthias Ringwald         context->command = HFP_CMD_NONE;
6873deb3ec6SMatthias Ringwald         return;
6883deb3ec6SMatthias Ringwald     }
6893deb3ec6SMatthias Ringwald 
6903deb3ec6SMatthias Ringwald     int done = hfp_ag_run_for_context_service_level_connection(context);
6913deb3ec6SMatthias Ringwald 
6923deb3ec6SMatthias Ringwald     if (rfcomm_can_send_packet_now(context->rfcomm_cid) && !done){
6933deb3ec6SMatthias Ringwald         done = hfp_ag_run_for_context_service_level_connection_queries(context);
6943deb3ec6SMatthias Ringwald         if (rfcomm_can_send_packet_now(context->rfcomm_cid) && !done){
6953deb3ec6SMatthias Ringwald             done = hfp_ag_run_for_context_codecs_connection(context);
6963deb3ec6SMatthias Ringwald         }
6973deb3ec6SMatthias Ringwald     }
6983deb3ec6SMatthias Ringwald 
6993deb3ec6SMatthias Ringwald 
7003deb3ec6SMatthias Ringwald     if (context->command == HFP_CMD_NONE && !done){
7013deb3ec6SMatthias Ringwald         switch(context->state){
7023deb3ec6SMatthias Ringwald             case HFP_W2_DISCONNECT_RFCOMM:
7033deb3ec6SMatthias Ringwald                 context->state = HFP_W4_RFCOMM_DISCONNECTED;
7043deb3ec6SMatthias Ringwald                 rfcomm_disconnect_internal(context->rfcomm_cid);
7053deb3ec6SMatthias Ringwald                 break;
7063deb3ec6SMatthias Ringwald             default:
7073deb3ec6SMatthias Ringwald                 break;
7083deb3ec6SMatthias Ringwald         }
7093deb3ec6SMatthias Ringwald     }
7103deb3ec6SMatthias Ringwald     if (done){
7113deb3ec6SMatthias Ringwald         context->command = HFP_CMD_NONE;
7123deb3ec6SMatthias Ringwald     }
7133deb3ec6SMatthias Ringwald }
7143deb3ec6SMatthias Ringwald 
7153deb3ec6SMatthias Ringwald static void hfp_handle_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
7163deb3ec6SMatthias Ringwald     hfp_connection_t * context = get_hfp_connection_context_for_rfcomm_cid(channel);
7173deb3ec6SMatthias Ringwald     if (!context) return;
7183deb3ec6SMatthias Ringwald 
7193deb3ec6SMatthias Ringwald     if (context->state == HFP_EXCHANGE_SUPPORTED_FEATURES){
7203deb3ec6SMatthias Ringwald         context->state = HFP_W4_EXCHANGE_SUPPORTED_FEATURES;
7213deb3ec6SMatthias Ringwald     }
7223deb3ec6SMatthias Ringwald 
7233deb3ec6SMatthias Ringwald     packet[size] = 0;
7243deb3ec6SMatthias Ringwald     int pos;
7253deb3ec6SMatthias Ringwald     for (pos = 0; pos < size ; pos++){
7263deb3ec6SMatthias Ringwald         hfp_parse(context, packet[pos]);
7273deb3ec6SMatthias Ringwald 
7283deb3ec6SMatthias Ringwald         // trigger next action after CMD received
7293deb3ec6SMatthias Ringwald         if (context->command == HFP_CMD_NONE) continue;
7303deb3ec6SMatthias Ringwald         //hfp_run_for_context(context);
7313deb3ec6SMatthias Ringwald     }
7323deb3ec6SMatthias Ringwald }
7333deb3ec6SMatthias Ringwald 
7343deb3ec6SMatthias Ringwald static void hfp_run(){
7353deb3ec6SMatthias Ringwald     linked_list_iterator_t it;
7363deb3ec6SMatthias Ringwald     linked_list_iterator_init(&it, hfp_get_connections());
7373deb3ec6SMatthias Ringwald     while (linked_list_iterator_has_next(&it)){
7383deb3ec6SMatthias Ringwald         hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it);
7393deb3ec6SMatthias Ringwald         hfp_run_for_context(connection);
7403deb3ec6SMatthias Ringwald     }
7413deb3ec6SMatthias Ringwald }
7423deb3ec6SMatthias Ringwald 
743*ffbf8201SMatthias Ringwald static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
7443deb3ec6SMatthias Ringwald     switch (packet_type){
7453deb3ec6SMatthias Ringwald         case RFCOMM_DATA_PACKET:
7463deb3ec6SMatthias Ringwald             hfp_handle_rfcomm_event(packet_type, channel, packet, size);
7473deb3ec6SMatthias Ringwald             break;
7483deb3ec6SMatthias Ringwald         case HCI_EVENT_PACKET:
7493deb3ec6SMatthias Ringwald             hfp_handle_hci_event(hfp_callback, packet_type, packet, size);
7503deb3ec6SMatthias Ringwald             return;
7513deb3ec6SMatthias Ringwald         default:
7523deb3ec6SMatthias Ringwald             break;
7533deb3ec6SMatthias Ringwald     }
7543deb3ec6SMatthias Ringwald 
7553deb3ec6SMatthias Ringwald     hfp_run();
7563deb3ec6SMatthias Ringwald }
7573deb3ec6SMatthias Ringwald 
7583deb3ec6SMatthias Ringwald void hfp_ag_init(uint16_t rfcomm_channel_nr, uint32_t supported_features,
7593deb3ec6SMatthias Ringwald     uint8_t * codecs, int codecs_nr,
7603deb3ec6SMatthias Ringwald     hfp_ag_indicator_t * ag_indicators, int ag_indicators_nr,
7613deb3ec6SMatthias Ringwald     hfp_generic_status_indicator_t * hf_indicators, int hf_indicators_nr,
7623deb3ec6SMatthias Ringwald     const char *call_hold_services[], int call_hold_services_nr){
7633deb3ec6SMatthias Ringwald     if (codecs_nr > HFP_MAX_NUM_CODECS){
7643deb3ec6SMatthias Ringwald         log_error("hfp_init: codecs_nr (%d) > HFP_MAX_NUM_CODECS (%d)", codecs_nr, HFP_MAX_NUM_CODECS);
7653deb3ec6SMatthias Ringwald         return;
7663deb3ec6SMatthias Ringwald     }
7673deb3ec6SMatthias Ringwald     rfcomm_register_packet_handler(packet_handler);
7683deb3ec6SMatthias Ringwald     hfp_init(rfcomm_channel_nr);
7693deb3ec6SMatthias Ringwald 
7703deb3ec6SMatthias Ringwald     hfp_supported_features = supported_features;
7713deb3ec6SMatthias Ringwald     hfp_codecs_nr = codecs_nr;
7723deb3ec6SMatthias Ringwald 
7733deb3ec6SMatthias Ringwald     int i;
7743deb3ec6SMatthias Ringwald     for (i=0; i<codecs_nr; i++){
7753deb3ec6SMatthias Ringwald         hfp_codecs[i] = codecs[i];
7763deb3ec6SMatthias Ringwald     }
7773deb3ec6SMatthias Ringwald 
7783deb3ec6SMatthias Ringwald     hfp_ag_indicators_nr = ag_indicators_nr;
7793deb3ec6SMatthias Ringwald     memcpy(hfp_ag_indicators, ag_indicators, ag_indicators_nr * sizeof(hfp_ag_indicator_t));
7803deb3ec6SMatthias Ringwald     for (i=0; i<hfp_ag_indicators_nr; i++){
7813deb3ec6SMatthias Ringwald         printf("ag ind %s\n", hfp_ag_indicators[i].name);
7823deb3ec6SMatthias Ringwald     }
7833deb3ec6SMatthias Ringwald 
7843deb3ec6SMatthias Ringwald     set_hfp_generic_status_indicators(hf_indicators, hf_indicators_nr);
7853deb3ec6SMatthias Ringwald 
7863deb3ec6SMatthias Ringwald     hfp_ag_call_hold_services_nr = call_hold_services_nr;
7873deb3ec6SMatthias Ringwald     memcpy(hfp_ag_call_hold_services, call_hold_services, call_hold_services_nr * sizeof(char *));
7883deb3ec6SMatthias Ringwald }
7893deb3ec6SMatthias Ringwald 
7903deb3ec6SMatthias Ringwald void hfp_ag_establish_service_level_connection(bd_addr_t bd_addr){
7913deb3ec6SMatthias Ringwald     hfp_establish_service_level_connection(bd_addr, SDP_Handsfree);
7923deb3ec6SMatthias Ringwald }
7933deb3ec6SMatthias Ringwald 
7943deb3ec6SMatthias Ringwald void hfp_ag_release_service_level_connection(bd_addr_t bd_addr){
7953deb3ec6SMatthias Ringwald     hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
7963deb3ec6SMatthias Ringwald     hfp_release_service_level_connection(connection);
7973deb3ec6SMatthias Ringwald     hfp_run_for_context(connection);
7983deb3ec6SMatthias Ringwald }
7993deb3ec6SMatthias Ringwald 
8003deb3ec6SMatthias Ringwald void hfp_ag_report_extended_audio_gateway_error_result_code(bd_addr_t bd_addr, hfp_cme_error_t error){
8013deb3ec6SMatthias Ringwald     hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
8023deb3ec6SMatthias Ringwald     if (!connection){
8033deb3ec6SMatthias Ringwald         log_error("HFP HF: connection doesn't exist.");
8043deb3ec6SMatthias Ringwald         return;
8053deb3ec6SMatthias Ringwald     }
8063deb3ec6SMatthias Ringwald     connection->extended_audio_gateway_error = 0;
8073deb3ec6SMatthias Ringwald     if (!connection->enable_extended_audio_gateway_error_report){
8083deb3ec6SMatthias Ringwald         return;
8093deb3ec6SMatthias Ringwald     }
8103deb3ec6SMatthias Ringwald     connection->extended_audio_gateway_error = error;
8113deb3ec6SMatthias Ringwald     hfp_run_for_context(connection);
8123deb3ec6SMatthias Ringwald }
8133deb3ec6SMatthias Ringwald 
8143deb3ec6SMatthias Ringwald void hfp_ag_transfer_call_status(bd_addr_t bd_addr, hfp_call_status_t status){
8153deb3ec6SMatthias Ringwald     hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
8163deb3ec6SMatthias Ringwald     if (!connection){
8173deb3ec6SMatthias Ringwald         log_error("HFP HF: connection doesn't exist.");
8183deb3ec6SMatthias Ringwald         return;
8193deb3ec6SMatthias Ringwald     }
8203deb3ec6SMatthias Ringwald     if (!connection->enable_status_update_for_ag_indicators) return;
8213deb3ec6SMatthias Ringwald     hfp_ag_update_indicator_status(connection, (char *)"call", status);
8223deb3ec6SMatthias Ringwald }
8233deb3ec6SMatthias Ringwald 
8243deb3ec6SMatthias Ringwald void hfp_ag_transfer_callsetup_status(bd_addr_t bd_addr, hfp_callsetup_status_t status){
8253deb3ec6SMatthias Ringwald     hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
8263deb3ec6SMatthias Ringwald     if (!connection){
8273deb3ec6SMatthias Ringwald         log_error("HFP HF: connection doesn't exist.");
8283deb3ec6SMatthias Ringwald         return;
8293deb3ec6SMatthias Ringwald     }
8303deb3ec6SMatthias Ringwald     if (!connection->enable_status_update_for_ag_indicators) return;
8313deb3ec6SMatthias Ringwald     hfp_ag_update_indicator_status(connection, (char *)"callsetup", status);
8323deb3ec6SMatthias Ringwald }
8333deb3ec6SMatthias Ringwald 
8343deb3ec6SMatthias Ringwald void hfp_ag_transfer_callheld_status(bd_addr_t bd_addr, hfp_callheld_status_t status){
8353deb3ec6SMatthias Ringwald     hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
8363deb3ec6SMatthias Ringwald     if (!connection){
8373deb3ec6SMatthias Ringwald         log_error("HFP AG: connection doesn't exist.");
8383deb3ec6SMatthias Ringwald         return;
8393deb3ec6SMatthias Ringwald     }
8403deb3ec6SMatthias Ringwald     if (!connection->enable_status_update_for_ag_indicators) return;
8413deb3ec6SMatthias Ringwald     hfp_ag_update_indicator_status(connection, (char *)"callheld", status);
8423deb3ec6SMatthias Ringwald     hfp_run_for_context(connection);
8433deb3ec6SMatthias Ringwald }
8443deb3ec6SMatthias Ringwald 
8453deb3ec6SMatthias Ringwald #if 0
8463deb3ec6SMatthias Ringwald static void hfp_ag_codec_connection_setup(hfp_connection_t * connection){
8473deb3ec6SMatthias Ringwald     if (!connection){
8483deb3ec6SMatthias Ringwald         log_error("HFP AG: connection doesn't exist.");
8493deb3ec6SMatthias Ringwald         return;
8503deb3ec6SMatthias Ringwald     }
8513deb3ec6SMatthias Ringwald     // TODO:
8523deb3ec6SMatthias Ringwald     hfp_run_for_context(connection);
8533deb3ec6SMatthias Ringwald }
8543deb3ec6SMatthias Ringwald #endif
8553deb3ec6SMatthias Ringwald 
8563deb3ec6SMatthias Ringwald /**
8573deb3ec6SMatthias Ringwald  * @param handle
8583deb3ec6SMatthias Ringwald  * @param transmit_bandwidth 8000(64kbps)
8593deb3ec6SMatthias Ringwald  * @param receive_bandwidth  8000(64kbps)
8603deb3ec6SMatthias Ringwald  * @param max_latency        >= 7ms for eSCO, 0xFFFF do not care
8613deb3ec6SMatthias Ringwald  * @param voice_settings     e.g. CVSD, Input Coding: Linear, Input Data Format: 2’s complement, data 16bit: 00011000000 == 0x60
8623deb3ec6SMatthias Ringwald  * @param retransmission_effort  e.g. 0xFF do not care
8633deb3ec6SMatthias Ringwald  * @param packet_type        at least EV3 for eSCO
8643deb3ec6SMatthias Ringwald 
8653deb3ec6SMatthias Ringwald  hci_send_cmd(&hci_setup_synchronous_connection, rfcomm_handle, 8000, 8000, 0xFFFF, 0x0060, 0xFF, 0x003F);
8663deb3ec6SMatthias Ringwald 
8673deb3ec6SMatthias Ringwald  */
8683deb3ec6SMatthias Ringwald 
8693deb3ec6SMatthias Ringwald #if 0
8703deb3ec6SMatthias Ringwald static void hfp_ag_negotiate_codecs(bd_addr_t bd_addr){
8713deb3ec6SMatthias Ringwald     hfp_ag_establish_service_level_connection(bd_addr);
8723deb3ec6SMatthias Ringwald     hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
8733deb3ec6SMatthias Ringwald     if (!has_codec_negotiation_feature(connection)) return;
8743deb3ec6SMatthias Ringwald     if (connection->remote_codecs_nr == 0) return;
8753deb3ec6SMatthias Ringwald 
8763deb3ec6SMatthias Ringwald     if (connection->state >= HFP_W2_DISCONNECT_SCO) return;
8773deb3ec6SMatthias Ringwald 
8783deb3ec6SMatthias Ringwald     if (connection->state != HFP_SLE_W2_EXCHANGE_COMMON_CODEC &&
8793deb3ec6SMatthias Ringwald         connection->state != HFP_SLE_W4_EXCHANGE_COMMON_CODEC){
8803deb3ec6SMatthias Ringwald         connection->ag_trigger_codec_connection_setup = 1;
8813deb3ec6SMatthias Ringwald     }
8823deb3ec6SMatthias Ringwald 
8833deb3ec6SMatthias Ringwald     hfp_run_for_context(connection);
8843deb3ec6SMatthias Ringwald }
8853deb3ec6SMatthias Ringwald #endif
8863deb3ec6SMatthias Ringwald 
8873deb3ec6SMatthias Ringwald void hfp_ag_establish_audio_connection(bd_addr_t bd_addr){
8883deb3ec6SMatthias Ringwald     hfp_ag_establish_service_level_connection(bd_addr);
8893deb3ec6SMatthias Ringwald     hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
8903deb3ec6SMatthias Ringwald     if (!has_codec_negotiation_feature(connection)) return;
8913deb3ec6SMatthias Ringwald     connection->establish_audio_connection = 0;
8923deb3ec6SMatthias Ringwald     if (connection->state == HFP_AUDIO_CONNECTION_ESTABLISHED) return;
8933deb3ec6SMatthias Ringwald     if (connection->state >= HFP_W2_DISCONNECT_SCO) return;
8943deb3ec6SMatthias Ringwald 
8953deb3ec6SMatthias Ringwald     connection->establish_audio_connection = 1;
8963deb3ec6SMatthias Ringwald     if (connection->state < HFP_SLE_W4_EXCHANGE_COMMON_CODEC){
8973deb3ec6SMatthias Ringwald         connection->ag_trigger_codec_connection_setup = 1;
8983deb3ec6SMatthias Ringwald     }
8993deb3ec6SMatthias Ringwald     hfp_run_for_context(connection);
9003deb3ec6SMatthias Ringwald }
9013deb3ec6SMatthias Ringwald 
9023deb3ec6SMatthias Ringwald void hfp_ag_release_audio_connection(bd_addr_t bd_addr){
9033deb3ec6SMatthias Ringwald     hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
9043deb3ec6SMatthias Ringwald     hfp_release_audio_connection(connection);
9053deb3ec6SMatthias Ringwald     hfp_run_for_context(connection);
9063deb3ec6SMatthias Ringwald }
907