mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-30 16:20:24 +00:00
hfp: test codec negotiation
This commit is contained in:
parent
97faa4568c
commit
7e7cacd7e6
@ -628,7 +628,8 @@ extern "C" {
|
||||
#define HFP_SUBEVENT_AG_INDICATOR_STATUS_CHANGED 0x06
|
||||
#define HFP_SUBEVENT_NETWORK_OPERATOR_CHANGED 0x07
|
||||
#define HFP_SUBEVENT_EXTENDED_AUDIO_GATEWAY_ERROR 0x08
|
||||
#define HFP_SUBEVENT_AUDIO_CONNECTION_COMPLETE 0x09
|
||||
#define HFP_SUBEVENT_CODECS_CONNECTION_COMPLETE 0x09
|
||||
#define HFP_SUBEVENT_AUDIO_CONNECTION_COMPLETE 0x0A
|
||||
|
||||
// ANCS Client
|
||||
#define ANCS_CLIENT_CONNECTED 0xF0
|
||||
|
@ -584,7 +584,7 @@ static void hfp_handle_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8
|
||||
}
|
||||
|
||||
packet[size] = 0;
|
||||
printf("\nparse command: %s\n", packet);
|
||||
printf("\nresponse: %s\n", packet);
|
||||
int pos;
|
||||
for (pos = 0; pos < size ; pos++){
|
||||
hfp_parse(context, packet[pos]);
|
||||
@ -607,6 +607,7 @@ static void hfp_run(){
|
||||
static void packet_handler(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
|
||||
switch (packet_type){
|
||||
case RFCOMM_DATA_PACKET:
|
||||
printf("\nRFCOMM_DATA_PACKET: %s\n", packet);
|
||||
hfp_handle_rfcomm_event(packet_type, channel, packet, size);
|
||||
break;
|
||||
case HCI_EVENT_PACKET:
|
||||
|
27
src/hfp_hf.c
27
src/hfp_hf.c
@ -485,8 +485,9 @@ static void hfp_run_for_context(hfp_connection_t * context){
|
||||
break;
|
||||
|
||||
case HFP_CODECS_CONNECTION_ESTABLISHED:
|
||||
|
||||
printf("HFP_CODECS_CONNECTION_ESTABLISHED \n");
|
||||
if (context->notify_ag_on_new_codecs){
|
||||
printf("restart codecs negotiation \n");
|
||||
hfp_hf_cmd_notify_on_codecs(context->rfcomm_cid);
|
||||
context->negotiated_codec = 0;
|
||||
context->wait_ok = 1;
|
||||
@ -494,6 +495,8 @@ static void hfp_run_for_context(hfp_connection_t * context){
|
||||
break;
|
||||
}
|
||||
|
||||
hfp_emit_event(hfp_callback, HFP_SUBEVENT_CODECS_CONNECTION_COMPLETE, 0);
|
||||
|
||||
if (context->establish_audio_connection){
|
||||
// TODO AUDIO CONNECTION
|
||||
}
|
||||
@ -564,7 +567,7 @@ static void hfp_handle_rfcomm_event(uint8_t packet_type, uint16_t channel, uint8
|
||||
|
||||
packet[size] = 0;
|
||||
int pos, i;
|
||||
printf("parse command: %s\n", packet+2);
|
||||
printf("response: %s\n", packet+2);
|
||||
for (pos = 0; pos < size ; pos++){
|
||||
hfp_parse(context, packet[pos]);
|
||||
|
||||
@ -708,6 +711,26 @@ void hfp_hf_enable_report_extended_audio_gateway_error_result_code(bd_addr_t bd_
|
||||
hfp_run_for_context(connection);
|
||||
}
|
||||
|
||||
void hfp_hf_negotiate_codecs(bd_addr_t bd_addr){
|
||||
hfp_hf_establish_service_level_connection(bd_addr);
|
||||
hfp_connection_t * connection = get_hfp_connection_context_for_bd_addr(bd_addr);
|
||||
if (!connection){
|
||||
log_error("HFP HF: connection doesn't exist.");
|
||||
return;
|
||||
}
|
||||
connection->trigger_codec_connection_setup = 0;
|
||||
|
||||
if (connection->state == HFP_CODECS_CONNECTION_ESTABLISHED) return;
|
||||
|
||||
if (!has_codec_negotiation_feature(connection)){
|
||||
connection->trigger_codec_connection_setup = 0;
|
||||
return;
|
||||
}
|
||||
connection->trigger_codec_connection_setup = 1;
|
||||
|
||||
hfp_run_for_context(connection);
|
||||
}
|
||||
|
||||
|
||||
void hfp_hf_establish_audio_connection(bd_addr_t bd_addr){
|
||||
hfp_hf_establish_service_level_connection(bd_addr);
|
||||
|
@ -141,6 +141,8 @@ void hfp_hf_enable_report_extended_audio_gateway_error_result_code(bd_addr_t bd_
|
||||
/**
|
||||
* @brief
|
||||
*/
|
||||
void hfp_hf_negotiate_codecs(bd_addr_t bd_addr);
|
||||
|
||||
void hfp_hf_establish_audio_connection(bd_addr_t bd_addr);
|
||||
|
||||
/**
|
||||
|
@ -64,120 +64,21 @@
|
||||
#include "hfp_hf.h"
|
||||
|
||||
const uint8_t rfcomm_channel_nr = 1;
|
||||
const char hfp_hf_service_name[] = "BTstack HFP HF Test";
|
||||
|
||||
static bd_addr_t pts_addr = {0x00,0x1b,0xDC,0x07,0x32,0xEF};
|
||||
static bd_addr_t phone_addr = {0xD8,0xBb,0x2C,0xDf,0xF1,0x08};
|
||||
static bd_addr_t device_addr = {0xD8,0xBb,0x2C,0xDf,0xF1,0x08};
|
||||
|
||||
static bd_addr_t device_addr;
|
||||
static uint8_t codecs[1] = {HFP_CODEC_CVSD};
|
||||
static uint16_t indicators[1] = {0x01};
|
||||
|
||||
static uint8_t service_level_connection_established = 0;
|
||||
static uint8_t codecs_connection_established = 0;
|
||||
static uint8_t audio_connection_established = 0;
|
||||
|
||||
// prototypes
|
||||
static void show_usage();
|
||||
uint8_t * get_rfcomm_payload();
|
||||
uint16_t get_rfcomm_payload_len();
|
||||
void inject_rfcomm_command(uint8_t * payload, int len);
|
||||
|
||||
// Testig User Interface
|
||||
static void show_usage(void){
|
||||
printf("\n--- Bluetooth HFP Hands-Free (HF) unit Test Console ---\n");
|
||||
printf("---\n");
|
||||
printf("y - use PTS module as Audiogateway\n");
|
||||
printf("z - use iPhone as Audiogateway\n");
|
||||
|
||||
printf("h - establish HFP connection to device\n");
|
||||
printf("H - release HFP connection to device\n");
|
||||
|
||||
printf("a - establish Audio connection to device\n");
|
||||
printf("A - release Audio connection to device\n");
|
||||
|
||||
printf("b - establish AUDIO connection\n");
|
||||
printf("B - release AUDIO connection\n");
|
||||
|
||||
printf("d - enable registration status update\n");
|
||||
printf("D - disable registration status update\n");
|
||||
|
||||
printf("e - enable HFP AG registration status update for individual indicators\n");
|
||||
|
||||
printf("f - query network operator\n");
|
||||
|
||||
printf("g - enable reporting of the extended AG error result code\n");
|
||||
printf("G - disable reporting of the extended AG error result code\n");
|
||||
|
||||
printf("---\n");
|
||||
printf("Ctrl-c - exit\n");
|
||||
printf("---\n");
|
||||
}
|
||||
|
||||
static int process(char cmd){
|
||||
switch (cmd){
|
||||
case 'a':
|
||||
memcpy(device_addr, pts_addr, 6);
|
||||
printf("Establish Audio connection to device with Bluetooth address %s...\n", bd_addr_to_str(device_addr));
|
||||
hfp_hf_establish_audio_connection(device_addr);
|
||||
break;
|
||||
case 'A':
|
||||
printf("Release Audio service level connection.\n");
|
||||
hfp_hf_release_audio_connection(device_addr);
|
||||
break;
|
||||
case 'h':
|
||||
memcpy(device_addr, pts_addr, 6);
|
||||
printf("Establish HFP service level connection to device with Bluetooth address %s...\n", bd_addr_to_str(device_addr));
|
||||
hfp_hf_establish_service_level_connection(device_addr);
|
||||
break;
|
||||
case 'H':
|
||||
printf("Release HFP service level connection.\n");
|
||||
hfp_hf_release_service_level_connection(device_addr);
|
||||
break;
|
||||
case 'b':
|
||||
printf("Establish Audio connection %s...\n", bd_addr_to_str(device_addr));
|
||||
hfp_hf_establish_audio_connection(device_addr);
|
||||
break;
|
||||
case 'B':
|
||||
printf("Release Audio connection.\n");
|
||||
hfp_hf_release_audio_connection(device_addr);
|
||||
break;
|
||||
case 'd':
|
||||
printf("Enable HFP AG registration status update.\n");
|
||||
hfp_hf_enable_status_update_for_all_ag_indicators(device_addr, 1);
|
||||
case 'D':
|
||||
printf("Disable HFP AG registration status update.\n");
|
||||
hfp_hf_enable_status_update_for_all_ag_indicators(device_addr, 0);
|
||||
break;
|
||||
case 'e':
|
||||
printf("Enable HFP AG registration status update for individual indicators.\n");
|
||||
hfp_hf_enable_status_update_for_individual_ag_indicators(device_addr, 63);
|
||||
break;
|
||||
case 'f':
|
||||
printf("Query network operator.\n");
|
||||
hfp_hf_query_operator_selection(device_addr);
|
||||
break;
|
||||
case 'g':
|
||||
printf("Enable reporting of the extended AG error result code.\n");
|
||||
hfp_hf_enable_report_extended_audio_gateway_error_result_code(device_addr, 1);
|
||||
break;
|
||||
case 'G':
|
||||
printf("Disable reporting of the extended AG error result code.\n");
|
||||
hfp_hf_enable_report_extended_audio_gateway_error_result_code(device_addr, 0);
|
||||
break;
|
||||
|
||||
case 'y':
|
||||
memcpy(device_addr, phone_addr, 6);
|
||||
printf("Use iPhone %s as Audiogateway.\n", bd_addr_to_str(device_addr));
|
||||
break;
|
||||
case 'z':
|
||||
memcpy(device_addr, pts_addr, 6);
|
||||
printf("Use PTS module %s as Audiogateway.\n", bd_addr_to_str(device_addr));
|
||||
break;
|
||||
default:
|
||||
show_usage();
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
if (event[0] != HCI_EVENT_HFP_META) return;
|
||||
if (event[3] && event[2] != HFP_SUBEVENT_EXTENDED_AUDIO_GATEWAY_ERROR){
|
||||
@ -186,8 +87,12 @@ void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
}
|
||||
switch (event[2]) {
|
||||
case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_ESTABLISHED:
|
||||
printf("Service level connection established.\n\n");
|
||||
service_level_connection_established = 1;
|
||||
break;
|
||||
case HFP_SUBEVENT_CODECS_CONNECTION_COMPLETE:
|
||||
codecs_connection_established = 1;
|
||||
break;
|
||||
|
||||
case HFP_SUBEVENT_SERVICE_LEVEL_CONNECTION_RELEASED:
|
||||
printf("Service level connection released.\n\n");
|
||||
break;
|
||||
@ -211,7 +116,7 @@ void packet_handler(uint8_t * event, uint16_t event_size){
|
||||
}
|
||||
|
||||
static int expected_rfcomm_command(const char * cmd){
|
||||
printf("%s\n", get_rfcomm_payload());
|
||||
//printf("%s\n", get_rfcomm_payload());
|
||||
return strcmp((char *)cmd, (char *)get_rfcomm_payload());
|
||||
}
|
||||
|
||||
@ -219,24 +124,97 @@ static void verify_expected_rfcomm_command(const char * cmd){
|
||||
CHECK_EQUAL(expected_rfcomm_command(cmd),0);
|
||||
}
|
||||
|
||||
const char hf_supported_features[] = "AT+BRSF=438\r\n";
|
||||
const char ag_supported_features[] = "\r\n+BRSF=1007\r\n\r\nOK\r\n";
|
||||
const char ag_ok[] = "\r\nOK\r\n";
|
||||
|
||||
/* START SERVICE LEVEL CONNECTION SEQUENCE */
|
||||
const char hf_supported_features[] = "AT+BRSF=438\r\n";
|
||||
const char ag_supported_features[] = "\r\n+BRSF:1007\r\n";
|
||||
|
||||
const char hf_supported_codecs[] = "AT+BAC=1\r\n";
|
||||
|
||||
const char hf_get_ag_indicators[] = "AT+CIND=?\r\n";
|
||||
const char ag_indicators[] = "\r\n+CIND:\"service\",(0,1),\"call\",(0,1),\"callsetup\",(0,3),\"battchg\",(0,5),\"signal\",(0,5),\"roam\",(0,1),\"callheld\",(0,2)\r\n";
|
||||
|
||||
const char hf_get_ag_indicators_status[] = "AT+CIND?\r\n";
|
||||
const char ag_indicators_status[] = "\r\n+CIND:1,0,0,3,5,0,0\r\n";
|
||||
|
||||
const char hf_enable_indicator_status[] = "AT+CMER=3,0,0,1\r\n";
|
||||
|
||||
const char hf_get_ag_call_and_multiparty_services[] = "AT+CHLD=?\r\n";
|
||||
const char ag_call_and_multiparty_services[] = "\r\n+CHLD:(1,1x,2,2x,3)\r\n";
|
||||
/* END SERVICE LEVEL CONNECTION SEQUENCE */
|
||||
|
||||
|
||||
/* START CODECS CONNECTION SEQUENCE */
|
||||
const char hf_trigger_codecs_connection[] = "AT+BCC\r\n";
|
||||
|
||||
const char ag_report_selected_codec[] = "\r\n+BCS:1\r\n";
|
||||
const char hf_confirm_selected_codec[] = "AT+BCS=1\r\n";
|
||||
/* END CODECS CONNECTION SEQUENCE */
|
||||
|
||||
|
||||
TEST_GROUP(HandsfreeClient){
|
||||
void setup(void){
|
||||
process('y');
|
||||
service_level_connection_established = 0;
|
||||
codecs_connection_established = 0;
|
||||
audio_connection_established = 0;
|
||||
}
|
||||
|
||||
void test_hfp_service_level_connection_state_machine(){
|
||||
service_level_connection_established = 0;
|
||||
hfp_hf_establish_service_level_connection(device_addr);
|
||||
verify_expected_rfcomm_command(hf_supported_features);
|
||||
inject_rfcomm_command((uint8_t*)ag_supported_features, strlen(ag_supported_features));
|
||||
inject_rfcomm_command((uint8_t*)ag_ok, strlen(ag_ok));
|
||||
|
||||
verify_expected_rfcomm_command(hf_supported_codecs);
|
||||
inject_rfcomm_command((uint8_t*)ag_ok, strlen(ag_ok));
|
||||
|
||||
verify_expected_rfcomm_command(hf_get_ag_indicators);
|
||||
inject_rfcomm_command((uint8_t*)ag_indicators, strlen(ag_indicators));
|
||||
inject_rfcomm_command((uint8_t*)ag_ok, strlen(ag_ok));
|
||||
|
||||
verify_expected_rfcomm_command(hf_get_ag_indicators_status);
|
||||
inject_rfcomm_command((uint8_t*)ag_indicators_status, strlen(ag_indicators_status));
|
||||
inject_rfcomm_command((uint8_t*)ag_ok, strlen(ag_ok));
|
||||
|
||||
verify_expected_rfcomm_command(hf_enable_indicator_status);
|
||||
inject_rfcomm_command((uint8_t*)ag_ok, strlen(ag_ok));
|
||||
|
||||
verify_expected_rfcomm_command(hf_get_ag_call_and_multiparty_services);
|
||||
inject_rfcomm_command((uint8_t*)ag_call_and_multiparty_services, strlen(ag_call_and_multiparty_services));
|
||||
inject_rfcomm_command((uint8_t*)ag_ok, strlen(ag_ok));
|
||||
CHECK_EQUAL(service_level_connection_established, 1);
|
||||
}
|
||||
|
||||
void test_hfp_codecs_connection_state_machine(){
|
||||
codecs_connection_established = 0;
|
||||
hfp_hf_negotiate_codecs(device_addr);
|
||||
|
||||
verify_expected_rfcomm_command(hf_trigger_codecs_connection);
|
||||
inject_rfcomm_command((uint8_t*)ag_ok, strlen(ag_ok));
|
||||
|
||||
inject_rfcomm_command((uint8_t*)ag_report_selected_codec, strlen(ag_report_selected_codec));
|
||||
verify_expected_rfcomm_command(hf_confirm_selected_codec);
|
||||
inject_rfcomm_command((uint8_t*)ag_ok, strlen(ag_ok));
|
||||
CHECK_EQUAL(codecs_connection_established, 1);
|
||||
}
|
||||
|
||||
void test_audio_connection_state_machine(){
|
||||
audio_connection_established = 0;
|
||||
hfp_hf_establish_audio_connection(device_addr);
|
||||
}
|
||||
};
|
||||
|
||||
TEST(HandsfreeClient, HFAudioConnection){
|
||||
process('a');
|
||||
verify_expected_rfcomm_command(hf_supported_features);
|
||||
inject_rfcomm_command((uint8_t*)ag_supported_features, strlen(ag_supported_features));
|
||||
|
||||
|
||||
TEST(HandsfreeClient, HFCodecsConnectionEstablished1){
|
||||
test_hfp_service_level_connection_state_machine();
|
||||
// test_hfp_codecs_connection_state_machine();
|
||||
|
||||
// hfp_hf_set_codecs(codecs, 2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main (int argc, const char * argv[]){
|
||||
hfp_hf_init(rfcomm_channel_nr, 438, indicators, sizeof(indicators)/sizeof(uint16_t), 1);
|
||||
hfp_hf_set_codecs(codecs, sizeof(codecs));
|
||||
|
@ -38,11 +38,10 @@ void inject_rfcomm_command(uint8_t * data, int len){
|
||||
}
|
||||
|
||||
int rfcomm_send_internal(uint16_t rfcomm_cid, uint8_t *data, uint16_t len){
|
||||
// printf("rfcomm_send_internal\n");
|
||||
printf("rfcomm_send_internal %s\n", data);
|
||||
memset(&rfcomm_payload, 0, 200);
|
||||
rfcomm_payload_len = len;
|
||||
memcpy((char*)&rfcomm_payload, data, rfcomm_payload_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user