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