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