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"; 65*aa4dd815SMatthias Ringwald 663deb3ec6SMatthias Ringwald static uint16_t hfp_supported_features = HFP_DEFAULT_AG_SUPPORTED_FEATURES; 67*aa4dd815SMatthias Ringwald 683deb3ec6SMatthias Ringwald static uint8_t hfp_codecs_nr = 0; 693deb3ec6SMatthias Ringwald static uint8_t hfp_codecs[HFP_MAX_NUM_CODECS]; 703deb3ec6SMatthias Ringwald 713deb3ec6SMatthias Ringwald static int hfp_ag_indicators_nr = 0; 723deb3ec6SMatthias Ringwald static hfp_ag_indicator_t hfp_ag_indicators[HFP_MAX_NUM_AG_INDICATORS]; 733deb3ec6SMatthias Ringwald 743deb3ec6SMatthias Ringwald static int hfp_ag_call_hold_services_nr = 0; 753deb3ec6SMatthias Ringwald static char *hfp_ag_call_hold_services[6]; 763deb3ec6SMatthias Ringwald static hfp_callback_t hfp_callback; 773deb3ec6SMatthias Ringwald 78*aa4dd815SMatthias Ringwald 79*aa4dd815SMatthias Ringwald static hfp_call_status_t hfp_ag_call_state; 80*aa4dd815SMatthias Ringwald static hfp_callsetup_status_t hfp_ag_callsetup_state; 81*aa4dd815SMatthias Ringwald static hfp_callheld_status_t hfp_ag_callheld_state; 82*aa4dd815SMatthias Ringwald 83*aa4dd815SMatthias Ringwald // CLIP feature 84*aa4dd815SMatthias Ringwald static uint8_t clip_type; // 0 == not set 85*aa4dd815SMatthias Ringwald static char clip_number[25]; // 86*aa4dd815SMatthias Ringwald 87*aa4dd815SMatthias Ringwald static void hfp_run_for_context(hfp_connection_t *context); 88*aa4dd815SMatthias Ringwald static void hfp_ag_setup_audio_connection(hfp_connection_t * connection); 893deb3ec6SMatthias Ringwald 903deb3ec6SMatthias Ringwald hfp_generic_status_indicator_t * get_hfp_generic_status_indicators(); 913deb3ec6SMatthias Ringwald int get_hfp_generic_status_indicators_nr(); 923deb3ec6SMatthias Ringwald void set_hfp_generic_status_indicators(hfp_generic_status_indicator_t * indicators, int indicator_nr); 933deb3ec6SMatthias Ringwald void set_hfp_ag_indicators(hfp_ag_indicator_t * indicators, int indicator_nr); 943deb3ec6SMatthias Ringwald int get_hfp_ag_indicators_nr(hfp_connection_t * context); 953deb3ec6SMatthias Ringwald hfp_ag_indicator_t * get_hfp_ag_indicators(hfp_connection_t * context); 963deb3ec6SMatthias Ringwald 973deb3ec6SMatthias Ringwald 983deb3ec6SMatthias Ringwald hfp_ag_indicator_t * get_hfp_ag_indicators(hfp_connection_t * context){ 993deb3ec6SMatthias Ringwald // TODO: save only value, and value changed in the context? 1003deb3ec6SMatthias Ringwald if (context->ag_indicators_nr != hfp_ag_indicators_nr){ 1013deb3ec6SMatthias Ringwald context->ag_indicators_nr = hfp_ag_indicators_nr; 1023deb3ec6SMatthias Ringwald memcpy(context->ag_indicators, hfp_ag_indicators, hfp_ag_indicators_nr * sizeof(hfp_ag_indicator_t)); 1033deb3ec6SMatthias Ringwald } 1043deb3ec6SMatthias Ringwald return (hfp_ag_indicator_t *)&(context->ag_indicators); 1053deb3ec6SMatthias Ringwald } 1063deb3ec6SMatthias Ringwald 107*aa4dd815SMatthias Ringwald static hfp_ag_indicator_t * get_ag_indicator_for_name(const char * name){ 108*aa4dd815SMatthias Ringwald int i; 109*aa4dd815SMatthias Ringwald for (i = 0; i < hfp_ag_indicators_nr; i++){ 110*aa4dd815SMatthias Ringwald if (strcmp(hfp_ag_indicators[i].name, name) == 0){ 111*aa4dd815SMatthias Ringwald return &hfp_ag_indicators[i]; 112*aa4dd815SMatthias Ringwald } 113*aa4dd815SMatthias Ringwald } 114*aa4dd815SMatthias Ringwald return NULL; 115*aa4dd815SMatthias Ringwald } 116*aa4dd815SMatthias Ringwald 117*aa4dd815SMatthias Ringwald static int get_ag_indicator_index_for_name(const char * name){ 118*aa4dd815SMatthias Ringwald int i; 119*aa4dd815SMatthias Ringwald for (i = 0; i < hfp_ag_indicators_nr; i++){ 120*aa4dd815SMatthias Ringwald if (strcmp(hfp_ag_indicators[i].name, name) == 0){ 121*aa4dd815SMatthias Ringwald return i; 122*aa4dd815SMatthias Ringwald } 123*aa4dd815SMatthias Ringwald } 124*aa4dd815SMatthias Ringwald return -1; 125*aa4dd815SMatthias Ringwald } 126*aa4dd815SMatthias Ringwald 1273deb3ec6SMatthias Ringwald void set_hfp_ag_indicators(hfp_ag_indicator_t * indicators, int indicator_nr){ 1283deb3ec6SMatthias Ringwald memcpy(hfp_ag_indicators, indicators, indicator_nr * sizeof(hfp_ag_indicator_t)); 1293deb3ec6SMatthias Ringwald hfp_ag_indicators_nr = indicator_nr; 1303deb3ec6SMatthias Ringwald } 1313deb3ec6SMatthias Ringwald 1323deb3ec6SMatthias Ringwald int get_hfp_ag_indicators_nr(hfp_connection_t * context){ 1333deb3ec6SMatthias Ringwald if (context->ag_indicators_nr != hfp_ag_indicators_nr){ 1343deb3ec6SMatthias Ringwald context->ag_indicators_nr = hfp_ag_indicators_nr; 1353deb3ec6SMatthias Ringwald memcpy(context->ag_indicators, hfp_ag_indicators, hfp_ag_indicators_nr * sizeof(hfp_ag_indicator_t)); 1363deb3ec6SMatthias Ringwald } 1373deb3ec6SMatthias Ringwald return context->ag_indicators_nr; 1383deb3ec6SMatthias Ringwald } 1393deb3ec6SMatthias Ringwald 1403deb3ec6SMatthias Ringwald 1413deb3ec6SMatthias Ringwald void hfp_ag_register_packet_handler(hfp_callback_t callback){ 1423deb3ec6SMatthias Ringwald if (callback == NULL){ 1433deb3ec6SMatthias Ringwald log_error("hfp_ag_register_packet_handler called with NULL callback"); 1443deb3ec6SMatthias Ringwald return; 1453deb3ec6SMatthias Ringwald } 1463deb3ec6SMatthias Ringwald hfp_callback = callback; 1473deb3ec6SMatthias Ringwald } 1483deb3ec6SMatthias Ringwald 149*aa4dd815SMatthias Ringwald static int use_in_band_tone(){ 150*aa4dd815SMatthias Ringwald return get_bit(hfp_supported_features, HFP_AGSF_IN_BAND_RING_TONE); 1513deb3ec6SMatthias Ringwald } 1523deb3ec6SMatthias Ringwald 1533deb3ec6SMatthias Ringwald static int has_codec_negotiation_feature(hfp_connection_t * connection){ 1543deb3ec6SMatthias Ringwald int hf = get_bit(connection->remote_supported_features, HFP_HFSF_CODEC_NEGOTIATION); 1553deb3ec6SMatthias Ringwald int ag = get_bit(hfp_supported_features, HFP_AGSF_CODEC_NEGOTIATION); 1563deb3ec6SMatthias Ringwald return hf && ag; 1573deb3ec6SMatthias Ringwald } 1583deb3ec6SMatthias Ringwald 1593deb3ec6SMatthias Ringwald static int has_call_waiting_and_3way_calling_feature(hfp_connection_t * connection){ 1603deb3ec6SMatthias Ringwald int hf = get_bit(connection->remote_supported_features, HFP_HFSF_THREE_WAY_CALLING); 1613deb3ec6SMatthias Ringwald int ag = get_bit(hfp_supported_features, HFP_AGSF_THREE_WAY_CALLING); 1623deb3ec6SMatthias Ringwald return hf && ag; 1633deb3ec6SMatthias Ringwald } 1643deb3ec6SMatthias Ringwald 1653deb3ec6SMatthias Ringwald static int has_hf_indicators_feature(hfp_connection_t * connection){ 1663deb3ec6SMatthias Ringwald int hf = get_bit(connection->remote_supported_features, HFP_HFSF_HF_INDICATORS); 1673deb3ec6SMatthias Ringwald int ag = get_bit(hfp_supported_features, HFP_AGSF_HF_INDICATORS); 1683deb3ec6SMatthias Ringwald return hf && ag; 1693deb3ec6SMatthias Ringwald } 1703deb3ec6SMatthias Ringwald 1713deb3ec6SMatthias 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){ 1723deb3ec6SMatthias Ringwald if (!name){ 1733deb3ec6SMatthias Ringwald name = default_hfp_ag_service_name; 1743deb3ec6SMatthias Ringwald } 175*aa4dd815SMatthias Ringwald hfp_create_sdp_record(service, SDP_HandsfreeAudioGateway, rfcomm_channel_nr, name); 1763deb3ec6SMatthias Ringwald 1773deb3ec6SMatthias Ringwald /* 1783deb3ec6SMatthias Ringwald * 0x01 – Ability to reject a call 1793deb3ec6SMatthias Ringwald * 0x00 – No ability to reject a call 1803deb3ec6SMatthias Ringwald */ 181*aa4dd815SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, 0x0301); // Hands-Free Profile - Network 182*aa4dd815SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_8, ability_to_reject_call); 183*aa4dd815SMatthias Ringwald 184*aa4dd815SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, 0x0311); // Hands-Free Profile - SupportedFeatures 185*aa4dd815SMatthias Ringwald de_add_number(service, DE_UINT, DE_SIZE_16, supported_features); 186*aa4dd815SMatthias Ringwald } 187*aa4dd815SMatthias Ringwald 188*aa4dd815SMatthias Ringwald static int hfp_ag_change_in_band_ring_tone_setting_cmd(uint16_t cid){ 189*aa4dd815SMatthias Ringwald char buffer[20]; 190*aa4dd815SMatthias Ringwald sprintf(buffer, "\r\n%s:%d\r\n", HFP_CHANGE_IN_BAND_RING_TONE_SETTING, use_in_band_tone()); 191*aa4dd815SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 1923deb3ec6SMatthias Ringwald } 1933deb3ec6SMatthias Ringwald 1943deb3ec6SMatthias Ringwald static int hfp_ag_exchange_supported_features_cmd(uint16_t cid){ 1953deb3ec6SMatthias Ringwald char buffer[40]; 1963deb3ec6SMatthias Ringwald sprintf(buffer, "\r\n%s:%d\r\n\r\nOK\r\n", HFP_SUPPORTED_FEATURES, hfp_supported_features); 1973deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 1983deb3ec6SMatthias Ringwald } 1993deb3ec6SMatthias Ringwald 2003deb3ec6SMatthias Ringwald static int hfp_ag_ok(uint16_t cid){ 2013deb3ec6SMatthias Ringwald char buffer[10]; 2023deb3ec6SMatthias Ringwald sprintf(buffer, "\r\nOK\r\n"); 2033deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 2043deb3ec6SMatthias Ringwald } 2053deb3ec6SMatthias Ringwald 206*aa4dd815SMatthias Ringwald static int hfp_ag_ring(uint16_t cid){ 207*aa4dd815SMatthias Ringwald return send_str_over_rfcomm(cid, (char *) "\r\nRING\r\n"); 208*aa4dd815SMatthias Ringwald } 209*aa4dd815SMatthias Ringwald 210*aa4dd815SMatthias Ringwald static int hfp_ag_send_clip(uint16_t cid){ 211*aa4dd815SMatthias Ringwald if (!clip_type){ 212*aa4dd815SMatthias Ringwald clip_number[0] = 0; 213*aa4dd815SMatthias Ringwald } 214*aa4dd815SMatthias Ringwald char buffer[50]; 215*aa4dd815SMatthias Ringwald sprintf(buffer, "\r\n%s: \"%s\",%u\r\n", HFP_ENABLE_CLIP, clip_number, clip_type); 216*aa4dd815SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 217*aa4dd815SMatthias Ringwald } 218*aa4dd815SMatthias Ringwald 219*aa4dd815SMatthias Ringwald static int hfp_ag_send_phone_number_for_voice_tag(uint16_t cid){ 220*aa4dd815SMatthias Ringwald char buffer[50]; 221*aa4dd815SMatthias Ringwald sprintf(buffer, "\r\n%s:%s\r\n", HFP_PHONE_NUMBER_FOR_VOICE_TAG, clip_number); 222*aa4dd815SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 223*aa4dd815SMatthias Ringwald } 224*aa4dd815SMatthias Ringwald 225*aa4dd815SMatthias Ringwald 226*aa4dd815SMatthias Ringwald static int hfp_ag_send_call_waiting_notification(uint16_t cid){ 227*aa4dd815SMatthias Ringwald if (!clip_type){ 228*aa4dd815SMatthias Ringwald clip_number[0] = 0; 229*aa4dd815SMatthias Ringwald } 230*aa4dd815SMatthias Ringwald char buffer[50]; 231*aa4dd815SMatthias Ringwald sprintf(buffer, "\r\n+CCWA: \"%s\",%u\r\n", clip_number, clip_type); 232*aa4dd815SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 233*aa4dd815SMatthias Ringwald } 234*aa4dd815SMatthias Ringwald 2353deb3ec6SMatthias Ringwald static int hfp_ag_error(uint16_t cid){ 2363deb3ec6SMatthias Ringwald char buffer[10]; 2373deb3ec6SMatthias Ringwald sprintf(buffer, "\r\nERROR\r\n"); 2383deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 2393deb3ec6SMatthias Ringwald } 2403deb3ec6SMatthias Ringwald 2413deb3ec6SMatthias Ringwald static int hfp_ag_report_extended_audio_gateway_error(uint16_t cid, uint8_t error){ 2423deb3ec6SMatthias Ringwald char buffer[20]; 2433deb3ec6SMatthias Ringwald sprintf(buffer, "\r\n%s=%d\r\n", HFP_EXTENDED_AUDIO_GATEWAY_ERROR, error); 2443deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 2453deb3ec6SMatthias Ringwald } 2463deb3ec6SMatthias Ringwald 2473deb3ec6SMatthias Ringwald static int hfp_ag_indicators_join(char * buffer, int buffer_size, hfp_connection_t * context){ 2483deb3ec6SMatthias Ringwald if (buffer_size < get_hfp_ag_indicators_nr(context) * (1 + sizeof(hfp_ag_indicator_t))) return 0; 2493deb3ec6SMatthias Ringwald int i; 2503deb3ec6SMatthias Ringwald int offset = 0; 2513deb3ec6SMatthias Ringwald for (i = 0; i < get_hfp_ag_indicators_nr(context)-1; i++) { 2523deb3ec6SMatthias Ringwald offset += snprintf(buffer+offset, buffer_size-offset, "(\"%s\",(%d,%d)),", 2533deb3ec6SMatthias Ringwald get_hfp_ag_indicators(context)[i].name, 2543deb3ec6SMatthias Ringwald get_hfp_ag_indicators(context)[i].min_range, 2553deb3ec6SMatthias Ringwald get_hfp_ag_indicators(context)[i].max_range); 2563deb3ec6SMatthias Ringwald } 2573deb3ec6SMatthias Ringwald if ( i < get_hfp_ag_indicators_nr(context)){ 2583deb3ec6SMatthias Ringwald offset += snprintf(buffer+offset, buffer_size-offset, "(\"%s\",(%d,%d))", 2593deb3ec6SMatthias Ringwald get_hfp_ag_indicators(context)[i].name, 2603deb3ec6SMatthias Ringwald get_hfp_ag_indicators(context)[i].min_range, 2613deb3ec6SMatthias Ringwald get_hfp_ag_indicators(context)[i].max_range); 2623deb3ec6SMatthias Ringwald } 2633deb3ec6SMatthias Ringwald return offset; 2643deb3ec6SMatthias Ringwald } 2653deb3ec6SMatthias Ringwald 2663deb3ec6SMatthias Ringwald static int hfp_hf_indicators_join(char * buffer, int buffer_size){ 2673deb3ec6SMatthias Ringwald if (buffer_size < hfp_ag_indicators_nr * 3) return 0; 2683deb3ec6SMatthias Ringwald int i; 2693deb3ec6SMatthias Ringwald int offset = 0; 2703deb3ec6SMatthias Ringwald for (i = 0; i < get_hfp_generic_status_indicators_nr()-1; i++) { 2713deb3ec6SMatthias Ringwald offset += snprintf(buffer+offset, buffer_size-offset, "%d,", get_hfp_generic_status_indicators()[i].uuid); 2723deb3ec6SMatthias Ringwald } 2733deb3ec6SMatthias Ringwald if (i < get_hfp_generic_status_indicators_nr()){ 2743deb3ec6SMatthias Ringwald offset += snprintf(buffer+offset, buffer_size-offset, "%d,", get_hfp_generic_status_indicators()[i].uuid); 2753deb3ec6SMatthias Ringwald } 2763deb3ec6SMatthias Ringwald return offset; 2773deb3ec6SMatthias Ringwald } 2783deb3ec6SMatthias Ringwald 2793deb3ec6SMatthias Ringwald static int hfp_hf_indicators_initial_status_join(char * buffer, int buffer_size){ 2803deb3ec6SMatthias Ringwald if (buffer_size < get_hfp_generic_status_indicators_nr() * 3) return 0; 2813deb3ec6SMatthias Ringwald int i; 2823deb3ec6SMatthias Ringwald int offset = 0; 2833deb3ec6SMatthias Ringwald for (i = 0; i < get_hfp_generic_status_indicators_nr(); i++) { 2843deb3ec6SMatthias 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); 2853deb3ec6SMatthias Ringwald } 2863deb3ec6SMatthias Ringwald return offset; 2873deb3ec6SMatthias Ringwald } 2883deb3ec6SMatthias Ringwald 2893deb3ec6SMatthias Ringwald static int hfp_ag_indicators_status_join(char * buffer, int buffer_size){ 2903deb3ec6SMatthias Ringwald if (buffer_size < hfp_ag_indicators_nr * 3) return 0; 2913deb3ec6SMatthias Ringwald int i; 2923deb3ec6SMatthias Ringwald int offset = 0; 2933deb3ec6SMatthias Ringwald for (i = 0; i < hfp_ag_indicators_nr-1; i++) { 2943deb3ec6SMatthias Ringwald offset += snprintf(buffer+offset, buffer_size-offset, "%d,", hfp_ag_indicators[i].status); 2953deb3ec6SMatthias Ringwald } 2963deb3ec6SMatthias Ringwald if (i<hfp_ag_indicators_nr){ 2973deb3ec6SMatthias Ringwald offset += snprintf(buffer+offset, buffer_size-offset, "%d", hfp_ag_indicators[i].status); 2983deb3ec6SMatthias Ringwald } 2993deb3ec6SMatthias Ringwald return offset; 3003deb3ec6SMatthias Ringwald } 3013deb3ec6SMatthias Ringwald 3023deb3ec6SMatthias Ringwald static int hfp_ag_call_services_join(char * buffer, int buffer_size){ 3033deb3ec6SMatthias Ringwald if (buffer_size < hfp_ag_call_hold_services_nr * 3) return 0; 3043deb3ec6SMatthias Ringwald int i; 3053deb3ec6SMatthias Ringwald int offset = snprintf(buffer, buffer_size, "("); 3063deb3ec6SMatthias Ringwald for (i = 0; i < hfp_ag_call_hold_services_nr-1; i++) { 3073deb3ec6SMatthias Ringwald offset += snprintf(buffer+offset, buffer_size-offset, "%s,", hfp_ag_call_hold_services[i]); 3083deb3ec6SMatthias Ringwald } 3093deb3ec6SMatthias Ringwald if (i<hfp_ag_call_hold_services_nr){ 3103deb3ec6SMatthias Ringwald offset += snprintf(buffer+offset, buffer_size-offset, "%s)", hfp_ag_call_hold_services[i]); 3113deb3ec6SMatthias Ringwald } 3123deb3ec6SMatthias Ringwald return offset; 3133deb3ec6SMatthias Ringwald } 3143deb3ec6SMatthias Ringwald 3153deb3ec6SMatthias Ringwald static int hfp_ag_retrieve_indicators_cmd(uint16_t cid, hfp_connection_t * context){ 3163deb3ec6SMatthias Ringwald char buffer[250]; 3173deb3ec6SMatthias Ringwald int offset = snprintf(buffer, sizeof(buffer), "\r\n%s:", HFP_INDICATOR); 3183deb3ec6SMatthias Ringwald offset += hfp_ag_indicators_join(buffer+offset, sizeof(buffer)-offset, context); 3193deb3ec6SMatthias Ringwald 3203deb3ec6SMatthias Ringwald buffer[offset] = 0; 3213deb3ec6SMatthias Ringwald 3223deb3ec6SMatthias Ringwald offset += snprintf(buffer+offset, sizeof(buffer)-offset, "\r\n\r\nOK\r\n"); 3233deb3ec6SMatthias Ringwald buffer[offset] = 0; 3243deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 3253deb3ec6SMatthias Ringwald } 3263deb3ec6SMatthias Ringwald 3273deb3ec6SMatthias Ringwald static int hfp_ag_retrieve_indicators_status_cmd(uint16_t cid){ 3283deb3ec6SMatthias Ringwald char buffer[40]; 3293deb3ec6SMatthias Ringwald int offset = snprintf(buffer, sizeof(buffer), "\r\n%s:", HFP_INDICATOR); 3303deb3ec6SMatthias Ringwald offset += hfp_ag_indicators_status_join(buffer+offset, sizeof(buffer)-offset); 3313deb3ec6SMatthias Ringwald 3323deb3ec6SMatthias Ringwald buffer[offset] = 0; 3333deb3ec6SMatthias Ringwald 3343deb3ec6SMatthias Ringwald offset += snprintf(buffer+offset, sizeof(buffer)-offset, "\r\n\r\nOK\r\n"); 3353deb3ec6SMatthias Ringwald buffer[offset] = 0; 3363deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 3373deb3ec6SMatthias Ringwald } 3383deb3ec6SMatthias Ringwald 3393deb3ec6SMatthias Ringwald static int hfp_ag_set_indicator_status_update_cmd(uint16_t cid, uint8_t activate){ 3403deb3ec6SMatthias Ringwald // AT\r\n%s:3,0,0,%d\r\n 3413deb3ec6SMatthias Ringwald return hfp_ag_ok(cid); 3423deb3ec6SMatthias Ringwald } 3433deb3ec6SMatthias Ringwald 3443deb3ec6SMatthias Ringwald 3453deb3ec6SMatthias Ringwald static int hfp_ag_retrieve_can_hold_call_cmd(uint16_t cid){ 3463deb3ec6SMatthias Ringwald char buffer[100]; 3473deb3ec6SMatthias Ringwald int offset = snprintf(buffer, sizeof(buffer), "\r\n%s:", HFP_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES); 3483deb3ec6SMatthias Ringwald offset += hfp_ag_call_services_join(buffer+offset, sizeof(buffer)-offset); 3493deb3ec6SMatthias Ringwald 3503deb3ec6SMatthias Ringwald buffer[offset] = 0; 3513deb3ec6SMatthias Ringwald 3523deb3ec6SMatthias Ringwald offset += snprintf(buffer+offset, sizeof(buffer)-offset, "\r\n\r\nOK\r\n"); 3533deb3ec6SMatthias Ringwald buffer[offset] = 0; 3543deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 3553deb3ec6SMatthias Ringwald } 3563deb3ec6SMatthias Ringwald 3573deb3ec6SMatthias Ringwald 3583deb3ec6SMatthias Ringwald static int hfp_ag_list_supported_generic_status_indicators_cmd(uint16_t cid){ 3593deb3ec6SMatthias Ringwald return hfp_ag_ok(cid); 3603deb3ec6SMatthias Ringwald } 3613deb3ec6SMatthias Ringwald 3623deb3ec6SMatthias Ringwald static int hfp_ag_retrieve_supported_generic_status_indicators_cmd(uint16_t cid){ 3633deb3ec6SMatthias Ringwald char buffer[40]; 364*aa4dd815SMatthias Ringwald int offset = snprintf(buffer, sizeof(buffer), "\r\n%s:(", HFP_GENERIC_STATUS_INDICATOR); 3653deb3ec6SMatthias Ringwald offset += hfp_hf_indicators_join(buffer+offset, sizeof(buffer)-offset); 3663deb3ec6SMatthias Ringwald 3673deb3ec6SMatthias Ringwald buffer[offset] = 0; 3683deb3ec6SMatthias Ringwald 369*aa4dd815SMatthias Ringwald offset += snprintf(buffer+offset, sizeof(buffer)-offset, ")\r\n\r\nOK\r\n"); 3703deb3ec6SMatthias Ringwald buffer[offset] = 0; 3713deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 3723deb3ec6SMatthias Ringwald } 3733deb3ec6SMatthias Ringwald 3743deb3ec6SMatthias Ringwald static int hfp_ag_retrieve_initital_supported_generic_status_indicators_cmd(uint16_t cid){ 3753deb3ec6SMatthias Ringwald char buffer[40]; 3763deb3ec6SMatthias Ringwald int offset = hfp_hf_indicators_initial_status_join(buffer, sizeof(buffer)); 3773deb3ec6SMatthias Ringwald 3783deb3ec6SMatthias Ringwald buffer[offset] = 0; 3793deb3ec6SMatthias Ringwald offset += snprintf(buffer+offset, sizeof(buffer)-offset, "\r\nOK\r\n"); 3803deb3ec6SMatthias Ringwald buffer[offset] = 0; 3813deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 3823deb3ec6SMatthias Ringwald } 3833deb3ec6SMatthias Ringwald 384*aa4dd815SMatthias Ringwald static int hfp_ag_transfer_ag_indicators_status_cmd(uint16_t cid, hfp_ag_indicator_t * indicator){ 3853deb3ec6SMatthias Ringwald char buffer[20]; 386*aa4dd815SMatthias Ringwald sprintf(buffer, "\r\n%s:%d,%d\r\n", HFP_TRANSFER_AG_INDICATOR_STATUS, indicator->index, indicator->status); 3873deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 3883deb3ec6SMatthias Ringwald } 3893deb3ec6SMatthias Ringwald 3903deb3ec6SMatthias Ringwald static int hfp_ag_report_network_operator_name_cmd(uint16_t cid, hfp_network_opearator_t op){ 3913deb3ec6SMatthias Ringwald char buffer[40]; 3923deb3ec6SMatthias Ringwald if (strlen(op.name) == 0){ 3933deb3ec6SMatthias Ringwald sprintf(buffer, "\r\n%s:%d,,\r\n\r\nOK\r\n", HFP_QUERY_OPERATOR_SELECTION, op.mode); 3943deb3ec6SMatthias Ringwald } else { 3953deb3ec6SMatthias 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); 3963deb3ec6SMatthias Ringwald } 3973deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 3983deb3ec6SMatthias Ringwald } 3993deb3ec6SMatthias Ringwald 4003deb3ec6SMatthias Ringwald 4013deb3ec6SMatthias Ringwald static int hfp_ag_cmd_suggest_codec(uint16_t cid, uint8_t codec){ 4023deb3ec6SMatthias Ringwald char buffer[30]; 4033deb3ec6SMatthias Ringwald sprintf(buffer, "\r\n%s:%d\r\n", HFP_CONFIRM_COMMON_CODEC, codec); 4043deb3ec6SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 4053deb3ec6SMatthias Ringwald } 4063deb3ec6SMatthias Ringwald 407*aa4dd815SMatthias Ringwald static int hfp_ag_activate_voice_recognition_cmd(uint16_t cid, uint8_t activate_voice_recognition){ 408*aa4dd815SMatthias Ringwald char buffer[30]; 409*aa4dd815SMatthias Ringwald sprintf(buffer, "\r\n%s: %d\r\n", HFP_ACTIVATE_VOICE_RECOGNITION, activate_voice_recognition); 410*aa4dd815SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 411*aa4dd815SMatthias Ringwald } 412*aa4dd815SMatthias Ringwald 413*aa4dd815SMatthias Ringwald static int hfp_ag_set_speaker_gain_cmd(uint16_t cid, uint8_t gain){ 414*aa4dd815SMatthias Ringwald char buffer[30]; 415*aa4dd815SMatthias Ringwald sprintf(buffer, "\r\n%s:%d\r\n", HFP_SET_SPEAKER_GAIN, gain); 416*aa4dd815SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 417*aa4dd815SMatthias Ringwald } 418*aa4dd815SMatthias Ringwald 419*aa4dd815SMatthias Ringwald static int hfp_ag_set_microphone_gain_cmd(uint16_t cid, uint8_t gain){ 420*aa4dd815SMatthias Ringwald char buffer[30]; 421*aa4dd815SMatthias Ringwald sprintf(buffer, "\r\n%s:%d\r\n", HFP_SET_MICROPHONE_GAIN, gain); 422*aa4dd815SMatthias Ringwald return send_str_over_rfcomm(cid, buffer); 423*aa4dd815SMatthias Ringwald } 424*aa4dd815SMatthias Ringwald 425*aa4dd815SMatthias Ringwald 4263deb3ec6SMatthias Ringwald static uint8_t hfp_ag_suggest_codec(hfp_connection_t *context){ 4273deb3ec6SMatthias Ringwald int i,j; 428*aa4dd815SMatthias Ringwald uint8_t codec = HFP_CODEC_CVSD; 4293deb3ec6SMatthias Ringwald for (i = 0; i < hfp_codecs_nr; i++){ 4303deb3ec6SMatthias Ringwald for (j = 0; j < context->remote_codecs_nr; j++){ 4313deb3ec6SMatthias Ringwald if (context->remote_codecs[j] == hfp_codecs[i]){ 4323deb3ec6SMatthias Ringwald codec = context->remote_codecs[j]; 4333deb3ec6SMatthias Ringwald continue; 4343deb3ec6SMatthias Ringwald } 4353deb3ec6SMatthias Ringwald } 4363deb3ec6SMatthias Ringwald } 4373deb3ec6SMatthias Ringwald return codec; 4383deb3ec6SMatthias Ringwald } 4393deb3ec6SMatthias Ringwald 440*aa4dd815SMatthias Ringwald static int codecs_exchange_state_machine(hfp_connection_t * context){ 441*aa4dd815SMatthias Ringwald /* events ( == commands): 442*aa4dd815SMatthias Ringwald HFP_CMD_AVAILABLE_CODECS == received AT+BAC with list of codecs 443*aa4dd815SMatthias Ringwald HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP: 444*aa4dd815SMatthias Ringwald hf_trigger_codec_connection_setup == received BCC 445*aa4dd815SMatthias Ringwald ag_trigger_codec_connection_setup == received from AG to send BCS 446*aa4dd815SMatthias Ringwald HFP_CMD_HF_CONFIRMED_CODEC == received AT+BCS 447*aa4dd815SMatthias Ringwald */ 448*aa4dd815SMatthias Ringwald 449*aa4dd815SMatthias Ringwald switch (context->codecs_state){ 450*aa4dd815SMatthias Ringwald case HFP_CODECS_RECEIVED_TRIGGER_CODEC_EXCHANGE: 451*aa4dd815SMatthias Ringwald context->command = HFP_CMD_AG_SEND_COMMON_CODEC; 452*aa4dd815SMatthias Ringwald break; 453*aa4dd815SMatthias Ringwald case HFP_CODECS_AG_RESEND_COMMON_CODEC: 454*aa4dd815SMatthias Ringwald context->command = HFP_CMD_AG_SEND_COMMON_CODEC; 455*aa4dd815SMatthias Ringwald break; 456*aa4dd815SMatthias Ringwald default: 457*aa4dd815SMatthias Ringwald break; 458*aa4dd815SMatthias Ringwald } 459*aa4dd815SMatthias Ringwald 460*aa4dd815SMatthias Ringwald // printf(" -> State machine: CC\n"); 461*aa4dd815SMatthias Ringwald 462*aa4dd815SMatthias Ringwald switch (context->command){ 463*aa4dd815SMatthias Ringwald case HFP_CMD_AVAILABLE_CODECS: 464*aa4dd815SMatthias Ringwald //printf("HFP_CODECS_RECEIVED_LIST \n"); 465*aa4dd815SMatthias Ringwald if (context->state < HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED){ 466*aa4dd815SMatthias Ringwald context->codecs_state = HFP_CODECS_RECEIVED_LIST; 467*aa4dd815SMatthias Ringwald hfp_ag_ok(context->rfcomm_cid); 468*aa4dd815SMatthias Ringwald return 1; 469*aa4dd815SMatthias Ringwald } 470*aa4dd815SMatthias Ringwald 471*aa4dd815SMatthias Ringwald switch (context->codecs_state){ 472*aa4dd815SMatthias Ringwald case HFP_CODECS_AG_SENT_COMMON_CODEC: 473*aa4dd815SMatthias Ringwald case HFP_CODECS_EXCHANGED: 474*aa4dd815SMatthias Ringwald context->codecs_state = HFP_CODECS_AG_RESEND_COMMON_CODEC; 475*aa4dd815SMatthias Ringwald break; 476*aa4dd815SMatthias Ringwald default: 477*aa4dd815SMatthias Ringwald break; 478*aa4dd815SMatthias Ringwald } 479*aa4dd815SMatthias Ringwald hfp_ag_ok(context->rfcomm_cid); 480*aa4dd815SMatthias Ringwald return 1; 481*aa4dd815SMatthias Ringwald 482*aa4dd815SMatthias Ringwald case HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP: 483*aa4dd815SMatthias Ringwald //printf(" HFP_CMD_TRIGGER_CODEC_CONNECTION_SETUP \n"); 484*aa4dd815SMatthias Ringwald context->codecs_state = HFP_CODECS_RECEIVED_TRIGGER_CODEC_EXCHANGE; 485*aa4dd815SMatthias Ringwald hfp_ag_ok(context->rfcomm_cid); 486*aa4dd815SMatthias Ringwald return 1; 487*aa4dd815SMatthias Ringwald 488*aa4dd815SMatthias Ringwald case HFP_CMD_AG_SEND_COMMON_CODEC: 489*aa4dd815SMatthias Ringwald //printf(" HFP_CMD_AG_SEND_COMMON_CODEC \n"); 490*aa4dd815SMatthias Ringwald context->codecs_state = HFP_CODECS_AG_SENT_COMMON_CODEC; 491*aa4dd815SMatthias Ringwald context->suggested_codec = hfp_ag_suggest_codec(context); 492*aa4dd815SMatthias Ringwald hfp_ag_cmd_suggest_codec(context->rfcomm_cid, context->suggested_codec); 493*aa4dd815SMatthias Ringwald return 1; 494*aa4dd815SMatthias Ringwald 495*aa4dd815SMatthias Ringwald case HFP_CMD_HF_CONFIRMED_CODEC: 496*aa4dd815SMatthias Ringwald //printf("HFP_CMD_HF_CONFIRMED_CODEC \n"); 497*aa4dd815SMatthias Ringwald if (context->codec_confirmed != context->suggested_codec){ 498*aa4dd815SMatthias Ringwald context->codecs_state = HFP_CODECS_ERROR; 499*aa4dd815SMatthias Ringwald hfp_ag_error(context->rfcomm_cid); 500*aa4dd815SMatthias Ringwald return 1; 501*aa4dd815SMatthias Ringwald } 502*aa4dd815SMatthias Ringwald context->negotiated_codec = context->codec_confirmed; 503*aa4dd815SMatthias Ringwald context->codecs_state = HFP_CODECS_EXCHANGED; 504*aa4dd815SMatthias Ringwald hfp_emit_event(hfp_callback, HFP_SUBEVENT_CODECS_CONNECTION_COMPLETE, 0); 505*aa4dd815SMatthias Ringwald hfp_ag_ok(context->rfcomm_cid); 506*aa4dd815SMatthias Ringwald return 1; 507*aa4dd815SMatthias Ringwald default: 508*aa4dd815SMatthias Ringwald break; 509*aa4dd815SMatthias Ringwald } 510*aa4dd815SMatthias Ringwald return 0; 511*aa4dd815SMatthias Ringwald } 512*aa4dd815SMatthias Ringwald 513*aa4dd815SMatthias Ringwald static void hfp_ag_slc_established(hfp_connection_t * context){ 514*aa4dd815SMatthias Ringwald context->state = HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED; 515*aa4dd815SMatthias Ringwald hfp_emit_event(hfp_callback, HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED, 0); 516*aa4dd815SMatthias Ringwald 517*aa4dd815SMatthias Ringwald // if active call exist, set per-connection state active, too (when audio is on) 518*aa4dd815SMatthias Ringwald if (hfp_ag_call_state == HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT){ 519*aa4dd815SMatthias Ringwald context->call_state = HFP_CALL_W4_AUDIO_CONNECTION_FOR_ACTIVE; 520*aa4dd815SMatthias Ringwald } 521*aa4dd815SMatthias Ringwald } 5223deb3ec6SMatthias Ringwald 5233deb3ec6SMatthias Ringwald static int hfp_ag_run_for_context_service_level_connection(hfp_connection_t * context){ 524*aa4dd815SMatthias Ringwald if (context->state >= HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return 0; 5253deb3ec6SMatthias Ringwald int done = 0; 526*aa4dd815SMatthias Ringwald // printf(" -> State machine: SLC\n"); 5273deb3ec6SMatthias Ringwald switch(context->command){ 5283deb3ec6SMatthias Ringwald case HFP_CMD_SUPPORTED_FEATURES: 5293deb3ec6SMatthias Ringwald switch(context->state){ 5303deb3ec6SMatthias Ringwald case HFP_W4_EXCHANGE_SUPPORTED_FEATURES: 531*aa4dd815SMatthias Ringwald case HFP_EXCHANGE_SUPPORTED_FEATURES: 5323deb3ec6SMatthias Ringwald if (has_codec_negotiation_feature(context)){ 5333deb3ec6SMatthias Ringwald context->state = HFP_W4_NOTIFY_ON_CODECS; 534*aa4dd815SMatthias Ringwald } else { 5353deb3ec6SMatthias Ringwald context->state = HFP_W4_RETRIEVE_INDICATORS; 536*aa4dd815SMatthias Ringwald } 537*aa4dd815SMatthias Ringwald hfp_ag_exchange_supported_features_cmd(context->rfcomm_cid); 538*aa4dd815SMatthias Ringwald return 1; 5393deb3ec6SMatthias Ringwald default: 5403deb3ec6SMatthias Ringwald break; 5413deb3ec6SMatthias Ringwald } 5423deb3ec6SMatthias Ringwald break; 5433deb3ec6SMatthias Ringwald case HFP_CMD_AVAILABLE_CODECS: 544*aa4dd815SMatthias Ringwald done = codecs_exchange_state_machine(context); 5453deb3ec6SMatthias Ringwald 546*aa4dd815SMatthias Ringwald if (context->codecs_state == HFP_CODECS_RECEIVED_LIST){ 547*aa4dd815SMatthias Ringwald context->state = HFP_W4_RETRIEVE_INDICATORS; 5483deb3ec6SMatthias Ringwald } 549*aa4dd815SMatthias Ringwald return done; 550*aa4dd815SMatthias Ringwald 551*aa4dd815SMatthias Ringwald case HFP_CMD_RETRIEVE_AG_INDICATORS: 552*aa4dd815SMatthias Ringwald if (context->state != HFP_W4_RETRIEVE_INDICATORS) break; 5533deb3ec6SMatthias Ringwald context->state = HFP_W4_RETRIEVE_INDICATORS_STATUS; 554*aa4dd815SMatthias Ringwald hfp_ag_retrieve_indicators_cmd(context->rfcomm_cid, context); 555*aa4dd815SMatthias Ringwald return 1; 556*aa4dd815SMatthias Ringwald 557*aa4dd815SMatthias Ringwald case HFP_CMD_RETRIEVE_AG_INDICATORS_STATUS: 558*aa4dd815SMatthias Ringwald if (context->state != HFP_W4_RETRIEVE_INDICATORS_STATUS) break; 5593deb3ec6SMatthias Ringwald context->state = HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE; 560*aa4dd815SMatthias Ringwald hfp_ag_retrieve_indicators_status_cmd(context->rfcomm_cid); 561*aa4dd815SMatthias Ringwald return 1; 562*aa4dd815SMatthias Ringwald 5633deb3ec6SMatthias Ringwald case HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE: 564*aa4dd815SMatthias Ringwald if (context->state != HFP_W4_ENABLE_INDICATORS_STATUS_UPDATE) break; 5653deb3ec6SMatthias Ringwald if (has_call_waiting_and_3way_calling_feature(context)){ 5663deb3ec6SMatthias Ringwald context->state = HFP_W4_RETRIEVE_CAN_HOLD_CALL; 567*aa4dd815SMatthias Ringwald } else if (has_hf_indicators_feature(context)){ 5683deb3ec6SMatthias Ringwald context->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS; 569*aa4dd815SMatthias Ringwald } else { 570*aa4dd815SMatthias Ringwald hfp_ag_slc_established(context); 5713deb3ec6SMatthias Ringwald } 572*aa4dd815SMatthias Ringwald hfp_ag_set_indicator_status_update_cmd(context->rfcomm_cid, 1); 573*aa4dd815SMatthias Ringwald return 1; 5743deb3ec6SMatthias Ringwald 575*aa4dd815SMatthias Ringwald case HFP_CMD_SUPPORT_CALL_HOLD_AND_MULTIPARTY_SERVICES: 576*aa4dd815SMatthias Ringwald if (context->state != HFP_W4_RETRIEVE_CAN_HOLD_CALL) break; 577*aa4dd815SMatthias Ringwald if (has_hf_indicators_feature(context)){ 578*aa4dd815SMatthias Ringwald context->state = HFP_W4_LIST_GENERIC_STATUS_INDICATORS; 579*aa4dd815SMatthias Ringwald } else { 580*aa4dd815SMatthias Ringwald hfp_ag_slc_established(context); 581*aa4dd815SMatthias Ringwald } 582*aa4dd815SMatthias Ringwald hfp_ag_retrieve_can_hold_call_cmd(context->rfcomm_cid); 583*aa4dd815SMatthias Ringwald return 1; 584*aa4dd815SMatthias Ringwald 585*aa4dd815SMatthias Ringwald case HFP_CMD_LIST_GENERIC_STATUS_INDICATORS: 586*aa4dd815SMatthias Ringwald if (context->state != HFP_W4_LIST_GENERIC_STATUS_INDICATORS) break; 587*aa4dd815SMatthias Ringwald context->state = HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS; 588*aa4dd815SMatthias Ringwald hfp_ag_list_supported_generic_status_indicators_cmd(context->rfcomm_cid); 589*aa4dd815SMatthias Ringwald return 1; 590*aa4dd815SMatthias Ringwald 591*aa4dd815SMatthias Ringwald case HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS: 592*aa4dd815SMatthias Ringwald if (context->state != HFP_W4_RETRIEVE_GENERIC_STATUS_INDICATORS) break; 593*aa4dd815SMatthias Ringwald context->state = HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS; 594*aa4dd815SMatthias Ringwald hfp_ag_retrieve_supported_generic_status_indicators_cmd(context->rfcomm_cid); 595*aa4dd815SMatthias Ringwald return 1; 596*aa4dd815SMatthias Ringwald 597*aa4dd815SMatthias Ringwald case HFP_CMD_RETRIEVE_GENERIC_STATUS_INDICATORS_STATE: 598*aa4dd815SMatthias Ringwald if (context->state != HFP_W4_RETRIEVE_INITITAL_STATE_GENERIC_STATUS_INDICATORS) break; 599*aa4dd815SMatthias Ringwald hfp_ag_slc_established(context); 600*aa4dd815SMatthias Ringwald hfp_ag_retrieve_initital_supported_generic_status_indicators_cmd(context->rfcomm_cid); 601*aa4dd815SMatthias Ringwald return 1; 6023deb3ec6SMatthias Ringwald default: 6033deb3ec6SMatthias Ringwald break; 6043deb3ec6SMatthias Ringwald } 6053deb3ec6SMatthias Ringwald return done; 6063deb3ec6SMatthias Ringwald } 6073deb3ec6SMatthias Ringwald 6083deb3ec6SMatthias Ringwald static int hfp_ag_run_for_context_service_level_connection_queries(hfp_connection_t * context){ 609*aa4dd815SMatthias Ringwald // if (context->state != HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED) return 0; 6103deb3ec6SMatthias Ringwald 611*aa4dd815SMatthias Ringwald int done = codecs_exchange_state_machine(context); 612*aa4dd815SMatthias Ringwald if (done) return done; 613*aa4dd815SMatthias Ringwald 614*aa4dd815SMatthias Ringwald // printf(" -> State machine: SLC Queries\n"); 6153deb3ec6SMatthias Ringwald switch(context->command){ 616*aa4dd815SMatthias Ringwald case HFP_CMD_AG_ACTIVATE_VOICE_RECOGNITION: 617*aa4dd815SMatthias Ringwald hfp_supported_features = store_bit(hfp_supported_features, HFP_AGSF_VOICE_RECOGNITION_FUNCTION, context->ag_activate_voice_recognition); 618*aa4dd815SMatthias Ringwald hfp_ag_activate_voice_recognition_cmd(context->rfcomm_cid, context->ag_activate_voice_recognition); 619*aa4dd815SMatthias Ringwald return 1; 620*aa4dd815SMatthias Ringwald case HFP_CMD_HF_ACTIVATE_VOICE_RECOGNITION: 621*aa4dd815SMatthias Ringwald if (get_bit(hfp_supported_features, HFP_AGSF_VOICE_RECOGNITION_FUNCTION)){ 622*aa4dd815SMatthias Ringwald hfp_supported_features = store_bit(hfp_supported_features, HFP_AGSF_VOICE_RECOGNITION_FUNCTION, context->ag_activate_voice_recognition); 6233deb3ec6SMatthias Ringwald hfp_ag_ok(context->rfcomm_cid); 624*aa4dd815SMatthias Ringwald hfp_ag_setup_audio_connection(context); 625*aa4dd815SMatthias Ringwald } else { 626*aa4dd815SMatthias Ringwald hfp_ag_error(context->rfcomm_cid); 627*aa4dd815SMatthias Ringwald } 628*aa4dd815SMatthias Ringwald return 1; 629*aa4dd815SMatthias Ringwald case HFP_CMD_CHANGE_IN_BAND_RING_TONE_SETTING: 630*aa4dd815SMatthias Ringwald hfp_ag_change_in_band_ring_tone_setting_cmd(context->rfcomm_cid); 631*aa4dd815SMatthias Ringwald return 1; 632*aa4dd815SMatthias Ringwald case HFP_CMD_QUERY_OPERATOR_SELECTION_NAME: 633*aa4dd815SMatthias Ringwald hfp_ag_report_network_operator_name_cmd(context->rfcomm_cid, context->network_operator); 634*aa4dd815SMatthias Ringwald return 1; 635*aa4dd815SMatthias Ringwald case HFP_CMD_QUERY_OPERATOR_SELECTION_NAME_FORMAT: 6363deb3ec6SMatthias Ringwald if (context->network_operator.format != 0){ 6373deb3ec6SMatthias Ringwald hfp_ag_error(context->rfcomm_cid); 638*aa4dd815SMatthias Ringwald } else { 6393deb3ec6SMatthias Ringwald hfp_ag_ok(context->rfcomm_cid); 6403deb3ec6SMatthias Ringwald } 641*aa4dd815SMatthias Ringwald return 1; 642*aa4dd815SMatthias Ringwald case HFP_CMD_ENABLE_INDIVIDUAL_AG_INDICATOR_STATUS_UPDATE: 6433deb3ec6SMatthias Ringwald hfp_ag_ok(context->rfcomm_cid); 644*aa4dd815SMatthias Ringwald return 1; 6453deb3ec6SMatthias Ringwald case HFP_CMD_ENABLE_EXTENDED_AUDIO_GATEWAY_ERROR: 6463deb3ec6SMatthias Ringwald if (context->extended_audio_gateway_error){ 6473deb3ec6SMatthias Ringwald context->extended_audio_gateway_error = 0; 648*aa4dd815SMatthias Ringwald hfp_ag_report_extended_audio_gateway_error(context->rfcomm_cid, context->extended_audio_gateway_error); 649*aa4dd815SMatthias Ringwald return 1; 6503deb3ec6SMatthias Ringwald } 6513deb3ec6SMatthias Ringwald case HFP_CMD_ENABLE_INDICATOR_STATUS_UPDATE: 6523deb3ec6SMatthias Ringwald printf("TODO\n"); 6533deb3ec6SMatthias Ringwald break; 6543deb3ec6SMatthias Ringwald default: 6553deb3ec6SMatthias Ringwald break; 6563deb3ec6SMatthias Ringwald } 657*aa4dd815SMatthias Ringwald return 0; 6583deb3ec6SMatthias Ringwald } 6593deb3ec6SMatthias Ringwald 6603deb3ec6SMatthias Ringwald 661*aa4dd815SMatthias Ringwald static int hfp_ag_run_for_audio_connection(hfp_connection_t * context){ 662*aa4dd815SMatthias Ringwald if (context->state < HFP_SERVICE_LEVEL_CONNECTION_ESTABLISHED || 663*aa4dd815SMatthias Ringwald context->state > HFP_W2_DISCONNECT_SCO) return 0; 6643deb3ec6SMatthias Ringwald 665*aa4dd815SMatthias Ringwald 666*aa4dd815SMatthias Ringwald if (context->state == HFP_AUDIO_CONNECTION_ESTABLISHED && context->release_audio_connection){ 667*aa4dd815SMatthias Ringwald context->state = HFP_W4_SCO_DISCONNECTED; 668*aa4dd815SMatthias Ringwald context->release_audio_connection = 0; 669*aa4dd815SMatthias Ringwald gap_disconnect(context->sco_handle); 670*aa4dd815SMatthias Ringwald return 1; 671*aa4dd815SMatthias Ringwald } 672*aa4dd815SMatthias Ringwald 673*aa4dd815SMatthias Ringwald if (context->state == HFP_AUDIO_CONNECTION_ESTABLISHED) return 0; 674*aa4dd815SMatthias Ringwald 675*aa4dd815SMatthias Ringwald // run codecs exchange 676*aa4dd815SMatthias Ringwald int done = codecs_exchange_state_machine(context); 677*aa4dd815SMatthias Ringwald if (done) return done; 678*aa4dd815SMatthias Ringwald // printf(" -> State machine: Audio Connection\n"); 679*aa4dd815SMatthias Ringwald 680*aa4dd815SMatthias Ringwald if (context->codecs_state != HFP_CODECS_EXCHANGED) return done; 681*aa4dd815SMatthias Ringwald if (context->establish_audio_connection){ 682*aa4dd815SMatthias Ringwald context->state = HFP_W4_SCO_CONNECTED; 683*aa4dd815SMatthias Ringwald context->establish_audio_connection = 0; 684*aa4dd815SMatthias Ringwald hci_send_cmd(&hci_setup_synchronous_connection, context->con_handle, 8000, 8000, 0xFFFF, hci_get_sco_voice_setting(), 0xFF, 0x003F); 685*aa4dd815SMatthias Ringwald return 1; 686*aa4dd815SMatthias Ringwald 687*aa4dd815SMatthias Ringwald } 688*aa4dd815SMatthias Ringwald return 0; 689*aa4dd815SMatthias Ringwald } 690*aa4dd815SMatthias Ringwald 691*aa4dd815SMatthias Ringwald static hfp_connection_t * hfp_ag_context_for_timer(timer_source_t * ts){ 692*aa4dd815SMatthias Ringwald linked_list_iterator_t it; 693*aa4dd815SMatthias Ringwald linked_list_iterator_init(&it, hfp_get_connections()); 694*aa4dd815SMatthias Ringwald 695*aa4dd815SMatthias Ringwald while (linked_list_iterator_has_next(&it)){ 696*aa4dd815SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); 697*aa4dd815SMatthias Ringwald if ( &connection->hfp_timeout == ts) { 698*aa4dd815SMatthias Ringwald return connection; 699*aa4dd815SMatthias Ringwald } 700*aa4dd815SMatthias Ringwald } 701*aa4dd815SMatthias Ringwald return NULL; 702*aa4dd815SMatthias Ringwald } 703*aa4dd815SMatthias Ringwald 704*aa4dd815SMatthias Ringwald static void hfp_timeout_handler(timer_source_t * timer){ 705*aa4dd815SMatthias Ringwald hfp_connection_t * context = hfp_ag_context_for_timer(timer); 706*aa4dd815SMatthias Ringwald if (!context) return; 707*aa4dd815SMatthias Ringwald 708*aa4dd815SMatthias Ringwald log_info("HFP start ring timeout, con handle 0x%02x", context->con_handle); 709*aa4dd815SMatthias Ringwald context->ag_ring = 1; 710*aa4dd815SMatthias Ringwald context->ag_send_clip = clip_type && context->clip_enabled; 711*aa4dd815SMatthias Ringwald 712*aa4dd815SMatthias Ringwald run_loop_set_timer(&context->hfp_timeout, 2000); // 5 seconds timeout 713*aa4dd815SMatthias Ringwald run_loop_add_timer(&context->hfp_timeout); 714*aa4dd815SMatthias Ringwald 715*aa4dd815SMatthias Ringwald hfp_run_for_context(context); 716*aa4dd815SMatthias Ringwald } 717*aa4dd815SMatthias Ringwald 718*aa4dd815SMatthias Ringwald static void hfp_timeout_start(hfp_connection_t * context){ 719*aa4dd815SMatthias Ringwald run_loop_remove_timer(&context->hfp_timeout); 720*aa4dd815SMatthias Ringwald run_loop_set_timer_handler(&context->hfp_timeout, hfp_timeout_handler); 721*aa4dd815SMatthias Ringwald run_loop_set_timer(&context->hfp_timeout, 2000); // 5 seconds timeout 722*aa4dd815SMatthias Ringwald run_loop_add_timer(&context->hfp_timeout); 723*aa4dd815SMatthias Ringwald } 724*aa4dd815SMatthias Ringwald 725*aa4dd815SMatthias Ringwald static void hfp_timeout_stop(hfp_connection_t * context){ 726*aa4dd815SMatthias Ringwald log_info("HFP stop ring timeout, con handle 0x%02x", context->con_handle); 727*aa4dd815SMatthias Ringwald run_loop_remove_timer(&context->hfp_timeout); 728*aa4dd815SMatthias Ringwald } 729*aa4dd815SMatthias Ringwald 730*aa4dd815SMatthias Ringwald // 731*aa4dd815SMatthias Ringwald // transitition implementations for hfp_ag_call_state_machine 732*aa4dd815SMatthias Ringwald // 733*aa4dd815SMatthias Ringwald 734*aa4dd815SMatthias Ringwald static void hfp_ag_hf_start_ringing(hfp_connection_t * context){ 735*aa4dd815SMatthias Ringwald hfp_timeout_start(context); 736*aa4dd815SMatthias Ringwald context->ag_ring = 1; 737*aa4dd815SMatthias Ringwald context->ag_send_clip = clip_type && context->clip_enabled; 738*aa4dd815SMatthias Ringwald if (use_in_band_tone()){ 739*aa4dd815SMatthias Ringwald context->call_state = HFP_CALL_W4_AUDIO_CONNECTION_FOR_IN_BAND_RING; 740*aa4dd815SMatthias Ringwald hfp_ag_establish_audio_connection(context->remote_addr); 741*aa4dd815SMatthias Ringwald } else { 742*aa4dd815SMatthias Ringwald context->call_state = HFP_CALL_RINGING; 743*aa4dd815SMatthias Ringwald hfp_emit_event(hfp_callback, HFP_SUBEVENT_START_RINGINIG, 0); 744*aa4dd815SMatthias Ringwald } 745*aa4dd815SMatthias Ringwald } 746*aa4dd815SMatthias Ringwald 747*aa4dd815SMatthias Ringwald static void hfp_ag_hf_stop_ringing(hfp_connection_t * context){ 748*aa4dd815SMatthias Ringwald context->ag_ring = 0; 749*aa4dd815SMatthias Ringwald context->ag_send_clip = 0; 750*aa4dd815SMatthias Ringwald hfp_timeout_stop(context); 751*aa4dd815SMatthias Ringwald hfp_emit_event(hfp_callback, HFP_SUBEVENT_STOP_RINGINIG, 0); 752*aa4dd815SMatthias Ringwald } 753*aa4dd815SMatthias Ringwald 754*aa4dd815SMatthias Ringwald static void hfp_ag_trigger_incoming_call(void){ 755*aa4dd815SMatthias Ringwald int indicator_index = get_ag_indicator_index_for_name("callsetup"); 756*aa4dd815SMatthias Ringwald if (indicator_index < 0) return; 757*aa4dd815SMatthias Ringwald 758*aa4dd815SMatthias Ringwald linked_list_iterator_t it; 759*aa4dd815SMatthias Ringwald linked_list_iterator_init(&it, hfp_get_connections()); 760*aa4dd815SMatthias Ringwald while (linked_list_iterator_has_next(&it)){ 761*aa4dd815SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); 762*aa4dd815SMatthias Ringwald hfp_ag_establish_service_level_connection(connection->remote_addr); 763*aa4dd815SMatthias Ringwald if (connection->call_state == HFP_CALL_IDLE){ 764*aa4dd815SMatthias Ringwald connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, indicator_index, 1); 765*aa4dd815SMatthias Ringwald hfp_ag_hf_start_ringing(connection); 766*aa4dd815SMatthias Ringwald } 767*aa4dd815SMatthias Ringwald if (connection->call_state == HFP_CALL_ACTIVE){ 768*aa4dd815SMatthias Ringwald connection->call_state = HFP_CALL_W2_SEND_CALL_WAITING; 769*aa4dd815SMatthias Ringwald } 770*aa4dd815SMatthias Ringwald hfp_run_for_context(connection); 771*aa4dd815SMatthias Ringwald } 772*aa4dd815SMatthias Ringwald } 773*aa4dd815SMatthias Ringwald 774*aa4dd815SMatthias Ringwald static void hfp_ag_transfer_callsetup_state(void){ 775*aa4dd815SMatthias Ringwald int indicator_index = get_ag_indicator_index_for_name("callsetup"); 776*aa4dd815SMatthias Ringwald if (indicator_index < 0) return; 777*aa4dd815SMatthias Ringwald 778*aa4dd815SMatthias Ringwald linked_list_iterator_t it; 779*aa4dd815SMatthias Ringwald linked_list_iterator_init(&it, hfp_get_connections()); 780*aa4dd815SMatthias Ringwald while (linked_list_iterator_has_next(&it)){ 781*aa4dd815SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); 782*aa4dd815SMatthias Ringwald hfp_ag_establish_service_level_connection(connection->remote_addr); 783*aa4dd815SMatthias Ringwald connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, indicator_index, 1); 784*aa4dd815SMatthias Ringwald hfp_run_for_context(connection); 785*aa4dd815SMatthias Ringwald } 786*aa4dd815SMatthias Ringwald } 787*aa4dd815SMatthias Ringwald 788*aa4dd815SMatthias Ringwald static void hfp_ag_transfer_call_state(void){ 789*aa4dd815SMatthias Ringwald int indicator_index = get_ag_indicator_index_for_name("call"); 790*aa4dd815SMatthias Ringwald if (indicator_index < 0) return; 791*aa4dd815SMatthias Ringwald 792*aa4dd815SMatthias Ringwald linked_list_iterator_t it; 793*aa4dd815SMatthias Ringwald linked_list_iterator_init(&it, hfp_get_connections()); 794*aa4dd815SMatthias Ringwald while (linked_list_iterator_has_next(&it)){ 795*aa4dd815SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); 796*aa4dd815SMatthias Ringwald hfp_ag_establish_service_level_connection(connection->remote_addr); 797*aa4dd815SMatthias Ringwald connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, indicator_index, 1); 798*aa4dd815SMatthias Ringwald hfp_run_for_context(connection); 799*aa4dd815SMatthias Ringwald } 800*aa4dd815SMatthias Ringwald } 801*aa4dd815SMatthias Ringwald 802*aa4dd815SMatthias Ringwald static void hfp_ag_transfer_callheld_state(void){ 803*aa4dd815SMatthias Ringwald int indicator_index = get_ag_indicator_index_for_name("callheld"); 804*aa4dd815SMatthias Ringwald if (indicator_index < 0) return; 805*aa4dd815SMatthias Ringwald 806*aa4dd815SMatthias Ringwald linked_list_iterator_t it; 807*aa4dd815SMatthias Ringwald linked_list_iterator_init(&it, hfp_get_connections()); 808*aa4dd815SMatthias Ringwald while (linked_list_iterator_has_next(&it)){ 809*aa4dd815SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); 810*aa4dd815SMatthias Ringwald hfp_ag_establish_service_level_connection(connection->remote_addr); 811*aa4dd815SMatthias Ringwald connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, indicator_index, 1); 812*aa4dd815SMatthias Ringwald hfp_run_for_context(connection); 813*aa4dd815SMatthias Ringwald } 814*aa4dd815SMatthias Ringwald } 815*aa4dd815SMatthias Ringwald 816*aa4dd815SMatthias Ringwald static void hfp_ag_hf_accept_call(hfp_connection_t * source){ 817*aa4dd815SMatthias Ringwald 818*aa4dd815SMatthias Ringwald int call_indicator_index = get_ag_indicator_index_for_name("call"); 819*aa4dd815SMatthias Ringwald int callsetup_indicator_index = get_ag_indicator_index_for_name("callsetup"); 820*aa4dd815SMatthias Ringwald 821*aa4dd815SMatthias Ringwald linked_list_iterator_t it; 822*aa4dd815SMatthias Ringwald linked_list_iterator_init(&it, hfp_get_connections()); 823*aa4dd815SMatthias Ringwald while (linked_list_iterator_has_next(&it)){ 824*aa4dd815SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); 825*aa4dd815SMatthias Ringwald if (connection->call_state != HFP_CALL_RINGING && 826*aa4dd815SMatthias Ringwald connection->call_state != HFP_CALL_W4_AUDIO_CONNECTION_FOR_IN_BAND_RING) continue; 827*aa4dd815SMatthias Ringwald 828*aa4dd815SMatthias Ringwald hfp_ag_hf_stop_ringing(connection); 829*aa4dd815SMatthias Ringwald if (connection == source){ 830*aa4dd815SMatthias Ringwald connection->ok_pending = 1; 831*aa4dd815SMatthias Ringwald 832*aa4dd815SMatthias Ringwald if (use_in_band_tone()){ 833*aa4dd815SMatthias Ringwald connection->call_state = HFP_CALL_ACTIVE; 834*aa4dd815SMatthias Ringwald } else { 835*aa4dd815SMatthias Ringwald connection->call_state = HFP_CALL_W4_AUDIO_CONNECTION_FOR_ACTIVE; 836*aa4dd815SMatthias Ringwald hfp_ag_establish_audio_connection(connection->remote_addr); 837*aa4dd815SMatthias Ringwald } 838*aa4dd815SMatthias Ringwald 839*aa4dd815SMatthias Ringwald connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, call_indicator_index, 1); 840*aa4dd815SMatthias Ringwald connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1); 841*aa4dd815SMatthias Ringwald 842*aa4dd815SMatthias Ringwald } else { 843*aa4dd815SMatthias Ringwald connection->call_state = HFP_CALL_IDLE; 844*aa4dd815SMatthias Ringwald } 845*aa4dd815SMatthias Ringwald hfp_run_for_context(connection); 846*aa4dd815SMatthias Ringwald } 847*aa4dd815SMatthias Ringwald } 848*aa4dd815SMatthias Ringwald 849*aa4dd815SMatthias Ringwald static void hfp_ag_ag_accept_call(void){ 850*aa4dd815SMatthias Ringwald 851*aa4dd815SMatthias Ringwald int call_indicator_index = get_ag_indicator_index_for_name("call"); 852*aa4dd815SMatthias Ringwald int callsetup_indicator_index = get_ag_indicator_index_for_name("callsetup"); 853*aa4dd815SMatthias Ringwald 854*aa4dd815SMatthias Ringwald linked_list_iterator_t it; 855*aa4dd815SMatthias Ringwald linked_list_iterator_init(&it, hfp_get_connections()); 856*aa4dd815SMatthias Ringwald while (linked_list_iterator_has_next(&it)){ 857*aa4dd815SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); 858*aa4dd815SMatthias Ringwald if (connection->call_state != HFP_CALL_RINGING) continue; 859*aa4dd815SMatthias Ringwald 860*aa4dd815SMatthias Ringwald hfp_ag_hf_stop_ringing(connection); 861*aa4dd815SMatthias Ringwald connection->call_state = HFP_CALL_TRIGGER_AUDIO_CONNECTION; 862*aa4dd815SMatthias Ringwald 863*aa4dd815SMatthias Ringwald connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, call_indicator_index, 1); 864*aa4dd815SMatthias Ringwald connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1); 865*aa4dd815SMatthias Ringwald 866*aa4dd815SMatthias Ringwald hfp_run_for_context(connection); 867*aa4dd815SMatthias Ringwald break; // only single 868*aa4dd815SMatthias Ringwald } 869*aa4dd815SMatthias Ringwald } 870*aa4dd815SMatthias Ringwald 871*aa4dd815SMatthias Ringwald static void hfp_ag_trigger_reject_call(void){ 872*aa4dd815SMatthias Ringwald int callsetup_indicator_index = get_ag_indicator_index_for_name("callsetup"); 873*aa4dd815SMatthias Ringwald linked_list_iterator_t it; 874*aa4dd815SMatthias Ringwald linked_list_iterator_init(&it, hfp_get_connections()); 875*aa4dd815SMatthias Ringwald while (linked_list_iterator_has_next(&it)){ 876*aa4dd815SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); 877*aa4dd815SMatthias Ringwald if (connection->call_state != HFP_CALL_RINGING && 878*aa4dd815SMatthias Ringwald connection->call_state != HFP_CALL_W4_AUDIO_CONNECTION_FOR_IN_BAND_RING) continue; 879*aa4dd815SMatthias Ringwald hfp_ag_hf_stop_ringing(connection); 880*aa4dd815SMatthias Ringwald connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1); 881*aa4dd815SMatthias Ringwald connection->call_state = HFP_CALL_IDLE; 882*aa4dd815SMatthias Ringwald hfp_run_for_context(connection); 883*aa4dd815SMatthias Ringwald } 884*aa4dd815SMatthias Ringwald } 885*aa4dd815SMatthias Ringwald 886*aa4dd815SMatthias Ringwald static void hfp_ag_trigger_terminate_call(void){ 887*aa4dd815SMatthias Ringwald int call_indicator_index = get_ag_indicator_index_for_name("call"); 888*aa4dd815SMatthias Ringwald 889*aa4dd815SMatthias Ringwald linked_list_iterator_t it; 890*aa4dd815SMatthias Ringwald linked_list_iterator_init(&it, hfp_get_connections()); 891*aa4dd815SMatthias Ringwald while (linked_list_iterator_has_next(&it)){ 892*aa4dd815SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); 893*aa4dd815SMatthias Ringwald hfp_ag_establish_service_level_connection(connection->remote_addr); 894*aa4dd815SMatthias Ringwald if (connection->call_state == HFP_CALL_IDLE) continue; 895*aa4dd815SMatthias Ringwald connection->call_state = HFP_CALL_IDLE; 896*aa4dd815SMatthias Ringwald connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, call_indicator_index, 1); 897*aa4dd815SMatthias Ringwald hfp_run_for_context(connection); 898*aa4dd815SMatthias Ringwald } 899*aa4dd815SMatthias Ringwald hfp_emit_event(hfp_callback, HFP_SUBEVENT_CALL_TERMINATED, 0); 900*aa4dd815SMatthias Ringwald } 901*aa4dd815SMatthias Ringwald 902*aa4dd815SMatthias Ringwald static void hfp_ag_set_callsetup_state(hfp_callsetup_status_t state){ 903*aa4dd815SMatthias Ringwald hfp_ag_callsetup_state = state; 904*aa4dd815SMatthias Ringwald hfp_ag_indicator_t * indicator = get_ag_indicator_for_name("callsetup"); 905*aa4dd815SMatthias Ringwald if (!indicator){ 906*aa4dd815SMatthias Ringwald log_error("hfp_ag_set_callsetup_state: callsetup indicator is missing"); 907*aa4dd815SMatthias Ringwald }; 908*aa4dd815SMatthias Ringwald indicator->status = state; 909*aa4dd815SMatthias Ringwald } 910*aa4dd815SMatthias Ringwald 911*aa4dd815SMatthias Ringwald static void hfp_ag_set_callheld_state(hfp_callheld_status_t state){ 912*aa4dd815SMatthias Ringwald hfp_ag_callheld_state = state; 913*aa4dd815SMatthias Ringwald hfp_ag_indicator_t * indicator = get_ag_indicator_for_name("callheld"); 914*aa4dd815SMatthias Ringwald if (!indicator){ 915*aa4dd815SMatthias Ringwald log_error("hfp_ag_set_callheld_state: callheld indicator is missing"); 916*aa4dd815SMatthias Ringwald }; 917*aa4dd815SMatthias Ringwald indicator->status = state; 918*aa4dd815SMatthias Ringwald } 919*aa4dd815SMatthias Ringwald 920*aa4dd815SMatthias Ringwald static void hfp_ag_set_call_state(hfp_call_status_t state){ 921*aa4dd815SMatthias Ringwald hfp_ag_call_state = state; 922*aa4dd815SMatthias Ringwald hfp_ag_indicator_t * indicator = get_ag_indicator_for_name("call"); 923*aa4dd815SMatthias Ringwald if (!indicator){ 924*aa4dd815SMatthias Ringwald log_error("hfp_ag_set_call_state: call indicator is missing"); 925*aa4dd815SMatthias Ringwald }; 926*aa4dd815SMatthias Ringwald indicator->status = state; 927*aa4dd815SMatthias Ringwald } 928*aa4dd815SMatthias Ringwald 929*aa4dd815SMatthias Ringwald static void hfp_ag_stop_ringing(void){ 930*aa4dd815SMatthias Ringwald linked_list_iterator_t it; 931*aa4dd815SMatthias Ringwald linked_list_iterator_init(&it, hfp_get_connections()); 932*aa4dd815SMatthias Ringwald while (linked_list_iterator_has_next(&it)){ 933*aa4dd815SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); 934*aa4dd815SMatthias Ringwald if (connection->call_state != HFP_CALL_RINGING && 935*aa4dd815SMatthias Ringwald connection->call_state != HFP_CALL_W4_AUDIO_CONNECTION_FOR_IN_BAND_RING) continue; 936*aa4dd815SMatthias Ringwald hfp_ag_hf_stop_ringing(connection); 937*aa4dd815SMatthias Ringwald } 938*aa4dd815SMatthias Ringwald } 939*aa4dd815SMatthias Ringwald 940*aa4dd815SMatthias Ringwald static hfp_connection_t * hfp_ag_connection_for_call_state(hfp_call_state_t call_state){ 941*aa4dd815SMatthias Ringwald linked_list_iterator_t it; 942*aa4dd815SMatthias Ringwald linked_list_iterator_init(&it, hfp_get_connections()); 943*aa4dd815SMatthias Ringwald while (linked_list_iterator_has_next(&it)){ 944*aa4dd815SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); 945*aa4dd815SMatthias Ringwald if (connection->call_state == call_state) return connection; 946*aa4dd815SMatthias Ringwald } 947*aa4dd815SMatthias Ringwald return NULL; 948*aa4dd815SMatthias Ringwald } 949*aa4dd815SMatthias Ringwald 950*aa4dd815SMatthias Ringwald static int call_setup_state_machine(hfp_connection_t * connection){ 951*aa4dd815SMatthias Ringwald int indicator_index; 952*aa4dd815SMatthias Ringwald switch (connection->call_state){ 953*aa4dd815SMatthias Ringwald case HFP_CALL_W4_AUDIO_CONNECTION_FOR_IN_BAND_RING: 954*aa4dd815SMatthias Ringwald if (connection->state != HFP_AUDIO_CONNECTION_ESTABLISHED) return 0; 955*aa4dd815SMatthias Ringwald // we got event: audio connection established 956*aa4dd815SMatthias Ringwald connection->call_state = HFP_CALL_RINGING; 957*aa4dd815SMatthias Ringwald hfp_emit_event(hfp_callback, HFP_SUBEVENT_START_RINGINIG, 0); 958*aa4dd815SMatthias Ringwald break; 959*aa4dd815SMatthias Ringwald case HFP_CALL_W4_AUDIO_CONNECTION_FOR_ACTIVE: 960*aa4dd815SMatthias Ringwald if (connection->state != HFP_AUDIO_CONNECTION_ESTABLISHED) return 0; 961*aa4dd815SMatthias Ringwald // we got event: audio connection established 962*aa4dd815SMatthias Ringwald connection->call_state = HFP_CALL_ACTIVE; 963*aa4dd815SMatthias Ringwald break; 964*aa4dd815SMatthias Ringwald case HFP_CALL_W2_SEND_CALL_WAITING: 965*aa4dd815SMatthias Ringwald connection->call_state = HFP_CALL_W4_CHLD; 966*aa4dd815SMatthias Ringwald hfp_ag_send_call_waiting_notification(connection->rfcomm_cid); 967*aa4dd815SMatthias Ringwald indicator_index = get_ag_indicator_index_for_name("callsetup"); 968*aa4dd815SMatthias Ringwald connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, indicator_index, 1); 969*aa4dd815SMatthias Ringwald break; 970*aa4dd815SMatthias Ringwald default: 971*aa4dd815SMatthias Ringwald break; 972*aa4dd815SMatthias Ringwald } 973*aa4dd815SMatthias Ringwald return 0; 974*aa4dd815SMatthias Ringwald } 975*aa4dd815SMatthias Ringwald // connection is used to identify originating HF 976*aa4dd815SMatthias Ringwald static void hfp_ag_call_sm(hfp_ag_call_event_t event, hfp_connection_t * connection){ 977*aa4dd815SMatthias Ringwald int indicator_index; 978*aa4dd815SMatthias Ringwald switch (event){ 979*aa4dd815SMatthias Ringwald case HFP_AG_INCOMING_CALL: 980*aa4dd815SMatthias Ringwald switch (hfp_ag_call_state){ 981*aa4dd815SMatthias Ringwald case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: 982*aa4dd815SMatthias Ringwald switch (hfp_ag_callsetup_state){ 983*aa4dd815SMatthias Ringwald case HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS: 984*aa4dd815SMatthias Ringwald hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS); 985*aa4dd815SMatthias Ringwald hfp_ag_trigger_incoming_call(); 986*aa4dd815SMatthias Ringwald printf("AG rings\n"); 987*aa4dd815SMatthias Ringwald break; 988*aa4dd815SMatthias Ringwald default: 9893deb3ec6SMatthias Ringwald break; 9903deb3ec6SMatthias Ringwald } 9913deb3ec6SMatthias Ringwald break; 992*aa4dd815SMatthias Ringwald case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT: 993*aa4dd815SMatthias Ringwald switch (hfp_ag_callsetup_state){ 994*aa4dd815SMatthias Ringwald case HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS: 995*aa4dd815SMatthias Ringwald hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS); 996*aa4dd815SMatthias Ringwald hfp_ag_trigger_incoming_call(); 997*aa4dd815SMatthias Ringwald printf("AG call waiting\n"); 998*aa4dd815SMatthias Ringwald break; 999*aa4dd815SMatthias Ringwald default: 10003deb3ec6SMatthias Ringwald break; 10013deb3ec6SMatthias Ringwald } 10023deb3ec6SMatthias Ringwald break; 1003*aa4dd815SMatthias Ringwald } 1004*aa4dd815SMatthias Ringwald break; 1005*aa4dd815SMatthias Ringwald case HFP_AG_INCOMING_CALL_ACCEPTED_BY_AG: 1006*aa4dd815SMatthias Ringwald // clear CLIP 1007*aa4dd815SMatthias Ringwald clip_type = 0; 1008*aa4dd815SMatthias Ringwald switch (hfp_ag_call_state){ 1009*aa4dd815SMatthias Ringwald case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: 1010*aa4dd815SMatthias Ringwald switch (hfp_ag_callsetup_state){ 1011*aa4dd815SMatthias Ringwald case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS: 1012*aa4dd815SMatthias Ringwald hfp_ag_set_call_state(HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT); 1013*aa4dd815SMatthias Ringwald hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 1014*aa4dd815SMatthias Ringwald hfp_ag_ag_accept_call(); 1015*aa4dd815SMatthias Ringwald printf("AG answers call, accept call by GSM\n"); 1016*aa4dd815SMatthias Ringwald break; 1017*aa4dd815SMatthias Ringwald default: 10183deb3ec6SMatthias Ringwald break; 10193deb3ec6SMatthias Ringwald } 1020*aa4dd815SMatthias Ringwald break; 1021*aa4dd815SMatthias Ringwald case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT: 1022*aa4dd815SMatthias Ringwald switch (hfp_ag_callsetup_state){ 1023*aa4dd815SMatthias Ringwald case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS: 1024*aa4dd815SMatthias Ringwald printf("AG: current call is placed on hold, incoming call gets active\n"); 1025*aa4dd815SMatthias Ringwald hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 1026*aa4dd815SMatthias Ringwald hfp_ag_set_callheld_state(HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED); 1027*aa4dd815SMatthias Ringwald // TODO: update AG indicators for all connections 1028*aa4dd815SMatthias Ringwald // context->ag_indicators_status_update_bitmap = store_bit(context->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1); 1029*aa4dd815SMatthias Ringwald // context->ag_indicators_status_update_bitmap = store_bit(context->ag_indicators_status_update_bitmap, callheld_indicator_index, 1); 1030*aa4dd815SMatthias Ringwald // context->call_state = HFP_CALL_ACTIVE; 1031*aa4dd815SMatthias Ringwald break; 1032*aa4dd815SMatthias Ringwald default: 1033*aa4dd815SMatthias Ringwald break; 1034*aa4dd815SMatthias Ringwald } 1035*aa4dd815SMatthias Ringwald break; 1036*aa4dd815SMatthias Ringwald } 1037*aa4dd815SMatthias Ringwald break; 1038*aa4dd815SMatthias Ringwald case HFP_AG_INCOMING_CALL_ACCEPTED_BY_HF: 1039*aa4dd815SMatthias Ringwald // clear CLIP 1040*aa4dd815SMatthias Ringwald clip_type = 0; 1041*aa4dd815SMatthias Ringwald switch (hfp_ag_call_state){ 1042*aa4dd815SMatthias Ringwald case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: 1043*aa4dd815SMatthias Ringwald switch (hfp_ag_callsetup_state){ 1044*aa4dd815SMatthias Ringwald case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS: 1045*aa4dd815SMatthias Ringwald hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 1046*aa4dd815SMatthias Ringwald hfp_ag_set_call_state(HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT); 1047*aa4dd815SMatthias Ringwald hfp_ag_hf_accept_call(connection); 1048*aa4dd815SMatthias Ringwald printf("HF answers call, accept call by GSM\n"); 1049*aa4dd815SMatthias Ringwald break; 1050*aa4dd815SMatthias Ringwald default: 1051*aa4dd815SMatthias Ringwald break; 1052*aa4dd815SMatthias Ringwald } 10533deb3ec6SMatthias Ringwald break; 10543deb3ec6SMatthias Ringwald default: 10553deb3ec6SMatthias Ringwald break; 10563deb3ec6SMatthias Ringwald } 10573deb3ec6SMatthias Ringwald break; 10583deb3ec6SMatthias Ringwald 1059*aa4dd815SMatthias Ringwald case HFP_AG_TERMINATE_CALL_BY_HF: 1060*aa4dd815SMatthias Ringwald // clear CLIP 1061*aa4dd815SMatthias Ringwald clip_type = 0; 1062*aa4dd815SMatthias Ringwald switch (hfp_ag_call_state){ 1063*aa4dd815SMatthias Ringwald case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: 1064*aa4dd815SMatthias Ringwald switch (hfp_ag_callsetup_state){ 1065*aa4dd815SMatthias Ringwald case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS: 1066*aa4dd815SMatthias Ringwald hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 1067*aa4dd815SMatthias Ringwald hfp_ag_transfer_callsetup_state(); 1068*aa4dd815SMatthias Ringwald hfp_ag_trigger_reject_call(); 1069*aa4dd815SMatthias Ringwald printf("HF Rejected Incoming call, AG terminate call\n"); 1070*aa4dd815SMatthias Ringwald break; 1071*aa4dd815SMatthias Ringwald case HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_DIALING_STATE: 1072*aa4dd815SMatthias Ringwald case HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_ALERTING_STATE: 1073*aa4dd815SMatthias Ringwald hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 1074*aa4dd815SMatthias Ringwald hfp_ag_transfer_callsetup_state(); 1075*aa4dd815SMatthias Ringwald printf("AG terminate outgoing call process\n"); 1076*aa4dd815SMatthias Ringwald default: 1077*aa4dd815SMatthias Ringwald break; 1078*aa4dd815SMatthias Ringwald } 1079*aa4dd815SMatthias Ringwald break; 1080*aa4dd815SMatthias Ringwald case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT: 1081*aa4dd815SMatthias Ringwald hfp_ag_set_call_state(HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS); 1082*aa4dd815SMatthias Ringwald hfp_ag_transfer_call_state(); 1083*aa4dd815SMatthias Ringwald printf("AG terminate call\n"); 1084*aa4dd815SMatthias Ringwald break; 1085*aa4dd815SMatthias Ringwald } 1086*aa4dd815SMatthias Ringwald break; 10873deb3ec6SMatthias Ringwald 1088*aa4dd815SMatthias Ringwald case HFP_AG_TERMINATE_CALL_BY_AG: 1089*aa4dd815SMatthias Ringwald // clear CLIP 1090*aa4dd815SMatthias Ringwald clip_type = 0; 1091*aa4dd815SMatthias Ringwald switch (hfp_ag_call_state){ 1092*aa4dd815SMatthias Ringwald case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: 1093*aa4dd815SMatthias Ringwald switch (hfp_ag_callsetup_state){ 1094*aa4dd815SMatthias Ringwald case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS: 1095*aa4dd815SMatthias Ringwald hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 1096*aa4dd815SMatthias Ringwald hfp_ag_trigger_reject_call(); 1097*aa4dd815SMatthias Ringwald printf("AG Rejected Incoming call, AG terminate call\n"); 1098*aa4dd815SMatthias Ringwald break; 1099*aa4dd815SMatthias Ringwald default: 1100*aa4dd815SMatthias Ringwald break; 11013deb3ec6SMatthias Ringwald } 1102*aa4dd815SMatthias Ringwald case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT: 1103*aa4dd815SMatthias Ringwald hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 1104*aa4dd815SMatthias Ringwald hfp_ag_set_call_state(HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS); 1105*aa4dd815SMatthias Ringwald hfp_ag_trigger_terminate_call(); 1106*aa4dd815SMatthias Ringwald printf("AG terminate call\n"); 1107*aa4dd815SMatthias Ringwald break; 1108*aa4dd815SMatthias Ringwald default: 11093deb3ec6SMatthias Ringwald break; 11103deb3ec6SMatthias Ringwald } 11113deb3ec6SMatthias Ringwald break; 1112*aa4dd815SMatthias Ringwald case HFP_AG_CALL_DROPPED: 1113*aa4dd815SMatthias Ringwald // clear CLIP 1114*aa4dd815SMatthias Ringwald clip_type = 0; 1115*aa4dd815SMatthias Ringwald switch (hfp_ag_call_state){ 1116*aa4dd815SMatthias Ringwald case HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS: 1117*aa4dd815SMatthias Ringwald switch (hfp_ag_callsetup_state){ 1118*aa4dd815SMatthias Ringwald case HFP_CALLSETUP_STATUS_INCOMING_CALL_SETUP_IN_PROGRESS: 1119*aa4dd815SMatthias Ringwald hfp_ag_stop_ringing(); 1120*aa4dd815SMatthias Ringwald printf("Incoming call interrupted\n"); 1121*aa4dd815SMatthias Ringwald break; 1122*aa4dd815SMatthias Ringwald case HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_DIALING_STATE: 1123*aa4dd815SMatthias Ringwald case HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_ALERTING_STATE: 1124*aa4dd815SMatthias Ringwald printf("Outgoing call interrupted\n"); 1125*aa4dd815SMatthias Ringwald printf("AG notify call dropped\n"); 1126*aa4dd815SMatthias Ringwald break; 1127*aa4dd815SMatthias Ringwald default: 11283deb3ec6SMatthias Ringwald break; 11293deb3ec6SMatthias Ringwald } 1130*aa4dd815SMatthias Ringwald hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 1131*aa4dd815SMatthias Ringwald hfp_ag_transfer_callsetup_state(); 1132*aa4dd815SMatthias Ringwald break; 1133*aa4dd815SMatthias Ringwald case HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT: 1134*aa4dd815SMatthias Ringwald hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 1135*aa4dd815SMatthias Ringwald hfp_ag_set_call_state(HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS); 1136*aa4dd815SMatthias Ringwald hfp_ag_trigger_terminate_call(); 1137*aa4dd815SMatthias Ringwald printf("AG notify call dropped\n"); 1138*aa4dd815SMatthias Ringwald break; 1139*aa4dd815SMatthias Ringwald default: 1140*aa4dd815SMatthias Ringwald break; 1141*aa4dd815SMatthias Ringwald } 1142*aa4dd815SMatthias Ringwald break; 1143*aa4dd815SMatthias Ringwald 1144*aa4dd815SMatthias Ringwald case HFP_AG_OUTGOING_CALL_INITIATED: 1145*aa4dd815SMatthias Ringwald connection->call_state = HFP_CALL_OUTGOING_INITIATED; 1146*aa4dd815SMatthias Ringwald hfp_emit_string_event(hfp_callback, HFP_SUBEVENT_PLACE_CALL_WITH_NUMBER, (const char *) &connection->line_buffer[3]); 1147*aa4dd815SMatthias Ringwald break; 1148*aa4dd815SMatthias Ringwald 1149*aa4dd815SMatthias Ringwald case HFP_AG_OUTGOING_REDIAL_INITIATED: 1150*aa4dd815SMatthias Ringwald connection->call_state = HFP_CALL_OUTGOING_INITIATED; 1151*aa4dd815SMatthias Ringwald hfp_emit_event(hfp_callback, HFP_SUBEVENT_REDIAL_LAST_NUMBER, 0); 1152*aa4dd815SMatthias Ringwald break; 1153*aa4dd815SMatthias Ringwald 1154*aa4dd815SMatthias Ringwald case HFP_AG_OUTGOING_CALL_REJECTED: 1155*aa4dd815SMatthias Ringwald connection = hfp_ag_connection_for_call_state(HFP_CALL_OUTGOING_INITIATED); 1156*aa4dd815SMatthias Ringwald if (!connection){ 1157*aa4dd815SMatthias Ringwald log_info("hfp_ag_call_sm: did not find outgoing connection in initiated state"); 1158*aa4dd815SMatthias Ringwald break; 1159*aa4dd815SMatthias Ringwald } 1160*aa4dd815SMatthias Ringwald connection->call_state = HFP_CALL_IDLE; 1161*aa4dd815SMatthias Ringwald connection->send_error = 1; 1162*aa4dd815SMatthias Ringwald hfp_run_for_context(connection); 1163*aa4dd815SMatthias Ringwald break; 1164*aa4dd815SMatthias Ringwald 1165*aa4dd815SMatthias Ringwald case HFP_AG_OUTGOING_CALL_ACCEPTED: 1166*aa4dd815SMatthias Ringwald connection = hfp_ag_connection_for_call_state(HFP_CALL_OUTGOING_INITIATED); 1167*aa4dd815SMatthias Ringwald if (!connection){ 1168*aa4dd815SMatthias Ringwald log_info("hfp_ag_call_sm: did not find outgoing connection in initiated state"); 1169*aa4dd815SMatthias Ringwald break; 1170*aa4dd815SMatthias Ringwald } 1171*aa4dd815SMatthias Ringwald 1172*aa4dd815SMatthias Ringwald connection->ok_pending = 1; 1173*aa4dd815SMatthias Ringwald connection->call_state = HFP_CALL_OUTGOING_DIALING; 1174*aa4dd815SMatthias Ringwald 1175*aa4dd815SMatthias Ringwald // trigger callsetup to be 1176*aa4dd815SMatthias Ringwald hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_DIALING_STATE); 1177*aa4dd815SMatthias Ringwald indicator_index = get_ag_indicator_index_for_name("callsetup"); 1178*aa4dd815SMatthias Ringwald connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, indicator_index, 1); 1179*aa4dd815SMatthias Ringwald 1180*aa4dd815SMatthias Ringwald // put current call on hold if active 1181*aa4dd815SMatthias Ringwald if (hfp_ag_call_state == HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT){ 1182*aa4dd815SMatthias Ringwald printf("AG putting current call on hold for new outgoing call\n"); 1183*aa4dd815SMatthias Ringwald hfp_ag_set_callheld_state(HFP_CALLHELD_STATUS_CALL_ON_HOLD_AND_NO_ACTIVE_CALLS); 1184*aa4dd815SMatthias Ringwald indicator_index = get_ag_indicator_index_for_name("callheld"); 1185*aa4dd815SMatthias Ringwald hfp_ag_transfer_ag_indicators_status_cmd(connection->rfcomm_cid, &hfp_ag_indicators[indicator_index]); 1186*aa4dd815SMatthias Ringwald } 1187*aa4dd815SMatthias Ringwald 1188*aa4dd815SMatthias Ringwald // start audio if needed 1189*aa4dd815SMatthias Ringwald hfp_ag_establish_audio_connection(connection->remote_addr); 1190*aa4dd815SMatthias Ringwald break; 1191*aa4dd815SMatthias Ringwald 1192*aa4dd815SMatthias Ringwald case HFP_AG_OUTGOING_CALL_RINGING: 1193*aa4dd815SMatthias Ringwald connection = hfp_ag_connection_for_call_state(HFP_CALL_OUTGOING_DIALING); 1194*aa4dd815SMatthias Ringwald if (!connection){ 1195*aa4dd815SMatthias Ringwald log_info("hfp_ag_call_sm: did not find outgoing connection in dialing state"); 1196*aa4dd815SMatthias Ringwald break; 1197*aa4dd815SMatthias Ringwald } 1198*aa4dd815SMatthias Ringwald connection->call_state = HFP_CALL_OUTGOING_RINGING; 1199*aa4dd815SMatthias Ringwald hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_OUTGOING_CALL_SETUP_IN_ALERTING_STATE); 1200*aa4dd815SMatthias Ringwald hfp_ag_transfer_callsetup_state(); 1201*aa4dd815SMatthias Ringwald break; 1202*aa4dd815SMatthias Ringwald 1203*aa4dd815SMatthias Ringwald case HFP_AG_OUTGOING_CALL_ESTABLISHED: 1204*aa4dd815SMatthias Ringwald // get outgoing call 1205*aa4dd815SMatthias Ringwald connection = hfp_ag_connection_for_call_state(HFP_CALL_OUTGOING_RINGING); 1206*aa4dd815SMatthias Ringwald if (!connection){ 1207*aa4dd815SMatthias Ringwald connection = hfp_ag_connection_for_call_state(HFP_CALL_OUTGOING_DIALING); 1208*aa4dd815SMatthias Ringwald } 1209*aa4dd815SMatthias Ringwald if (!connection){ 1210*aa4dd815SMatthias Ringwald log_info("hfp_ag_call_sm: did not find outgoing connection"); 1211*aa4dd815SMatthias Ringwald break; 1212*aa4dd815SMatthias Ringwald } 1213*aa4dd815SMatthias Ringwald connection->call_state = HFP_CALL_ACTIVE; 1214*aa4dd815SMatthias Ringwald hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 1215*aa4dd815SMatthias Ringwald hfp_ag_set_call_state(HFP_CALL_STATUS_ACTIVE_OR_HELD_CALL_IS_PRESENT); 1216*aa4dd815SMatthias Ringwald hfp_ag_transfer_call_state(); 1217*aa4dd815SMatthias Ringwald hfp_ag_transfer_callsetup_state(); 1218*aa4dd815SMatthias Ringwald if (hfp_ag_callheld_state == HFP_CALLHELD_STATUS_CALL_ON_HOLD_AND_NO_ACTIVE_CALLS){ 1219*aa4dd815SMatthias Ringwald hfp_ag_set_callheld_state(HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED); 1220*aa4dd815SMatthias Ringwald hfp_ag_transfer_callheld_state(); 12213deb3ec6SMatthias Ringwald } 12223deb3ec6SMatthias Ringwald break; 12233deb3ec6SMatthias Ringwald default: 12243deb3ec6SMatthias Ringwald break; 12253deb3ec6SMatthias Ringwald } 12263deb3ec6SMatthias Ringwald } 12273deb3ec6SMatthias Ringwald 12283deb3ec6SMatthias Ringwald static void hfp_run_for_context(hfp_connection_t *context){ 12293deb3ec6SMatthias Ringwald if (!context) return; 12303deb3ec6SMatthias Ringwald if (!rfcomm_can_send_packet_now(context->rfcomm_cid)) return; 12313deb3ec6SMatthias Ringwald 1232*aa4dd815SMatthias Ringwald if (context->command == HFP_CMD_UNKNOWN){ 1233*aa4dd815SMatthias Ringwald context->ok_pending = 0; 1234*aa4dd815SMatthias Ringwald context->send_error = 0; 12353deb3ec6SMatthias Ringwald context->command = HFP_CMD_NONE; 1236*aa4dd815SMatthias Ringwald hfp_ag_error(context->rfcomm_cid); 1237*aa4dd815SMatthias Ringwald return; 1238*aa4dd815SMatthias Ringwald } 1239*aa4dd815SMatthias Ringwald 1240*aa4dd815SMatthias Ringwald if (context->ok_pending){ 1241*aa4dd815SMatthias Ringwald context->ok_pending = 0; 1242*aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1243*aa4dd815SMatthias Ringwald hfp_ag_ok(context->rfcomm_cid); 12443deb3ec6SMatthias Ringwald return; 12453deb3ec6SMatthias Ringwald } 12463deb3ec6SMatthias Ringwald 12473deb3ec6SMatthias Ringwald if (context->send_error){ 12483deb3ec6SMatthias Ringwald context->send_error = 0; 12493deb3ec6SMatthias Ringwald context->command = HFP_CMD_NONE; 1250*aa4dd815SMatthias Ringwald hfp_ag_error(context->rfcomm_cid); 1251*aa4dd815SMatthias Ringwald return; 1252*aa4dd815SMatthias Ringwald } 1253*aa4dd815SMatthias Ringwald 1254*aa4dd815SMatthias Ringwald // update AG indicators 1255*aa4dd815SMatthias Ringwald if (context->ag_indicators_status_update_bitmap){ 1256*aa4dd815SMatthias Ringwald int i; 1257*aa4dd815SMatthias Ringwald for (i=0;i<context->ag_indicators_nr;i++){ 1258*aa4dd815SMatthias Ringwald if (get_bit(context->ag_indicators_status_update_bitmap, i)){ 1259*aa4dd815SMatthias Ringwald context->ag_indicators_status_update_bitmap = store_bit(context->ag_indicators_status_update_bitmap, i, 0); 1260*aa4dd815SMatthias Ringwald hfp_ag_transfer_ag_indicators_status_cmd(context->rfcomm_cid, &hfp_ag_indicators[i]); 1261*aa4dd815SMatthias Ringwald return; 1262*aa4dd815SMatthias Ringwald } 1263*aa4dd815SMatthias Ringwald } 1264*aa4dd815SMatthias Ringwald } 1265*aa4dd815SMatthias Ringwald 1266*aa4dd815SMatthias Ringwald if (context->ag_ring){ 1267*aa4dd815SMatthias Ringwald context->ag_ring = 0; 1268*aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1269*aa4dd815SMatthias Ringwald hfp_ag_ring(context->rfcomm_cid); 1270*aa4dd815SMatthias Ringwald return; 1271*aa4dd815SMatthias Ringwald } 1272*aa4dd815SMatthias Ringwald 1273*aa4dd815SMatthias Ringwald if (context->ag_send_clip){ 1274*aa4dd815SMatthias Ringwald context->ag_send_clip = 0; 1275*aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1276*aa4dd815SMatthias Ringwald hfp_ag_send_clip(context->rfcomm_cid); 1277*aa4dd815SMatthias Ringwald return; 1278*aa4dd815SMatthias Ringwald } 1279*aa4dd815SMatthias Ringwald 1280*aa4dd815SMatthias Ringwald if (context->send_phone_number_for_voice_tag){ 1281*aa4dd815SMatthias Ringwald context->send_phone_number_for_voice_tag = 0; 1282*aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1283*aa4dd815SMatthias Ringwald context->ok_pending = 1; 1284*aa4dd815SMatthias Ringwald hfp_ag_send_phone_number_for_voice_tag(context->rfcomm_cid); 1285*aa4dd815SMatthias Ringwald return; 1286*aa4dd815SMatthias Ringwald } 1287*aa4dd815SMatthias Ringwald 1288*aa4dd815SMatthias Ringwald if (context->send_microphone_gain){ 1289*aa4dd815SMatthias Ringwald context->send_microphone_gain = 0; 1290*aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1291*aa4dd815SMatthias Ringwald hfp_ag_set_microphone_gain_cmd(context->rfcomm_cid, context->microphone_gain); 1292*aa4dd815SMatthias Ringwald return; 1293*aa4dd815SMatthias Ringwald } 1294*aa4dd815SMatthias Ringwald 1295*aa4dd815SMatthias Ringwald if (context->send_speaker_gain){ 1296*aa4dd815SMatthias Ringwald context->send_speaker_gain = 0; 1297*aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1298*aa4dd815SMatthias Ringwald hfp_ag_set_speaker_gain_cmd(context->rfcomm_cid, context->speaker_gain); 12993deb3ec6SMatthias Ringwald return; 13003deb3ec6SMatthias Ringwald } 13013deb3ec6SMatthias Ringwald 13023deb3ec6SMatthias Ringwald int done = hfp_ag_run_for_context_service_level_connection(context); 1303*aa4dd815SMatthias Ringwald if (!done){ 13043deb3ec6SMatthias Ringwald done = hfp_ag_run_for_context_service_level_connection_queries(context); 13053deb3ec6SMatthias Ringwald } 13063deb3ec6SMatthias Ringwald 1307*aa4dd815SMatthias Ringwald if (!done){ 1308*aa4dd815SMatthias Ringwald done = call_setup_state_machine(context); 1309*aa4dd815SMatthias Ringwald } 1310*aa4dd815SMatthias Ringwald 1311*aa4dd815SMatthias Ringwald if (!done){ 1312*aa4dd815SMatthias Ringwald done = hfp_ag_run_for_audio_connection(context); 1313*aa4dd815SMatthias Ringwald } 13143deb3ec6SMatthias Ringwald 13153deb3ec6SMatthias Ringwald if (context->command == HFP_CMD_NONE && !done){ 1316*aa4dd815SMatthias Ringwald // log_info("context->command == HFP_CMD_NONE"); 13173deb3ec6SMatthias Ringwald switch(context->state){ 13183deb3ec6SMatthias Ringwald case HFP_W2_DISCONNECT_RFCOMM: 13193deb3ec6SMatthias Ringwald context->state = HFP_W4_RFCOMM_DISCONNECTED; 13203deb3ec6SMatthias Ringwald rfcomm_disconnect_internal(context->rfcomm_cid); 13213deb3ec6SMatthias Ringwald break; 13223deb3ec6SMatthias Ringwald default: 13233deb3ec6SMatthias Ringwald break; 13243deb3ec6SMatthias Ringwald } 13253deb3ec6SMatthias Ringwald } 13263deb3ec6SMatthias Ringwald if (done){ 13273deb3ec6SMatthias Ringwald context->command = HFP_CMD_NONE; 13283deb3ec6SMatthias Ringwald } 13293deb3ec6SMatthias Ringwald } 13303deb3ec6SMatthias Ringwald 1331*aa4dd815SMatthias Ringwald static void hfp_handle_rfcomm_data(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 13323deb3ec6SMatthias Ringwald hfp_connection_t * context = get_hfp_connection_context_for_rfcomm_cid(channel); 13333deb3ec6SMatthias Ringwald if (!context) return; 13343deb3ec6SMatthias Ringwald int pos; 13353deb3ec6SMatthias Ringwald for (pos = 0; pos < size ; pos++){ 1336*aa4dd815SMatthias Ringwald hfp_parse(context, packet[pos], 0); 1337*aa4dd815SMatthias Ringwald } 1338*aa4dd815SMatthias Ringwald switch(context->command){ 1339*aa4dd815SMatthias Ringwald case HFP_CMD_HF_REQUEST_PHONE_NUMBER: 1340*aa4dd815SMatthias Ringwald hfp_emit_event(hfp_callback, HFP_SUBEVENT_ATTACH_NUMBER_TO_VOICE_TAG, 0); 1341*aa4dd815SMatthias Ringwald break; 13423deb3ec6SMatthias Ringwald 1343*aa4dd815SMatthias Ringwald case HFP_CMD_TURN_OFF_EC_AND_NR: 1344*aa4dd815SMatthias Ringwald if (get_bit(hfp_supported_features, HFP_AGSF_EC_NR_FUNCTION)){ 1345*aa4dd815SMatthias Ringwald context->ok_pending = 1; 1346*aa4dd815SMatthias Ringwald hfp_supported_features = store_bit(hfp_supported_features, HFP_AGSF_EC_NR_FUNCTION, context->ag_echo_and_noise_reduction); 1347*aa4dd815SMatthias Ringwald printf("AG: EC/NR = %u\n", context->ag_echo_and_noise_reduction); 1348*aa4dd815SMatthias Ringwald } else { 1349*aa4dd815SMatthias Ringwald context->send_error = 1; 1350*aa4dd815SMatthias Ringwald } 1351*aa4dd815SMatthias Ringwald break; 1352*aa4dd815SMatthias Ringwald case HFP_CMD_CALL_ANSWERED: 1353*aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1354*aa4dd815SMatthias Ringwald printf("HFP: ATA\n"); 1355*aa4dd815SMatthias Ringwald hfp_ag_call_sm(HFP_AG_INCOMING_CALL_ACCEPTED_BY_HF, context); 1356*aa4dd815SMatthias Ringwald break; 1357*aa4dd815SMatthias Ringwald case HFP_CMD_HANG_UP_CALL: 1358*aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1359*aa4dd815SMatthias Ringwald context->ok_pending = 1; 1360*aa4dd815SMatthias Ringwald hfp_ag_call_sm(HFP_AG_TERMINATE_CALL_BY_HF, context); 1361*aa4dd815SMatthias Ringwald break; 1362*aa4dd815SMatthias Ringwald case HFP_CMD_CALL_HOLD: { 1363*aa4dd815SMatthias Ringwald // TODO: fully implement this 1364*aa4dd815SMatthias Ringwald log_error("HFP: unhandled call hold type %c", context->line_buffer[0]); 1365*aa4dd815SMatthias Ringwald int callsetup_indicator_index = get_ag_indicator_index_for_name("callsetup"); 1366*aa4dd815SMatthias Ringwald int callheld_indicator_index = get_ag_indicator_index_for_name("callheld"); 1367*aa4dd815SMatthias Ringwald int call_indicator_index = get_ag_indicator_index_for_name("call"); 1368*aa4dd815SMatthias Ringwald switch (context->line_buffer[0]){ 1369*aa4dd815SMatthias Ringwald case '0': 1370*aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1371*aa4dd815SMatthias Ringwald context->ok_pending = 1; 1372*aa4dd815SMatthias Ringwald hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 1373*aa4dd815SMatthias Ringwald context->ag_indicators_status_update_bitmap = store_bit(context->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1); 1374*aa4dd815SMatthias Ringwald context->call_state = HFP_CALL_ACTIVE; 1375*aa4dd815SMatthias Ringwald printf("AG: Call Waiting, User Busy\n"); 1376*aa4dd815SMatthias Ringwald break; 1377*aa4dd815SMatthias Ringwald case '1': 1378*aa4dd815SMatthias Ringwald // Releases all active calls (if any exist) and accepts the other (held or waiting) call. 1379*aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1380*aa4dd815SMatthias Ringwald context->ok_pending = 1; 1381*aa4dd815SMatthias Ringwald if (hfp_ag_callsetup_state != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS){ 1382*aa4dd815SMatthias Ringwald printf("AG: Call Dropped, Accept new call\n"); 1383*aa4dd815SMatthias Ringwald hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 1384*aa4dd815SMatthias Ringwald context->ag_indicators_status_update_bitmap = store_bit(context->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1); 1385*aa4dd815SMatthias Ringwald } else { 1386*aa4dd815SMatthias Ringwald printf("AG: Call Dropped, Resume held call\n"); 1387*aa4dd815SMatthias Ringwald } 1388*aa4dd815SMatthias Ringwald if (hfp_ag_callheld_state != HFP_CALLHELD_STATUS_NO_CALLS_HELD){ 1389*aa4dd815SMatthias Ringwald hfp_ag_set_callheld_state(HFP_CALLHELD_STATUS_NO_CALLS_HELD); 1390*aa4dd815SMatthias Ringwald context->ag_indicators_status_update_bitmap = store_bit(context->ag_indicators_status_update_bitmap, callheld_indicator_index, 1); 1391*aa4dd815SMatthias Ringwald } 1392*aa4dd815SMatthias Ringwald context->call_state = HFP_CALL_ACTIVE; 1393*aa4dd815SMatthias Ringwald break; 1394*aa4dd815SMatthias Ringwald case '2': 1395*aa4dd815SMatthias Ringwald // Places all active calls (if any exist) on hold and accepts the other (held or waiting) call. 1396*aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1397*aa4dd815SMatthias Ringwald context->ok_pending = 1; 1398*aa4dd815SMatthias Ringwald // only update if callsetup changed 1399*aa4dd815SMatthias Ringwald if (hfp_ag_callsetup_state != HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS){ 1400*aa4dd815SMatthias Ringwald printf("AG: Call on Hold, Accept new call\n"); 1401*aa4dd815SMatthias Ringwald hfp_ag_set_callsetup_state(HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS); 1402*aa4dd815SMatthias Ringwald context->ag_indicators_status_update_bitmap = store_bit(context->ag_indicators_status_update_bitmap, callsetup_indicator_index, 1); 1403*aa4dd815SMatthias Ringwald } else { 1404*aa4dd815SMatthias Ringwald printf("AG: Swap calls\n"); 1405*aa4dd815SMatthias Ringwald } 1406*aa4dd815SMatthias Ringwald hfp_ag_set_callheld_state(HFP_CALLHELD_STATUS_CALL_ON_HOLD_OR_SWAPPED); 1407*aa4dd815SMatthias Ringwald context->ag_indicators_status_update_bitmap = store_bit(context->ag_indicators_status_update_bitmap, callheld_indicator_index, 1); 1408*aa4dd815SMatthias Ringwald context->call_state = HFP_CALL_ACTIVE; 1409*aa4dd815SMatthias Ringwald break; 1410*aa4dd815SMatthias Ringwald case '3': 1411*aa4dd815SMatthias Ringwald // Adds a held call to the conversation. 1412*aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1413*aa4dd815SMatthias Ringwald context->ok_pending = 1; 1414*aa4dd815SMatthias Ringwald if (hfp_ag_callheld_state != HFP_CALLHELD_STATUS_NO_CALLS_HELD){ 1415*aa4dd815SMatthias Ringwald printf("AG: Join 3-way-call\n"); 1416*aa4dd815SMatthias Ringwald hfp_ag_set_callheld_state(HFP_CALLHELD_STATUS_NO_CALLS_HELD); 1417*aa4dd815SMatthias Ringwald context->ag_indicators_status_update_bitmap = store_bit(context->ag_indicators_status_update_bitmap, callheld_indicator_index, 1); 1418*aa4dd815SMatthias Ringwald } 1419*aa4dd815SMatthias Ringwald context->call_state = HFP_CALL_ACTIVE; 1420*aa4dd815SMatthias Ringwald break; 1421*aa4dd815SMatthias Ringwald case '4': 1422*aa4dd815SMatthias Ringwald // Connects the two calls and disconnects the subscriber from both calls (Explicit Call Transfer) 1423*aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1424*aa4dd815SMatthias Ringwald context->ok_pending = 1; 1425*aa4dd815SMatthias Ringwald printf("AG: Transfer call -> Connect two calls and disconnect\n"); 1426*aa4dd815SMatthias Ringwald hfp_ag_set_call_state(HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS); 1427*aa4dd815SMatthias Ringwald hfp_ag_set_callheld_state(HFP_CALLHELD_STATUS_NO_CALLS_HELD); 1428*aa4dd815SMatthias Ringwald context->ag_indicators_status_update_bitmap = store_bit(context->ag_indicators_status_update_bitmap, call_indicator_index, 1); 1429*aa4dd815SMatthias Ringwald context->ag_indicators_status_update_bitmap = store_bit(context->ag_indicators_status_update_bitmap, callheld_indicator_index, 1); 1430*aa4dd815SMatthias Ringwald context->call_state = HFP_CALL_IDLE; 1431*aa4dd815SMatthias Ringwald break; 1432*aa4dd815SMatthias Ringwald default: 1433*aa4dd815SMatthias Ringwald break; 1434*aa4dd815SMatthias Ringwald } 1435*aa4dd815SMatthias Ringwald break; 1436*aa4dd815SMatthias Ringwald } 1437*aa4dd815SMatthias Ringwald case HFP_CMD_CALL_PHONE_NUMBER: 1438*aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1439*aa4dd815SMatthias Ringwald hfp_ag_call_sm(HFP_AG_OUTGOING_CALL_INITIATED, context); 1440*aa4dd815SMatthias Ringwald break; 1441*aa4dd815SMatthias Ringwald case HFP_CMD_REDIAL_LAST_NUMBER: 1442*aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1443*aa4dd815SMatthias Ringwald hfp_ag_call_sm(HFP_AG_OUTGOING_REDIAL_INITIATED, context); 1444*aa4dd815SMatthias Ringwald break; 1445*aa4dd815SMatthias Ringwald case HFP_CMD_ENABLE_CLIP: 1446*aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1447*aa4dd815SMatthias Ringwald context->clip_enabled = context->line_buffer[8] != '0'; 1448*aa4dd815SMatthias Ringwald log_info("hfp: clip set, now: %u", context->clip_enabled); 1449*aa4dd815SMatthias Ringwald context->ok_pending = 1; 1450*aa4dd815SMatthias Ringwald break; 1451*aa4dd815SMatthias Ringwald case HFP_CMD_ENABLE_CALL_WAITING_NOTIFICATION: 1452*aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1453*aa4dd815SMatthias Ringwald context->call_waiting_notification_enabled = context->line_buffer[8] != '0'; 1454*aa4dd815SMatthias Ringwald log_info("hfp: call waiting notification set, now: %u", context->call_waiting_notification_enabled); 1455*aa4dd815SMatthias Ringwald context->ok_pending = 1; 1456*aa4dd815SMatthias Ringwald break; 1457*aa4dd815SMatthias Ringwald case HFP_CMD_SET_SPEAKER_GAIN: 1458*aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1459*aa4dd815SMatthias Ringwald context->ok_pending = 1; 1460*aa4dd815SMatthias Ringwald printf("HF speaker gain = %u\n", context->speaker_gain); 1461*aa4dd815SMatthias Ringwald break; 1462*aa4dd815SMatthias Ringwald case HFP_CMD_SET_MICROPHONE_GAIN: 1463*aa4dd815SMatthias Ringwald context->command = HFP_CMD_NONE; 1464*aa4dd815SMatthias Ringwald context->ok_pending = 1; 1465*aa4dd815SMatthias Ringwald printf("HF microphone gain = %u\n", context->microphone_gain); 1466*aa4dd815SMatthias Ringwald break; 1467*aa4dd815SMatthias Ringwald default: 1468*aa4dd815SMatthias Ringwald break; 14693deb3ec6SMatthias Ringwald } 14703deb3ec6SMatthias Ringwald } 14713deb3ec6SMatthias Ringwald 1472*aa4dd815SMatthias Ringwald static void hfp_run(void){ 14733deb3ec6SMatthias Ringwald linked_list_iterator_t it; 14743deb3ec6SMatthias Ringwald linked_list_iterator_init(&it, hfp_get_connections()); 14753deb3ec6SMatthias Ringwald while (linked_list_iterator_has_next(&it)){ 14763deb3ec6SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); 14773deb3ec6SMatthias Ringwald hfp_run_for_context(connection); 14783deb3ec6SMatthias Ringwald } 14793deb3ec6SMatthias Ringwald } 14803deb3ec6SMatthias Ringwald 1481ffbf8201SMatthias Ringwald static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 14823deb3ec6SMatthias Ringwald switch (packet_type){ 14833deb3ec6SMatthias Ringwald case RFCOMM_DATA_PACKET: 1484*aa4dd815SMatthias Ringwald hfp_handle_rfcomm_data(packet_type, channel, packet, size); 14853deb3ec6SMatthias Ringwald break; 14863deb3ec6SMatthias Ringwald case HCI_EVENT_PACKET: 14873deb3ec6SMatthias Ringwald hfp_handle_hci_event(hfp_callback, packet_type, packet, size); 1488*aa4dd815SMatthias Ringwald break; 14893deb3ec6SMatthias Ringwald default: 14903deb3ec6SMatthias Ringwald break; 14913deb3ec6SMatthias Ringwald } 14923deb3ec6SMatthias Ringwald 14933deb3ec6SMatthias Ringwald hfp_run(); 14943deb3ec6SMatthias Ringwald } 14953deb3ec6SMatthias Ringwald 14963deb3ec6SMatthias Ringwald void hfp_ag_init(uint16_t rfcomm_channel_nr, uint32_t supported_features, 14973deb3ec6SMatthias Ringwald uint8_t * codecs, int codecs_nr, 14983deb3ec6SMatthias Ringwald hfp_ag_indicator_t * ag_indicators, int ag_indicators_nr, 14993deb3ec6SMatthias Ringwald hfp_generic_status_indicator_t * hf_indicators, int hf_indicators_nr, 15003deb3ec6SMatthias Ringwald const char *call_hold_services[], int call_hold_services_nr){ 15013deb3ec6SMatthias Ringwald if (codecs_nr > HFP_MAX_NUM_CODECS){ 15023deb3ec6SMatthias Ringwald log_error("hfp_init: codecs_nr (%d) > HFP_MAX_NUM_CODECS (%d)", codecs_nr, HFP_MAX_NUM_CODECS); 15033deb3ec6SMatthias Ringwald return; 15043deb3ec6SMatthias Ringwald } 1505*aa4dd815SMatthias Ringwald l2cap_init(); 1506*aa4dd815SMatthias Ringwald l2cap_register_packet_handler(packet_handler); 1507*aa4dd815SMatthias Ringwald 1508e4dd59a7SMatthias Ringwald rfcomm_register_packet_handler(packet_handler); 1509*aa4dd815SMatthias Ringwald 15103deb3ec6SMatthias Ringwald hfp_init(rfcomm_channel_nr); 15113deb3ec6SMatthias Ringwald 15123deb3ec6SMatthias Ringwald hfp_supported_features = supported_features; 15133deb3ec6SMatthias Ringwald hfp_codecs_nr = codecs_nr; 15143deb3ec6SMatthias Ringwald 15153deb3ec6SMatthias Ringwald int i; 15163deb3ec6SMatthias Ringwald for (i=0; i<codecs_nr; i++){ 15173deb3ec6SMatthias Ringwald hfp_codecs[i] = codecs[i]; 15183deb3ec6SMatthias Ringwald } 15193deb3ec6SMatthias Ringwald 15203deb3ec6SMatthias Ringwald hfp_ag_indicators_nr = ag_indicators_nr; 15213deb3ec6SMatthias Ringwald memcpy(hfp_ag_indicators, ag_indicators, ag_indicators_nr * sizeof(hfp_ag_indicator_t)); 15223deb3ec6SMatthias Ringwald 15233deb3ec6SMatthias Ringwald set_hfp_generic_status_indicators(hf_indicators, hf_indicators_nr); 15243deb3ec6SMatthias Ringwald 15253deb3ec6SMatthias Ringwald hfp_ag_call_hold_services_nr = call_hold_services_nr; 15263deb3ec6SMatthias Ringwald memcpy(hfp_ag_call_hold_services, call_hold_services, call_hold_services_nr * sizeof(char *)); 1527*aa4dd815SMatthias Ringwald 1528*aa4dd815SMatthias Ringwald hfp_ag_call_state = HFP_CALL_STATUS_NO_HELD_OR_ACTIVE_CALLS; 1529*aa4dd815SMatthias Ringwald hfp_ag_callsetup_state = HFP_CALLSETUP_STATUS_NO_CALL_SETUP_IN_PROGRESS; 1530*aa4dd815SMatthias Ringwald hfp_ag_callheld_state = HFP_CALLHELD_STATUS_NO_CALLS_HELD; 15313deb3ec6SMatthias Ringwald } 15323deb3ec6SMatthias Ringwald 15333deb3ec6SMatthias Ringwald void hfp_ag_establish_service_level_connection(bd_addr_t bd_addr){ 15343deb3ec6SMatthias Ringwald hfp_establish_service_level_connection(bd_addr, SDP_Handsfree); 15353deb3ec6SMatthias Ringwald } 15363deb3ec6SMatthias Ringwald 15373deb3ec6SMatthias Ringwald void hfp_ag_release_service_level_connection(bd_addr_t bd_addr){ 15383deb3ec6SMatthias Ringwald hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); 15393deb3ec6SMatthias Ringwald hfp_release_service_level_connection(connection); 15403deb3ec6SMatthias Ringwald hfp_run_for_context(connection); 15413deb3ec6SMatthias Ringwald } 15423deb3ec6SMatthias Ringwald 15433deb3ec6SMatthias Ringwald void hfp_ag_report_extended_audio_gateway_error_result_code(bd_addr_t bd_addr, hfp_cme_error_t error){ 15443deb3ec6SMatthias Ringwald hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); 15453deb3ec6SMatthias Ringwald if (!connection){ 15463deb3ec6SMatthias Ringwald log_error("HFP HF: connection doesn't exist."); 15473deb3ec6SMatthias Ringwald return; 15483deb3ec6SMatthias Ringwald } 15493deb3ec6SMatthias Ringwald connection->extended_audio_gateway_error = 0; 15503deb3ec6SMatthias Ringwald if (!connection->enable_extended_audio_gateway_error_report){ 15513deb3ec6SMatthias Ringwald return; 15523deb3ec6SMatthias Ringwald } 15533deb3ec6SMatthias Ringwald connection->extended_audio_gateway_error = error; 15543deb3ec6SMatthias Ringwald hfp_run_for_context(connection); 15553deb3ec6SMatthias Ringwald } 15563deb3ec6SMatthias Ringwald 1557*aa4dd815SMatthias Ringwald static void hfp_ag_setup_audio_connection(hfp_connection_t * connection){ 15583deb3ec6SMatthias Ringwald if (connection->state == HFP_AUDIO_CONNECTION_ESTABLISHED) return; 15593deb3ec6SMatthias Ringwald if (connection->state >= HFP_W2_DISCONNECT_SCO) return; 15603deb3ec6SMatthias Ringwald 15613deb3ec6SMatthias Ringwald connection->establish_audio_connection = 1; 1562*aa4dd815SMatthias Ringwald 1563*aa4dd815SMatthias Ringwald if (!has_codec_negotiation_feature(connection)){ 1564*aa4dd815SMatthias Ringwald log_info("hfp_ag_establish_audio_connection - no codec negotiation feature, using defaults"); 1565*aa4dd815SMatthias Ringwald connection->codecs_state = HFP_CODECS_EXCHANGED; 15663deb3ec6SMatthias Ringwald } 1567*aa4dd815SMatthias Ringwald 1568*aa4dd815SMatthias Ringwald switch (connection->codecs_state){ 1569*aa4dd815SMatthias Ringwald case HFP_CODECS_IDLE: 1570*aa4dd815SMatthias Ringwald case HFP_CODECS_RECEIVED_LIST: 1571*aa4dd815SMatthias Ringwald case HFP_CODECS_AG_RESEND_COMMON_CODEC: 1572*aa4dd815SMatthias Ringwald case HFP_CODECS_ERROR: 1573*aa4dd815SMatthias Ringwald connection->command = HFP_CMD_AG_SEND_COMMON_CODEC; 1574*aa4dd815SMatthias Ringwald break; 1575*aa4dd815SMatthias Ringwald default: 1576*aa4dd815SMatthias Ringwald break; 1577*aa4dd815SMatthias Ringwald } 1578*aa4dd815SMatthias Ringwald } 1579*aa4dd815SMatthias Ringwald 1580*aa4dd815SMatthias Ringwald void hfp_ag_establish_audio_connection(bd_addr_t bd_addr){ 1581*aa4dd815SMatthias Ringwald hfp_ag_establish_service_level_connection(bd_addr); 1582*aa4dd815SMatthias Ringwald hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); 1583*aa4dd815SMatthias Ringwald 1584*aa4dd815SMatthias Ringwald connection->establish_audio_connection = 0; 1585*aa4dd815SMatthias Ringwald hfp_ag_setup_audio_connection(connection); 15863deb3ec6SMatthias Ringwald hfp_run_for_context(connection); 15873deb3ec6SMatthias Ringwald } 15883deb3ec6SMatthias Ringwald 15893deb3ec6SMatthias Ringwald void hfp_ag_release_audio_connection(bd_addr_t bd_addr){ 15903deb3ec6SMatthias Ringwald hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); 15913deb3ec6SMatthias Ringwald hfp_release_audio_connection(connection); 15923deb3ec6SMatthias Ringwald hfp_run_for_context(connection); 15933deb3ec6SMatthias Ringwald } 1594*aa4dd815SMatthias Ringwald 1595*aa4dd815SMatthias Ringwald /** 1596*aa4dd815SMatthias Ringwald * @brief Enable in-band ring tone 1597*aa4dd815SMatthias Ringwald */ 1598*aa4dd815SMatthias Ringwald void hfp_ag_set_use_in_band_ring_tone(int use_in_band_ring_tone){ 1599*aa4dd815SMatthias Ringwald if (get_bit(hfp_supported_features, HFP_AGSF_IN_BAND_RING_TONE) == use_in_band_ring_tone){ 1600*aa4dd815SMatthias Ringwald return; 1601*aa4dd815SMatthias Ringwald } 1602*aa4dd815SMatthias Ringwald hfp_supported_features = store_bit(hfp_supported_features, HFP_AGSF_IN_BAND_RING_TONE, use_in_band_ring_tone); 1603*aa4dd815SMatthias Ringwald 1604*aa4dd815SMatthias Ringwald linked_list_iterator_t it; 1605*aa4dd815SMatthias Ringwald linked_list_iterator_init(&it, hfp_get_connections()); 1606*aa4dd815SMatthias Ringwald while (linked_list_iterator_has_next(&it)){ 1607*aa4dd815SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); 1608*aa4dd815SMatthias Ringwald connection->command = HFP_CMD_CHANGE_IN_BAND_RING_TONE_SETTING; 1609*aa4dd815SMatthias Ringwald hfp_run_for_context(connection); 1610*aa4dd815SMatthias Ringwald } 1611*aa4dd815SMatthias Ringwald } 1612*aa4dd815SMatthias Ringwald 1613*aa4dd815SMatthias Ringwald /** 1614*aa4dd815SMatthias Ringwald * @brief Called from GSM 1615*aa4dd815SMatthias Ringwald */ 1616*aa4dd815SMatthias Ringwald void hfp_ag_incoming_call(void){ 1617*aa4dd815SMatthias Ringwald hfp_ag_call_sm(HFP_AG_INCOMING_CALL, NULL); 1618*aa4dd815SMatthias Ringwald } 1619*aa4dd815SMatthias Ringwald 1620*aa4dd815SMatthias Ringwald /** 1621*aa4dd815SMatthias Ringwald * @brief number is stored. 1622*aa4dd815SMatthias Ringwald */ 1623*aa4dd815SMatthias Ringwald void hfp_ag_set_clip(uint8_t type, const char * number){ 1624*aa4dd815SMatthias Ringwald clip_type = type; 1625*aa4dd815SMatthias Ringwald // copy and terminate 1626*aa4dd815SMatthias Ringwald strncpy(clip_number, number, sizeof(clip_number)); 1627*aa4dd815SMatthias Ringwald clip_number[sizeof(clip_number)-1] = '\0'; 1628*aa4dd815SMatthias Ringwald } 1629*aa4dd815SMatthias Ringwald 1630*aa4dd815SMatthias Ringwald void hfp_ag_call_dropped(void){ 1631*aa4dd815SMatthias Ringwald hfp_ag_call_sm(HFP_AG_CALL_DROPPED, NULL); 1632*aa4dd815SMatthias Ringwald } 1633*aa4dd815SMatthias Ringwald 1634*aa4dd815SMatthias Ringwald // call from AG UI 1635*aa4dd815SMatthias Ringwald void hfp_ag_answer_incoming_call(void){ 1636*aa4dd815SMatthias Ringwald hfp_ag_call_sm(HFP_AG_INCOMING_CALL_ACCEPTED_BY_AG, NULL); 1637*aa4dd815SMatthias Ringwald } 1638*aa4dd815SMatthias Ringwald 1639*aa4dd815SMatthias Ringwald void hfp_ag_terminate_call(void){ 1640*aa4dd815SMatthias Ringwald hfp_ag_call_sm(HFP_AG_TERMINATE_CALL_BY_AG, NULL); 1641*aa4dd815SMatthias Ringwald } 1642*aa4dd815SMatthias Ringwald 1643*aa4dd815SMatthias Ringwald void hfp_ag_outgoing_call_ringing(void){ 1644*aa4dd815SMatthias Ringwald hfp_ag_call_sm(HFP_AG_OUTGOING_CALL_RINGING, NULL); 1645*aa4dd815SMatthias Ringwald } 1646*aa4dd815SMatthias Ringwald 1647*aa4dd815SMatthias Ringwald void hfp_ag_outgoing_call_established(void){ 1648*aa4dd815SMatthias Ringwald hfp_ag_call_sm(HFP_AG_OUTGOING_CALL_ESTABLISHED, NULL); 1649*aa4dd815SMatthias Ringwald } 1650*aa4dd815SMatthias Ringwald 1651*aa4dd815SMatthias Ringwald void hfp_ag_outgoing_call_rejected(void){ 1652*aa4dd815SMatthias Ringwald hfp_ag_call_sm(HFP_AG_OUTGOING_CALL_REJECTED, NULL); 1653*aa4dd815SMatthias Ringwald } 1654*aa4dd815SMatthias Ringwald 1655*aa4dd815SMatthias Ringwald void hfp_ag_outgoing_call_accepted(void){ 1656*aa4dd815SMatthias Ringwald hfp_ag_call_sm(HFP_AG_OUTGOING_CALL_ACCEPTED, NULL); 1657*aa4dd815SMatthias Ringwald } 1658*aa4dd815SMatthias Ringwald static void hfp_ag_set_ag_indicator(const char * name, int value){ 1659*aa4dd815SMatthias Ringwald int indicator_index = get_ag_indicator_index_for_name(name); 1660*aa4dd815SMatthias Ringwald if (indicator_index < 0) return; 1661*aa4dd815SMatthias Ringwald hfp_ag_indicators[indicator_index].status = value; 1662*aa4dd815SMatthias Ringwald 1663*aa4dd815SMatthias Ringwald linked_list_iterator_t it; 1664*aa4dd815SMatthias Ringwald linked_list_iterator_init(&it, hfp_get_connections()); 1665*aa4dd815SMatthias Ringwald while (linked_list_iterator_has_next(&it)){ 1666*aa4dd815SMatthias Ringwald hfp_connection_t * connection = (hfp_connection_t *)linked_list_iterator_next(&it); 1667*aa4dd815SMatthias Ringwald connection->ag_indicators_status_update_bitmap = store_bit(connection->ag_indicators_status_update_bitmap, indicator_index, 1); 1668*aa4dd815SMatthias Ringwald hfp_run_for_context(connection); 1669*aa4dd815SMatthias Ringwald } 1670*aa4dd815SMatthias Ringwald } 1671*aa4dd815SMatthias Ringwald 1672*aa4dd815SMatthias Ringwald /* 1673*aa4dd815SMatthias Ringwald * @brief 1674*aa4dd815SMatthias Ringwald */ 1675*aa4dd815SMatthias Ringwald void hfp_ag_set_registration_status(int status){ 1676*aa4dd815SMatthias Ringwald hfp_ag_set_ag_indicator("service", status); 1677*aa4dd815SMatthias Ringwald } 1678*aa4dd815SMatthias Ringwald 1679*aa4dd815SMatthias Ringwald /* 1680*aa4dd815SMatthias Ringwald * @brief 1681*aa4dd815SMatthias Ringwald */ 1682*aa4dd815SMatthias Ringwald void hfp_ag_set_signal_strength(int strength){ 1683*aa4dd815SMatthias Ringwald hfp_ag_set_ag_indicator("signal", strength); 1684*aa4dd815SMatthias Ringwald } 1685*aa4dd815SMatthias Ringwald 1686*aa4dd815SMatthias Ringwald /* 1687*aa4dd815SMatthias Ringwald * @brief 1688*aa4dd815SMatthias Ringwald */ 1689*aa4dd815SMatthias Ringwald void hfp_ag_set_roaming_status(int status){ 1690*aa4dd815SMatthias Ringwald hfp_ag_set_ag_indicator("roam", status); 1691*aa4dd815SMatthias Ringwald } 1692*aa4dd815SMatthias Ringwald 1693*aa4dd815SMatthias Ringwald /* 1694*aa4dd815SMatthias Ringwald * @brief 1695*aa4dd815SMatthias Ringwald */ 1696*aa4dd815SMatthias Ringwald void hfp_ag_set_battery_level(int level){ 1697*aa4dd815SMatthias Ringwald hfp_ag_set_ag_indicator("battchg", level); 1698*aa4dd815SMatthias Ringwald } 1699*aa4dd815SMatthias Ringwald 1700*aa4dd815SMatthias Ringwald /* 1701*aa4dd815SMatthias Ringwald * @brief 1702*aa4dd815SMatthias Ringwald */ 1703*aa4dd815SMatthias Ringwald void hfp_ag_activate_voice_recognition(bd_addr_t bd_addr, int activate){ 1704*aa4dd815SMatthias Ringwald if (!get_bit(hfp_supported_features, HFP_AGSF_VOICE_RECOGNITION_FUNCTION)) return; 1705*aa4dd815SMatthias Ringwald hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); 1706*aa4dd815SMatthias Ringwald 1707*aa4dd815SMatthias Ringwald if (!get_bit(connection->remote_supported_features, HFP_HFSF_VOICE_RECOGNITION_FUNCTION)) { 1708*aa4dd815SMatthias Ringwald printf("AG cannot acivate voice recognition - not supported by HF\n"); 1709*aa4dd815SMatthias Ringwald return; 1710*aa4dd815SMatthias Ringwald } 1711*aa4dd815SMatthias Ringwald 1712*aa4dd815SMatthias Ringwald if (activate){ 1713*aa4dd815SMatthias Ringwald hfp_ag_establish_audio_connection(bd_addr); 1714*aa4dd815SMatthias Ringwald } 1715*aa4dd815SMatthias Ringwald 1716*aa4dd815SMatthias Ringwald connection->ag_activate_voice_recognition = activate; 1717*aa4dd815SMatthias Ringwald connection->command = HFP_CMD_AG_ACTIVATE_VOICE_RECOGNITION; 1718*aa4dd815SMatthias Ringwald hfp_run_for_context(connection); 1719*aa4dd815SMatthias Ringwald } 1720*aa4dd815SMatthias Ringwald 1721*aa4dd815SMatthias Ringwald /* 1722*aa4dd815SMatthias Ringwald * @brief 1723*aa4dd815SMatthias Ringwald */ 1724*aa4dd815SMatthias Ringwald void hfp_ag_set_microphone_gain(bd_addr_t bd_addr, int gain){ 1725*aa4dd815SMatthias Ringwald hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); 1726*aa4dd815SMatthias Ringwald if (connection->microphone_gain != gain){ 1727*aa4dd815SMatthias Ringwald connection->command = HFP_CMD_SET_MICROPHONE_GAIN; 1728*aa4dd815SMatthias Ringwald connection->microphone_gain = gain; 1729*aa4dd815SMatthias Ringwald connection->send_microphone_gain = 1; 1730*aa4dd815SMatthias Ringwald } 1731*aa4dd815SMatthias Ringwald } 1732*aa4dd815SMatthias Ringwald 1733*aa4dd815SMatthias Ringwald /* 1734*aa4dd815SMatthias Ringwald * @brief 1735*aa4dd815SMatthias Ringwald */ 1736*aa4dd815SMatthias Ringwald void hfp_ag_set_speaker_gain(bd_addr_t bd_addr, int gain){ 1737*aa4dd815SMatthias Ringwald hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); 1738*aa4dd815SMatthias Ringwald if (connection->speaker_gain != gain){ 1739*aa4dd815SMatthias Ringwald connection->speaker_gain = gain; 1740*aa4dd815SMatthias Ringwald connection->send_speaker_gain = 1; 1741*aa4dd815SMatthias Ringwald } 1742*aa4dd815SMatthias Ringwald } 1743*aa4dd815SMatthias Ringwald 1744*aa4dd815SMatthias Ringwald /* 1745*aa4dd815SMatthias Ringwald * @brief 1746*aa4dd815SMatthias Ringwald */ 1747*aa4dd815SMatthias Ringwald void hfp_ag_send_phone_number_for_voice_tag(bd_addr_t bd_addr, const char * number){ 1748*aa4dd815SMatthias Ringwald hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); 1749*aa4dd815SMatthias Ringwald hfp_ag_set_clip(0, number); 1750*aa4dd815SMatthias Ringwald connection->send_phone_number_for_voice_tag = 1; 1751*aa4dd815SMatthias Ringwald } 1752*aa4dd815SMatthias Ringwald 1753*aa4dd815SMatthias Ringwald void hfp_ag_reject_phone_number_for_voice_tag(bd_addr_t bd_addr){ 1754*aa4dd815SMatthias Ringwald hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr); 1755*aa4dd815SMatthias Ringwald connection->send_error = 1; 1756*aa4dd815SMatthias Ringwald } 1757*aa4dd815SMatthias Ringwald 1758*aa4dd815SMatthias Ringwald 1759*aa4dd815SMatthias Ringwald 1760