/****************************************************************************** * @file gl_audio.c * * @brief for TLSR chips * * @author public@telink-semi.com; * @date Sep. 30, 2010 * * @attention * * Copyright (C) 2019-2020 Telink Semiconductor (Shanghai) Co., Ltd. * Copyright (C) Atmosic 2022 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *****************************************************************************/ #ifdef CFG_ATM_SDK #include "refdesignrcu.h" #include "bridge_att.h" #include "bridge_audio.h" #include "gl_audio.h" #include "vendor/827x_ble_remote/app_att.h" #else #include "tl_common.h" #include "drivers.h" #include "audio_config.h" #include "adpcm.h" #include "gl_audio.h" #include "tl_audio.h" #endif #if defined(CFG_ATM_SDK) || (TL_AUDIO_MODE == TL_AUDIO_RCU_ADPCM_GATT_GOOGLE) #ifdef CFG_ATM_SDK #include "stack/ble/ble_format.h" #else #include "stack/ble/ble.h" #endif extern void ui_enable_mic(int en); #ifndef CFG_ATM_SDK extern u8 buffer_mic_pkt_wptr; extern u8 buffer_mic_pkt_rptr; #endif u8 audio_start_reason = 0; //on-request(0x00),PTT(0x01),HTT(0x03) etc. u8 audio_stop_reason = 0; u8 app_audio_send_index = 0; u8 app_audio_sync_serial = 0; //Used for google voice v0.4 sync cmd u16 mic_open_error_code = 0; _attribute_data_retention_ u8 mic_open_mode = CAPTURE_MODE; //0x00:playback mode 0x01:capture mode _attribute_data_retention_ u8 google_voice_ver = 4; //4: ver 0.4e 10:ver 1.0 _attribute_data_retention_ u8 used_assistant_model = REASON_MICOPEN; //Google voice v1.0 control parameter _attribute_data_retention_ u8 auido_frame_size = 20; //Byte. this variable is updated after sending CAPS_RESP _attribute_data_retention_ u8 stream_id = 0; //The identifier of an audio stream to extend. _attribute_data_retention_ u8 flag_active_mic_open = 0; //Enable/disable mic open command _attribute_data_retention_ u16 google_voice_ctl = 0; _attribute_data_retention_ u16 atv_char_ctl_ccc = 0; _attribute_data_retention_ u16 atv_char_rx_ccc = 0; _attribute_data_retention_ u16 google_voice_codec_used = CODEC_USED_16K; _attribute_data_retention_ u16 google_voice_packet_length = VOICE_V0P4_ADPCM_PACKET_LEN; _attribute_data_retention_ u16 google_voice_pcm_sample_packet = VOICE_V0P4_ADPCM_UNIT_SIZE; _attribute_data_retention_ u32 app_audio_start_delay = 0; _attribute_data_retention_ u32 app_active_remote_timer = 0; //Wait mic open cmd after send START_SEARCH _attribute_data_retention_ u32 app_audio_transfer_timer = 0; //Used for google voice timeout _attribute_data_retention_ u32 g_delay_send_audio_stop = 0; extern u8 device_in_connection_state; /** * @brief initialize packet parameters according to the version of google voice * @param none * @return none */ void google_voice_para_init(){ if(google_voice_ver == 4){ //ver0.4e google_voice_packet_length = VOICE_V0P4_ADPCM_PACKET_LEN; //128+6+2 google_voice_pcm_sample_packet = VOICE_V0P4_ADPCM_UNIT_SIZE; // }else if(google_voice_ver == 10){ //ver1.0 google_voice_packet_length = VOICE_V1P0_ADPCM_PACKET_LEN; // google_voice_pcm_sample_packet = VOICE_V1P0_ADPCM_UNIT_SIZE; // google_voice_codec_used = CODEC_USED_16K; }else{//set to ver0.4e google_voice_ver = 4; google_voice_packet_length = VOICE_V0P4_ADPCM_PACKET_LEN; //128+6+2 google_voice_pcm_sample_packet = VOICE_V0P4_ADPCM_UNIT_SIZE; // } } /** * @brief initialize voice control parameters * @param none * @return none */ void app_audio_parameter_init(){ app_audio_send_index = 0; //v0.4 app_audio_sync_serial = 0; //app_audio_send_index = 0; #ifndef CFG_ATM_SDK //adpcm parameter adpcm_predict = 0; adpcm_predict_idx = 1; //adpcm_predict_idx = 0; adpcm_sequence_num = 0; //adpcm buffer buffer_mic_pkt_wptr = 0; buffer_mic_pkt_rptr = 0; #endif // previous_sampling_rate = U16_LO(CODEC_USED_16K); //default sampling rate:16k // previous_seq_no = 0xffff; } /** * @brief this function is used to save the assistant model. * @param[in] model:the model type * @return none */ void set_assistant_model(u8 model){ used_assistant_model = model; } /** * @brief this function is used to read the assistant model. * @param none * @return the model type */ u8 read_assistant_model(){ return used_assistant_model; } /** * @brief this function is used to enable the mic open command. * @param none * @return none */ void active_mic_open(){ flag_active_mic_open = 1; app_active_remote_timer = clock_time()|1; } /** * @brief this function is used to read the audio frame size. * @param none * @return the audio frame size */ u8 read_audio_frame_size(){ return auido_frame_size; } /** * @brief this function is used to set the audio frame size. * @param[in] frame_size:The frame size(data length exchange) * @return none */ void set_audio_frame_size(u8 frame_size){ auido_frame_size = 20; if(frame_size >= 123){ auido_frame_size = 120; }else if(frame_size >= 63){ auido_frame_size = 60; }else if(frame_size >= 43){ auido_frame_size = 40; }else if(frame_size >= 33){ auido_frame_size = 30; }else{ auido_frame_size = 20; } } /** * @brief initial settings before sending voice. * @param none * @return none */ void google_mic_enable(){ app_audio_parameter_init(); ui_enable_mic(1); //app_active_remote_timer = 0; app_audio_transfer_timer = clock_time() | 1; google_voice_ctl |= FLAG_NOTIFY_AUDIO_DATA; google_voice_ctl |= FLAG_GOOGLE_AUDIO_FIRST_SYNC; google_voice_ctl |= FLAG_DELAY_NOTIFY; app_audio_start_delay = clock_time() | 1; } /** * @brief set FLAG_GOOGLE_SEARCH bit for send search key(on-request) * @param none * @return none */ #define PREVENT_TIME 600 //ms _attribute_data_retention_ u32 prevent_repeat_trigger_on_request_tick = 0; void google_voice_on_request(){ //Prevent repeated triggers(2020.12.15) if(prevent_repeat_trigger_on_request_tick && (!clock_time_exceed(prevent_repeat_trigger_on_request_tick,PREVENT_TIME*1000))) return; prevent_repeat_trigger_on_request_tick = clock_time()|1; google_voice_ctl |= FLAG_GOOGLE_SEARCH; } /** * @brief set FLAG_GOOGLE_DPAD_SELECT bit for send DPAD cmd.(ver 0.4e 3.2.3) * @param none * @return none */ void google_voice_dpad_select(){ if(google_voice_ver == 4){ google_voice_ctl |= FLAG_GOOGLE_DPAD_SELECT; } } void google_init_audio_parameter(void) { u8 sendBuff[20] = {0}; stream_id++; //increase stream_id if(stream_id > 0x80) stream_id = 1; //stream_id range 0x01~0x80 google_voice_codec_used = CODEC_USED_16K; //init audio parameter sendBuff[0] = ATV_MIC_CHAR_CTL_AUDIO_START; sendBuff[1] = audio_start_reason; sendBuff[2] = U16_LO(google_voice_codec_used); sendBuff[3] = stream_id; bls_att_pushNotifyData(AUDIO_GOOGLE_CTL_DP_H, sendBuff, 4); google_mic_enable(); } /** * @brief this function is used to start the voice. * @param[in] start_reason:audio start reason * @return none */ u8 app_audio_key_start(u8 start_reason){ printf("app_audio_key_start\n"); if(!atv_char_rx_ccc) return 1; //ATVV_CHAR_AUDIO ccc is disabled if(google_voice_ver != 10) return 2; //google voice version error switch(start_reason){ case REASON_PTT: { printf("audio_start_reason = REASON_PTT\n"); audio_start_reason = REASON_PTT; google_init_audio_parameter(); break; } case REASON_HTT: { if(start_reason == REASON_HTT) { audio_start_reason = REASON_HTT; printf("audio_start_reason = REASON_HTT\n"); } google_init_audio_parameter(); break; } case REASON_MICOPEN: { printf("audio_start_reason = REASON_MICOPEN\n"); //send google voice CHAR_CTL search google_voice_on_request(); active_mic_open(); break; } default: { return 4; //not supported break; } } return 0; } /** * @brief this function is used to stop the voice. * @param[in] reason:Audio stop reason * @return none */ u8 app_audio_key_stop(u8 reason){ ui_enable_mic(0); app_active_remote_timer = 0; app_audio_transfer_timer = 0; audio_stop_reason = reason; google_voice_ctl |= FLAG_AUDIO_CLOSE; return 0; } /** * @brief this function is used to stop the voice by HTT. * @param none * @return 0: ready to stop voice 1:voice start reason is not HTT */ u8 app_audio_key_stop_by_htt(){ if(audio_start_reason != REASON_HTT) return 1; app_audio_key_stop(REASON_RELEASE_HTT); return 0; } /** * @brief according to the version of google voice, start the corresponding process * @param none * @return none */ void google_voice_start(){ if(google_voice_ver == 10){ app_audio_key_start(read_assistant_model()); }else{ google_voice_on_request(); } } /** * @brief this function is used to stop the voice. * @param none * @return none */ void google_voice_stop(){ if(audio_start_reason == REASON_HTT) app_audio_key_stop_by_htt(); } /** * @brief google voice 0.4 processing function. * @param[in] pw:received RF data * @return none */ void google_voice_v0p4(rf_packet_att_data_t *pw){ u8 sendBuff[20] = {0}; u8 cmd = pw->dat[0]; if(cmd == AUDIO_GOOGLE_CMD_OPEN) { //v0.4e proc u8 len = pw->l2cap-3; u16 ATV_codec_used = 2; printf("received pkt len:%d\n",len); array_printf(pw->dat,len); if(len == 3){ ATV_codec_used = (pw->dat[1]<<8) + pw->dat[2]; }else{ ATV_codec_used = 2; } printf("received v0.4 mic open:%d\n",ATV_codec_used); switch(ATV_codec_used){ case CODEC_USED_8K: { printf("ADPCM, 8khz/16bit\n"); google_voice_codec_used = CODEC_USED_8K; //8k google_voice_packet_length = VOICE_V0P4_ADPCM_PACKET_LEN ; // 2 is just for 4*n google_voice_pcm_sample_packet = VOICE_V0P4_ADPCM_UNIT_SIZE*2; //512. app_audio_send_index = 0; sendBuff[0] = ATV_MIC_CHAR_CTL_AUDIO_START; bls_att_pushNotifyData(AUDIO_GOOGLE_CTL_DP_H, sendBuff, 1); google_mic_enable(); break; } case CODEC_USED_16K: { printf("ADPCM, 16khz/16bit\n"); google_voice_codec_used = CODEC_USED_16K; google_voice_packet_length = VOICE_V0P4_ADPCM_PACKET_LEN ; // 2 is just for 4*n google_voice_pcm_sample_packet = VOICE_V0P4_ADPCM_UNIT_SIZE; //256 app_audio_send_index = 0; sendBuff[0] = ATV_MIC_CHAR_CTL_AUDIO_START; bls_att_pushNotifyData(AUDIO_GOOGLE_CTL_DP_H, sendBuff, 1); google_mic_enable(); break; } case CODEC_USED_OPUS: //printf("Opus(future),current sdk do Not support\n"); default: { printf("only support 8k voice\n"); printf("default ADPCM, 8khz/16bit\n"); google_voice_codec_used = CODEC_USED_8K; //8k google_voice_packet_length = VOICE_V0P4_ADPCM_PACKET_LEN ; // 2 is just for 4*n google_voice_pcm_sample_packet = VOICE_V0P4_ADPCM_UNIT_SIZE*2; //512. app_audio_send_index = 0; sendBuff[0] = ATV_MIC_CHAR_CTL_AUDIO_START; bls_att_pushNotifyData(AUDIO_GOOGLE_CTL_DP_H, sendBuff, 1); google_mic_enable(); //err parameter //printf("default\n"); // sendBuff[0] = ATV_MIC_CHAR_CTL_MIC_OPEN_ERROR; // sendBuff[1] = U16_HI(ERROR_INVALIED_CODEC); // sendBuff[2] = U16_LO(ERROR_INVALIED_CODEC); // bls_att_pushNotifyData(AUDIO_GOOGLE_CTL_DP_H, sendBuff, 3); break; } } printf("google_voice_pcm_sample_packet:%d\n",google_voice_pcm_sample_packet); printf("google_voice_packet_length:%d\n",google_voice_packet_length); }else if(cmd == AUDIO_GOOGLE_CMD_CLOSE){ printf("AUDIO_GOOGLE_CMD_CLOSE\n"); //u8 close_stream_id = pw->dat[1]; ui_enable_mic(0); //send audio close cmd google_voice_ctl |= FLAG_AUDIO_CLOSE; } } /** * @brief verify stream id. * @param[in] received stream id from host * @return 0: OK 1: audio_start_reason is not REASON_MICOPEN * 2: stream id out of range 3: the received id is inconsistent with the current id */ u8 verify_stream_id(u8 id){ switch(id){ case 0x00: // Check if start reason is on-request. { if(audio_start_reason != REASON_MICOPEN) return 1; break; } case 0xff: //any ongoing audio stream. { break; } default: //when start reason is htt or ptt,check the stream_id. { if(id > 0x80) return 2; //audio stream id range: 0x01 ~ 0x80 if(id != stream_id) return 3; break; } } return 0; } /** * @brief google voice 1.0 processing function. * @param[in] received RF data * @return none */ void google_voice_v1p0(rf_packet_att_data_t *pw){ if(pw->dat[0] == AUDIO_GOOGLE_CMD_OPEN){ printf("AUDIO_GOOGLE_CMD_OPEN\n"); //check ccc if(!atv_char_rx_ccc){ printf("atv_char_rx_ccc is disabled\n"); //notifications are disabled while audio data transfer is in progress google_voice_ctl |= FLAG_GOOGLE_OPEN_ERROR; mic_open_error_code = ERROR_CCC_NOT_ENABLED; return; } if(!flag_active_mic_open){ printf("mic is not activated\n"); } u8 mic_mode = pw->dat[1]; if(google_voice_ctl & FLAG_NOTIFY_AUDIO_DATA){ //ongoing audio stream printf("ongoing audio stream_audio_start_reason:%d\n",audio_start_reason); switch(audio_start_reason){ case REASON_PTT: case REASON_HTT: { //send open error.microphone is open because of ongoing PTT/HTT interaction mic_open_error_code = ERROR_ONGOING_PTT_HTT; google_voice_ctl |= FLAG_GOOGLE_OPEN_ERROR; break; } case REASON_MICOPEN: default: { //send audio stop and restart audio or ignore cmd //Prevent repeated triggers(2020.12.15) ui_enable_mic(0); google_voice_ctl |= FLAG_AUDIO_CLOSE; audio_stop_reason = REASON_UPCOMING_AUDIO_START; audio_start_reason = REASON_MICOPEN; break; } } }else{ printf("new audio. mic mode:0x%x \n",mic_mode); //start audio switch(mic_mode){ case PLAYBACK_MODE: { mic_open_mode = PLAYBACK_MODE; break; } case CAPTURE_MODE: // mic_open_mode = CAPTURE_MODE; // break; default: { mic_open_mode = CAPTURE_MODE; break; } } //SEND AUDIO START audio_start_reason = REASON_MICOPEN; google_voice_codec_used = CODEC_USED_16K; u8 sendBuff[4] = {0}; //init audio parameter sendBuff[0] = ATV_MIC_CHAR_CTL_AUDIO_START; sendBuff[1] = audio_start_reason; sendBuff[2] = U16_LO(google_voice_codec_used); sendBuff[3] = 0x00; //an audio stream which was initiated by the MIC_OPEN command printf("sendBuff:"); array_printf(sendBuff,4); bls_att_pushNotifyData(AUDIO_GOOGLE_CTL_DP_H, sendBuff, 4); google_mic_enable(); } }else if(pw->dat[0] == AUDIO_GOOGLE_CMD_CLOSE){ printf("AUDIO_GOOGLE_CMD_CLOSE\n"); u8 close_stream_id = pw->dat[1]; if(verify_stream_id(close_stream_id)) return; //close ongoing audio stream ui_enable_mic(0); google_voice_ctl |= FLAG_AUDIO_CLOSE; audio_stop_reason = REASON_MICCLOSE; }else if(pw->dat[0] == AUDIO_GOOGLE_CMD_EXTEND){ printf("AUDIO_GOOGLE_CMD_EXTEND\n"); u8 close_stream_id = pw->dat[1]; if(verify_stream_id(close_stream_id)) return; //fresh the timeout app_audio_transfer_timer = clock_time() | 1; } } /** * @brief google voice processing function. * @param[in] p: received RF data * @return none */ int app_auido_google_callback(void* p){ //u8 sendBuff[20] = {0}; rf_packet_att_data_t *pw = (rf_packet_att_data_t *)p; u8 google_command = pw->dat[0]; printf("google_command:%x\n",google_command); if(google_command == AUDIO_GOOGLE_CMD_CAP){ u16 voice_ver = (pw->dat[1]<<8) + pw->dat[2]; printf("STB google voice ver: 0x%x\n",voice_ver); if(ENABLE_GOOGLE_VOICE_1P0 && voice_ver == GOOGLE_VOICE_VERSION_1P0){ printf("GOOGLE_VOICE_VERSION_1P0\n"); array_printf(pw->dat,pw->l2cap-3); google_voice_ver = 10; //google_voice_para_init(); //u8 supported_assistant_models = pw->dat[5]; printf("supported_assistant_models:0x%x\n",pw->dat[5]); set_assistant_model(pw->dat[5]); }else{ printf("GOOGLE_VOICE_VERSION_0P4\n"); google_voice_ver = 0x04; } google_voice_ctl |= FLAG_GOOGLE_CAPS_RESP; google_voice_para_init(); #ifdef CFG_ATM_SDK bridge_audio_ready_ind(atv_char_ctl_ccc && atv_char_rx_ccc); #endif }else{ if(google_voice_ver == 10){ google_voice_v1p0(pw); }else{ google_voice_v0p4(pw); } } return 0; } /** * @brief google command process for google voice v0.4. * @param none * @return none */ void google_cmd_v0p4_proc(){ if(google_voice_ctl & FLAG_GOOGLE_DPAD_SELECT){ //audio stop. google voice auido end ble_sts_t ret; u8 sendData = ATV_MIC_CHAR_CTL_DPAD_SELECT; ret = bls_att_pushNotifyData(AUDIO_GOOGLE_CTL_DP_H, &sendData, 1); // if(ret != BLE_SUCCESS) return; // google_voice_ctl &= ~FLAG_GOOGLE_DPAD_SELECT; if(ret == BLE_SUCCESS) google_voice_ctl &= ~FLAG_GOOGLE_DPAD_SELECT; } if(google_voice_ctl & FLAG_AUDIO_CLOSE){ //audio stop. google voice auido end printf("google_cmd_v0p4_proc_close\r\n"); ble_sts_t ret; u8 sendData = ATV_MIC_CHAR_CTL_AUDIO_STOP; ret = bls_att_pushNotifyData(AUDIO_GOOGLE_CTL_DP_H, &sendData, 1); if(ret == BLE_SUCCESS){ google_voice_ctl = 0; ui_enable_mic(0); } } if(google_voice_ctl & FLAG_GOOGLE_AUDIO_SYNC){ //audio sync #ifdef CFG_ATM_SDK u8 *p = bridge_audio_read_frame(); #else int *p = mic_encoder_data_buffer (); #endif u16 frame_no; if(p){ frame_no = (p[0] <<8) + p[1]; }else{ #ifdef CFG_ATM_SDK ASSERT_ERR(0); return; #else frame_no = adpcm_sequence_num; #endif } ble_sts_t ret; u8 sendBuff[3] = {0}; sendBuff[0] = 0x0A; sendBuff[1] = U16_HI(frame_no); sendBuff[2] = U16_LO(frame_no); ret = bls_att_pushNotifyData(AUDIO_GOOGLE_CTL_DP_H, sendBuff, 3); if(ret == BLE_SUCCESS) google_voice_ctl &= ~FLAG_GOOGLE_AUDIO_SYNC; } if(google_voice_ctl & FLAG_GOOGLE_OPEN_ERROR){ //mic open error. //Timeout1.This is a timeout on the Android TV device. ble_sts_t ret; u8 sendBuff[3] = {0}; sendBuff[0] = ATV_MIC_CHAR_CTL_MIC_OPEN_ERROR; sendBuff[1] = U16_HI(ERROR_INVALIED_CODEC); sendBuff[2] = U16_LO(ERROR_INVALIED_CODEC); ret = bls_att_pushNotifyData(AUDIO_GOOGLE_CTL_DP_H, sendBuff, 3); if(ret== BLE_SUCCESS){ google_voice_ctl = 0; ui_enable_mic(0); } } } /** * @brief google command process for google voice v1.0. * @param none * @return none */ void google_cmd_v1p0_proc(){ if(!atv_char_rx_ccc && (google_voice_ctl & FLAG_NOTIFY_AUDIO_DATA)){ //notifications are disabled while audio data transfer is in progress google_voice_ctl |= FLAG_AUDIO_CLOSE; audio_stop_reason = REASON_DISABLE_CCC; } //audio stop if(google_voice_ctl & FLAG_AUDIO_CLOSE){ //audio stop. google voice auido end //printf("google_cmd_v1p0_proc_close\r\n"); u8 send_audio_stop = 1; if(REASON_RELEASE_HTT == audio_stop_reason){ // If the voice is stopped by HTT, wait for adpcm buffer to be empty before sending the stop command send_audio_stop = 0; // If the adpcm data is not sent within 1 second, send the stop command if(clock_time_exceed(g_delay_send_audio_stop,1000000)){ send_audio_stop = 1; } // adpcm buffer is empty #ifdef CFG_ATM_SDK u8 *p = bridge_audio_read_frame(); #else int *p = mic_encoder_data_buffer (); #endif if(!p){ send_audio_stop = 1; } } if(send_audio_stop){ ble_sts_t ret; u8 sendBuff[2] = {0}; sendBuff[0] = ATV_MIC_CHAR_CTL_AUDIO_STOP; sendBuff[1] = audio_stop_reason; ret = bls_att_pushNotifyData(AUDIO_GOOGLE_CTL_DP_H, sendBuff, 2); printf("google_cmd_v1p0_proc_close ret=%x\r\n",ret); if(ret == BLE_SUCCESS){ g_delay_send_audio_stop = 0; printf("ATV_MIC_CHAR_CTL_AUDIO_STOP:0x%x\n",audio_stop_reason); google_voice_ctl = 0; ui_enable_mic(0); if(audio_stop_reason == REASON_UPCOMING_AUDIO_START){ google_voice_ctl |= FLAG_GOOGLE_AUDIO_START; } } } } //audio start if(google_voice_ctl & FLAG_GOOGLE_AUDIO_START){ //audio start. triggered by an upcoming AUDIO_START command; google_voice_codec_used = CODEC_USED_16K; ble_sts_t ret; u8 sendBuff[4] = {0}; sendBuff[0] = ATV_MIC_CHAR_CTL_AUDIO_START; sendBuff[1] = audio_start_reason; sendBuff[2] = U16_LO(google_voice_codec_used); sendBuff[3] = 0x00; //an audio stream which was initiated by the MIC_OPEN command ret = bls_att_pushNotifyData(AUDIO_GOOGLE_CTL_DP_H, sendBuff, 4); if(ret == BLE_SUCCESS){ google_voice_ctl &= ~FLAG_GOOGLE_AUDIO_START; //start send audio data google_mic_enable(); } } //mic open error if(google_voice_ctl & FLAG_GOOGLE_OPEN_ERROR){ //mic open error. //Timeout1.This is a timeout on the Android TV device. printf("google_voice_ctl & FLAG_GOOGLE_OPEN_ERROR:%x",mic_open_error_code); ble_sts_t ret; u8 sendBuff[3] = {0}; sendBuff[0] = ATV_MIC_CHAR_CTL_MIC_OPEN_ERROR; sendBuff[1] = U16_HI(mic_open_error_code); sendBuff[2] = U16_LO(mic_open_error_code); ret = bls_att_pushNotifyData(AUDIO_GOOGLE_CTL_DP_H, sendBuff, 3); if(ret == BLE_SUCCESS){ google_voice_ctl = 0; ui_enable_mic(0); } } } /** * @brief notify CAPS_RESP packet. * @param none * @return none */ void google_get_rsp(void){ u8 sendBuff[9] = {0}; if(google_voice_ver == 10){ sendBuff[0] = ATV_MIC_CHAR_CTL_CAPS_RESP; sendBuff[1] = U16_HI(GOOGLE_VOICE_VERSION_1P0); //major version sendBuff[2] = U16_LO(GOOGLE_VOICE_VERSION_1P0); //minor version sendBuff[3] = CODEC_SUPPORTED_8K16K; //codecs supported (1) sendBuff[4] = read_assistant_model(); //set assistant interaction model. on-request,ptt,htt sendBuff[5] = 0x00; //audio frame size (2) sendBuff[6] = read_audio_frame_size(); //audio frame size (2) //sendBuff[7] = (read_audio_frame_size() == 20)?0:1; //extra configuration (1) extern u8 app_mtu_size; sendBuff[7] = ((read_audio_frame_size()+3) > app_mtu_size)?1:0; //extra configuration (1) sendBuff[8] = 0x00; //reserved(1) }else{ sendBuff[0] = ATV_MIC_CHAR_CTL_CAPS_RESP; sendBuff[1] = U16_HI(GOOGLE_VOICE_VERSION_0P4); //major version sendBuff[2] = U16_LO(GOOGLE_VOICE_VERSION_0P4); //minor version sendBuff[3] = 0x00; //codecs_supported high sendBuff[4] = CODEC_SUPPORTED_8K; //CODEC_SUPPORTED_8K16K; sendBuff[5] = 0x00; //frame lengths high sendBuff[6] = 0x86; //frame lengths low -- 134Byts sendBuff[7] = 0x00; //packet lengths high sendBuff[8] = 0x14; //packet lengths low -- 20 Bytes } ble_sts_t ret; ret = bls_att_pushNotifyData(AUDIO_GOOGLE_CTL_DP_H, sendBuff, 9); printf("google_get_rsp_ret=%x\r\n",ret); if(ret == BLE_SUCCESS){ if(google_voice_ver == 10) { printf("read_audio_frame_size():%d\n",sendBuff[6]); } printf("send FLAG_GOOGLE_CAPS_RESP_ver:%d\n",google_voice_ver); google_voice_ctl &= ~FLAG_GOOGLE_CAPS_RESP; } } _attribute_data_retention_ u8 notify_get_rsp_en = 0; _attribute_data_retention_ u32 notify_get_rsp_tick = 0; _attribute_data_retention_ u32 notify_get_rsp_delay_time = 6000000; /** * @brief google command process at app_audio_task. * @param none * @return none */ void google_cmd_proc(){ ble_sts_t ret; // if(app_active_remote_timer && clock_time_exceed(app_active_remote_timer, APP_AUDIO_GOOGLE_TIMEOUT1)){ // //wait mic open cmd // printf("app_active_remote_timer timeout\n"); // app_active_remote_timer = 0; // // mic_open_error_code = ERROR_RCU_NOT_ACTIVE; //google voice v1.0 // google_voice_ctl = 0; // google_voice_ctl |= FLAG_GOOGLE_OPEN_ERROR; // } if(app_audio_transfer_timer && clock_time_exceed(app_audio_transfer_timer, APP_AUDIO_GOOGLE_TIMEOUT2)){ printf("app_audio_transfer_timer timeout\n"); ui_enable_mic(0); //app_audio_disable(); app_audio_transfer_timer = 0; if(google_voice_ctl & FLAG_NOTIFY_AUDIO_DATA){ audio_stop_reason = REASON_TIMEOUT; google_voice_ctl |= FLAG_AUDIO_CLOSE; } } if(google_voice_ctl & FLAG_GOOGLE_SEARCH){ //google voice CHAR_CTL search #ifdef CFG_ATM_SDK if (1){ #else if (blc_ll_getTxFifoNumber() < (14 - 3)){ #endif printf("sendData = ATV_MIC_CHAR_CTL_SEARCH\n"); u8 sendData[2] = {0}; sendData[0] = ATV_MIC_CHAR_CTL_SEARCH; ret = bls_att_pushNotifyData(AUDIO_GOOGLE_CTL_DP_H, sendData, 1); printf("search 1 ret=%x\r\n",ret); #ifdef CFG_ATM_SDK google_voice_ctl &= ~FLAG_GOOGLE_SEARCH; #else sendData[0] = 0x21; sendData[1] = 0x02; ret = bls_att_pushNotifyData(HID_CONSUME_REPORT_INPUT_DP_H, sendData, 2); // 8 HID_NORMAL_KB_REPORT_INPUT_DP_H printf("search 2 ret=%x\r\n",ret); sendData[0] = 0x00; sendData[1] = 0x00; ret = bls_att_pushNotifyData (HID_CONSUME_REPORT_INPUT_DP_H, sendData, 2); printf("search 3 ret=%x\r\n",ret); google_voice_ctl &= ~FLAG_GOOGLE_SEARCH; extern void app_ota_status(u8 status); app_ota_status(0); #endif } } if(google_voice_ctl & FLAG_GOOGLE_CAPS_RESP){ if(notify_get_rsp_en) { if(notify_get_rsp_tick && clock_time_exceed(notify_get_rsp_tick,notify_get_rsp_delay_time)) { notify_get_rsp_en = 0; notify_get_rsp_tick = 0; notify_get_rsp_delay_time = 6000000; google_get_rsp(); } } else { google_get_rsp(); } } if(google_voice_ver == 10){ google_cmd_v1p0_proc(); }else{ google_cmd_v0p4_proc(); } } /** * @brief delay caps rsp time. * @param none * @return none */ void google_get_rsp_delay(void) { if(notify_get_rsp_en) { notify_get_rsp_tick = clock_time()|1; notify_get_rsp_delay_time = 300000; } } void google_reset_rsp_delay(void) { notify_get_rsp_delay_time = 12000000; } /** * @brief notify audio data process for google voice v0.4. * @param none * @return none */ void google_voice_data_notify_v0p4_proc(){ ////////////////////////////////////////////////////////////////// #ifdef CFG_ATM_SDK u8 *p = bridge_audio_read_frame(); #else if(blc_ll_getTxFifoNumber() >= (7 + app_audio_send_index)) return; int *p = mic_encoder_data_buffer (); #endif if(p == 0) return; u8 audio_send_length; for(u8 i=0; i<7; i++){ if(app_audio_send_index < 6){ audio_send_length = 20; }else if(app_audio_send_index == 6){ audio_send_length = 14; }else{ audio_send_length = 0; } if(BLE_SUCCESS == bls_att_pushNotifyData(AUDIO_GOOGLE_RX_DP_H, (u8*)p + app_audio_send_index*20, audio_send_length)){ app_audio_send_index++; }else{ return ; } if(app_audio_send_index == 7){ app_audio_send_index = 0; #ifdef CFG_ATM_SDK bridge_audio_sent_frame_ind(); #else mic_encoder_data_read_ok(); #endif app_audio_sync_serial ++; if(app_audio_sync_serial > 10){ app_audio_sync_serial =0; google_voice_ctl |= FLAG_GOOGLE_AUDIO_SYNC; } return ; } } } u8 previous_sampling_rate = U16_LO(CODEC_USED_16K); //default sampling rate:16k u16 previous_seq_no = 0xffff; /** * @brief notify audio data process for google voice v1.0 * @param none * @return none */ #ifdef CFG_ATM_SDK __FAST #endif void google_voice_data_notify_v1p0_proc(){ #ifdef CFG_ATM_SDK u8 *p = bridge_audio_read_frame(); #else int *p = mic_encoder_data_buffer (); #endif if(p){ //printf("google voice 1p0\n"); u8 *pd = (u8*)p; #ifdef CFG_ATM_SDK audio_sync_t *sync = bridge_audio_get_sync_info(); u16 current_seq_no = sync->frame_no; u8 current_sampling_rate = sync->codec; #else u16 current_seq_no = (pd[0]<<8) + pd[1]; u8 current_sampling_rate = pd[2]; #endif u8 need_buffer_count = 0; u8 send_sync_cmd_flag = 0; //check seq no and sampling rate before notify audio data if(current_sampling_rate != previous_sampling_rate){ send_sync_cmd_flag |= SAMPLING_CHANGE; need_buffer_count = 1; } if((u16)(current_seq_no - previous_seq_no) != 1){ send_sync_cmd_flag |= PACKET_LOSS; need_buffer_count = 1; } app_audio_sync_serial ++; if(app_audio_sync_serial >= 20){ //app_audio_sync_serial = 0; send_sync_cmd_flag |= SYNC_PACKET; need_buffer_count = 1; } if(google_voice_ctl & FLAG_GOOGLE_AUDIO_FIRST_SYNC){ //printf("FLAG_GOOGLE_AUDIO_FIRST_SYNC\n"); google_voice_ctl &= ~FLAG_GOOGLE_AUDIO_FIRST_SYNC; //send_sync_cmd_flag |= FIRST_SYNC; //need_buffer_count = 1; previous_sampling_rate = U16_LO(CODEC_USED_16K); //default sampling rate:16k previous_seq_no = 0xffff; app_audio_sync_serial = 0; //printf("start rate:0x%x",current_sampling_rate); } //adpcm packet: header:6byte, adpcm data:120byte,dummy:2byte need_buffer_count += (VOICE_V1P0_ADPCM_PACKET_LEN - 8)/auido_frame_size; #ifndef CFG_ATM_SDK if(blc_ll_getTxFifoNumber() >= (14 - need_buffer_count + app_audio_send_index)) return; #endif //check sync data if(send_sync_cmd_flag && !app_audio_send_index){ u8 sendBuff[7] = {0}; //send sync cmd u32 notify_seq_no = current_seq_no * ((VOICE_V1P0_ADPCM_PACKET_LEN - 8)/auido_frame_size); //printf("notify_seq_no:%d",notify_seq_no); sendBuff[0] = ATV_MIC_CHAR_CTL_SYNC; sendBuff[1] = current_sampling_rate; //The audio codec that will be used for the audio stream after this sync point. sendBuff[2] = (notify_seq_no >> 8) & 0xFF; //Sequence number of the audio frame sendBuff[3] = notify_seq_no & 0xFF; //Sequence number of the audio frame #ifdef CFG_ATM_SDK sendBuff[4] = (sync->pred_val >> 8) & 0xFF; sendBuff[5] = sync->pred_val & 0xFF; sendBuff[6] = sync->step_idx; #else sendBuff[4] = pd[3]; //Predicted ADPCM value. sendBuff[5] = pd[4]; //Predicted ADPCM value. sendBuff[6] = pd[5]; //step index (1) Index in ADPCM step size table. #endif if(send_sync_cmd_flag&FIRST_SYNC){ #ifndef CFG_ATM_SDK printf("Predicted ADPCM value1:0x%x\n",sendBuff[4]); printf("Predicted ADPCM value2:0x%x\n",sendBuff[5]); printf("step index:0x%x\n",sendBuff[6]); printf("need_buffer_count:0x%x\n",need_buffer_count); printf("(VOICE_V1P0_ADPCM_PACKET_LEN - 8)/auido_frame_size:%d\n",(VOICE_V1P0_ADPCM_PACKET_LEN - 8)/auido_frame_size); #endif } ble_sts_t ret = bls_att_pushNotifyData(AUDIO_GOOGLE_CTL_DP_H, sendBuff, 7); if(ret == BLE_SUCCESS){ #ifndef CFG_ATM_SDK printf("send_sync_cmd_flag:%d\n",send_sync_cmd_flag); if(send_sync_cmd_flag&SAMPLING_CHANGE) printf("SAMPLING_CHANGE previous_sampling_rate:%d_current:%d\n",previous_sampling_rate,current_sampling_rate); if(send_sync_cmd_flag&PACKET_LOSS) printf("PACKET_LOSS previous_seq_no:%d_current:%d\n",previous_seq_no,current_seq_no); #endif // array_printf(sendBuff,7); app_audio_send_index++; }else{ return ; } } //send audio data for(u8 i=0; i< ((VOICE_V1P0_ADPCM_PACKET_LEN - 8)/auido_frame_size); i++){ u8 audio_addr_shift = app_audio_send_index - (send_sync_cmd_flag==0)?0:1; // printf("send_sync_cmd_flag:%d\n",send_sync_cmd_flag); // printf("audio_addr_shift:%d\n",audio_addr_shift); #ifdef CFG_ATM_SDK if(BLE_SUCCESS == bls_att_pushNotifyData(AUDIO_GOOGLE_RX_DP_H, pd, auido_frame_size)){ #else if(BLE_SUCCESS == bls_att_pushNotifyData(AUDIO_GOOGLE_RX_DP_H, pd + 6 + audio_addr_shift *auido_frame_size, auido_frame_size)){ #endif app_audio_send_index++; // array_printf(pd + 6 + audio_addr_shift *auido_frame_size,20); }else{ return; } if(app_audio_send_index >= need_buffer_count){ // printf("need_buffer_count:0x%x\n",need_buffer_count); // printf("app_audio_send_index:0x%x\n",app_audio_send_index); app_audio_send_index = 0; //printf("notify data:"); //array_printf(pd,10); app_audio_sync_serial = 0; #ifdef CFG_ATM_SDK bridge_audio_sent_frame_ind(); #else mic_encoder_data_read_ok(); #endif previous_sampling_rate = current_sampling_rate; previous_seq_no = current_seq_no; return; } } } } /** * @brief notify audio data process. * @param none * @return none */ void google_voice_data_notify_proc(){ //send voice data if( google_voice_ver == 10){ google_voice_data_notify_v1p0_proc(); }else{ //google voice version error google_voice_data_notify_v0p4_proc(); } } /** * @brief google voice task at main loop. * @param none * @return none */ void app_audio_task(void){ if(app_active_remote_timer && clock_time_exceed(app_active_remote_timer, APP_AUDIO_GOOGLE_TIMEOUT1)){ //wait mic open cmd printf("app_active_remote_timer timeout\n"); app_active_remote_timer = 0; flag_active_mic_open = 0; } if(!google_voice_ctl) return; if(device_in_connection_state) google_cmd_proc(); if(google_voice_ctl & FLAG_DELAY_NOTIFY){ if(clock_time_exceed(app_audio_start_delay,30*1000)){ google_voice_ctl &= ~FLAG_DELAY_NOTIFY; audio_set_mute_pga(1); printf("start notify audio data\n"); if(google_voice_ver == 10){ if(google_voice_codec_used == CODEC_USED_16K){ printf("init adpcm unit size: to 240\n"); google_voice_pcm_sample_packet = VOICE_V1P0_ADPCM_UNIT_SIZE; }else if(google_voice_codec_used == CODEC_USED_8K){ google_voice_pcm_sample_packet = VOICE_V1P0_ADPCM_UNIT_SIZE*2; } }else{ if(google_voice_codec_used == CODEC_USED_16K){ printf("init adpcm unit size: to 256\n"); google_voice_pcm_sample_packet = VOICE_V0P4_ADPCM_UNIT_SIZE; }else if(google_voice_codec_used == CODEC_USED_8K){ google_voice_pcm_sample_packet = VOICE_V0P4_ADPCM_UNIT_SIZE*2; } } } return; } if((google_voice_ctl & FLAG_NOTIFY_AUDIO_DATA) == 0) return; prevent_repeat_trigger_on_request_tick = 0; proc_mic_encoder(); google_voice_data_notify_proc(); } #else #endif