/**************************************************************************** NAME usbAudioRoute DESCRIPTION Connect USB audio stream RETURNS void */ void usbAudioRoute(void) { AudioPluginFeatures features; Sink sink; Source source; uint16 sampleFreq; UsbDeviceClassGetValue(USB_DEVICE_CLASS_GET_VALUE_AUDIO_SOURCE, (uint16*)(&source)); /* Note: UsbDeviceClassGetValue uses uint16 which limits max value of sample frequency to 64k (uint 16 has range 0->65536) */ UsbDeviceClassGetValue(USB_DEVICE_CLASS_GET_VALUE_SAMPLE_FREQ, &sampleFreq); sink = StreamSinkFromSource(source); /* determine additional features applicable for this audio plugin */ features.stereo = (AUDIO_PLUGIN_FORCE_STEREO || theSink.features.stereo); features.use_i2s_output = theSink.features.UseI2SOutputCapability; USB_DEBUG(("USB: Audio ")); /* Check Audio configured (sink will be NULL if VM USB not enabled) */ if(USB_CLASS_ENABLED(USB_DEVICE_CLASS_AUDIO) && sink) { USB_DEBUG(("Configured ")); if(usbAudioIsAttached()) { USB_DEBUG(("Attached\n")); if(theSink.routed_audio != sink) { Task plugin; AUDIO_MODE_T mode; uint16 volume = usbGetVolume(&mode); const usb_plugin_info* plugin_info = usbAudioGetPluginInfo(&plugin, theSink.usb.config.plugin_type, theSink.usb.config.plugin_index); theSink.routed_audio = sink; UsbDeviceClassGetValue(USB_DEVICE_CLASS_GET_VALUE_AUDIO_SINK, (uint16*)(&theSink.cvc_params.usb_params.usb_sink)); /* Make sure we're using correct parameters for USB */ theSink.a2dp_link_data->a2dp_audio_connect_params.mode_params = &theSink.a2dp_link_data->a2dp_audio_mode_params; USB_DEBUG(("USB: Connect 0x%X 0x%X", (uint16)sink, (uint16)(theSink.cvc_params.usb_params.usb_sink))); #ifdef ENABLE_SUBWOOFER /* set the sub woofer link type prior to passing to audio connect */ theSink.a2dp_link_data->a2dp_audio_connect_params.sub_woofer_type = AUDIO_SUB_WOOFER_NONE; theSink.a2dp_link_data->a2dp_audio_connect_params.sub_sink = NULL; /* bits inverted in dsp plugin */ sinkAudioSetEnhancement(MUSIC_CONFIG_SUB_WOOFER_BYPASS,TRUE); #else /* no subwoofer support, set the sub woofer bypass bit in music config message sent o dsp */ sinkAudioSetEnhancement(MUSIC_CONFIG_SUB_WOOFER_BYPASS,FALSE); #endif /* use a2dp connect parameters */ /* sample frequency is not fixed so read this from usb library */ if(plugin_info->plugin_type == usb_plugin_stereo) AudioConnect(plugin, sink, AUDIO_SINK_USB, theSink.codec_task, volume, sampleFreq, features, mode, 0, powerManagerGetLBIPM(), &theSink.a2dp_link_data->a2dp_audio_connect_params, &theSink.task); /* all other plugins use cvc connect parameters */ else AudioConnect(plugin, sink, AUDIO_SINK_USB, theSink.codec_task, volume, sampleFreq, features, mode, 0, powerManagerGetLBIPM(), &theSink.cvc_params, &theSink.task); } } } USB_DEBUG(("\n")); }
/**************************************************************************** NAME audioHfpConnectAudio DESCRIPTION attempt to reconnect an audio connection from the sink value associcated with the passed hfp instance RETURNS */ void audioHfpConnectAudio (hfp_link_priority priority, Sink sink) { uint8 index = PROFILE_INDEX(priority); /* ensure sink is valid before trying to route audio */ TaskData *plugin = NULL; /* ensure a valid codec is negotiated, should be at least cvsd */ if(theSink.profile_data[index].audio.codec_selected) { AudioPluginFeatures features; /* determine additional features applicable for this audio plugin */ features.stereo = (AUDIO_PLUGIN_FORCE_STEREO || theSink.features.stereo); features.use_i2s_output = theSink.features.UseI2SOutputCapability; theSink.routed_audio = sink; plugin = audioHfpGetPlugin(theSink.profile_data[index].audio.codec_selected, theSink.features.audio_plugin); AUD_DEBUG(("AUD: plugin [%d] [%d], sink [%x]\n" , theSink.features.audio_plugin , theSink.profile_data[index].audio.codec_selected , (uint16)theSink.routed_audio)) ; /* connect audio using the audio plugin selected above */ AudioConnect ( plugin, theSink.routed_audio , theSink.profile_data[index].audio.link_type , theSink.codec_task , theSink.conf1->gVolMaps[ theSink.profile_data[index].audio.gSMVolumeLevel ].VolGain , theSink.profile_data[index].audio.tx_bandwidth , features , AUDIO_MODE_CONNECTED, AUDIO_ROUTE_INTERNAL, powerManagerGetLBIPM(), AUDIO_CONNECT_PARAMS, NULL ) ; audioControlLowPowerCodecs (TRUE) ; AUD_DEBUG(("AUD: Route SCO\n")); AUD_DEBUG(("Audio Connect[%d][%x]\n", theSink.features.audio_plugin , theSink.profile_data[index].audio.gSMVolumeLevel )) ; AudioSetVolume ( theSink.conf1->gVolMaps[ theSink.profile_data[index].audio.gSMVolumeLevel ].VolGain , TonesGetToneVolume(FALSE), theSink.codec_task ) ; /* mute control */ VolumeSetMicrophoneGain(priority, (theSink.profile_data[index].audio.gMuted ? VOLUME_MUTE_ON : VOLUME_MUTE_OFF)); } }
/**************************************************************************** NAME audioHfpConnectAudio DESCRIPTION attempt to reconnect an audio connection from the sink value associcated with the passed hfp instance RETURNS */ void audioHfpConnectAudio (hfp_link_priority priority, Sink sink) { uint8 index = PROFILE_INDEX(priority); /* ensure sink is valid before trying to route audio */ TaskData *plugin = NULL; /* ensure a valid codec is negotiated, should be at least cvsd */ if(theSink.profile_data[index].audio.codec_selected) { /* determine additional features applicable for this audio plugin */ theSink.routed_audio = sink; plugin = audioHfpGetPlugin(theSink.profile_data[index].audio.codec_selected, theSink.features.audio_plugin); AUD_DEBUG(("AUD: plugin [%d] [%d], sink [%x]\n" , theSink.features.audio_plugin , theSink.profile_data[index].audio.codec_selected , (uint16)theSink.routed_audio)) ; /* connect audio using the audio plugin selected above */ AudioConnect ( plugin, theSink.routed_audio , theSink.profile_data[index].audio.link_type , theSink.codec_task , theSink.conf1->volume_config.gVolMaps[ theSink.profile_data[index].audio.gSMVolumeLevel ].VolGain , theSink.profile_data[index].audio.tx_bandwidth , theSink.conf2->audio_routing_data.PluginFeatures , AUDIO_MODE_CONNECTED, AUDIO_ROUTE_INTERNAL, powerManagerGetLBIPM(), AUDIO_CONNECT_PARAMS, koovox.presentEnable, &theSink.task) ; DEBUG(("===presentEnable=%d\n", koovox.presentEnable)); audioControlLowPowerCodecs (TRUE) ; AUD_DEBUG(("AUD: Route SCO\n")); AUD_DEBUG(("Audio Connect[%d][%x]\n", theSink.features.audio_plugin , theSink.profile_data[index].audio.gSMVolumeLevel )) ; AudioSetVolume ( theSink.conf1->volume_config.gVolMaps[ theSink.profile_data[index].audio.gSMVolumeLevel ].VolGain , TonesGetToneVolume(FALSE), theSink.codec_task ) ; /* mute control */ VolumeSetMicrophoneGain(priority, (theSink.profile_data[index].audio.gMuted ? VOLUME_MUTE_ON : VOLUME_MUTE_OFF)); } }
/**************************************************************************** NAME audioConnectSco DESCRIPTION This function connects the synchronous connection to the CVC EC/NR Algorithm running in the Kalimba DSP. */ static bool audioConnectSco(AUDIO_SINK_T sink_type, uint32 bandwidth) { bool lResult = FALSE ; /* The mode to connect - connected as default */ AUDIO_MODE_T lMode = AUDIO_MODE_CONNECTED ; /* Disconnect A2DP audio if it was active */ streamControlCeaseA2dpStreaming(TRUE); /* Mute control */ if (theHeadset.gMuted ) { if (theHeadset.features.MuteSpeakerAndMic) { lMode = AUDIO_MODE_MUTE_BOTH; } else { lMode = AUDIO_MODE_MUTE_MIC; } } if (HfpGetAudioSink(theHeadset.hfp_hsp)) { HFP_DEBUG(("HFP: Route SCO mode=%d mic_mute=%d volindex=%d volgain=%d\n",lMode,theHeadset.gMuted,theHeadset.gHfpVolumeLevel,theHeadset.config->gVolLevels.volumes[theHeadset.gHfpVolumeLevel].hfpGain)); lResult = AudioConnect((TaskData*)gPlugins, HfpGetAudioSink(theHeadset.hfp_hsp), sink_type, theHeadset.theCodecTask, theHeadset.config->gVolLevels.volumes[theHeadset.gHfpVolumeLevel].hfpGain, bandwidth, theHeadset.features.mono ? FALSE : TRUE, lMode, NULL, &theHeadset.task); theHeadset.dsp_process = dsp_process_sco; } return (lResult=TRUE); }
/**************************************************************************** NAME audio_aghfp_connect - Route AGHFP audio */ void audio_aghfp_connect(Sink sink, bool esco, bool wbs, uint16 size_warp, uint16 *warp) { uint16 i = 0; AudioPluginFeatures features = {0,0,0}; /* no stereo or i2s output */ AUDIO_DEBUG(("AUDIO: audio_aghfp_connect\n")); /* start audio active timer */ audio_start_active_timer(); /* remove any A2DP audio */ audio_a2dp_disconnect_all(); theSource->audio_data.audio_aghfp_connect_params.mic = NULL; theSource->audio_data.ag_usb_params.usb_source = usb_get_speaker_source(); /* Set the USB Source */ theSource->audio_data.ag_usb_params.usb_sink = usb_get_mic_sink(); /* Set the USB Sink */ theSource->audio_data.audio_aghfp_connect_params.usb = &theSource->audio_data.ag_usb_params; for (i = 0; i < size_warp; i++) { theSource->audio_data.audio_aghfp_connect_params.warp[i] = warp[i]; } if (theSource->audio_data.audio_routed == AUDIO_ROUTED_NONE) { theSource->audio_data.audio_routed = AUDIO_ROUTED_AGHFP; AudioConnect(audio_aghfp_get_plugin(wbs), sink, esco ? AUDIO_SINK_ESCO : AUDIO_SINK_SCO, theSource->codec, /*aghfp_gain*/10, 8000, features , /* no stereo or I2S output required */ volume_get_mute_mode(), AUDIO_ROUTE_INTERNAL, /*power*/0, &theSource->audio_data.audio_aghfp_connect_params, &theSource->audioTask); } }
/**************************************************************************** NAME connectAudio DESCRIPTION Connects the specified SCO/eSCO channel to the DSP. */ static void connectAudio(Sink audio_sink) { DEBUG_AGHFP((" connectAudio(0x%X)\n", (uint16)audio_sink)); if (audio_sink) { audio_codec_type codec = audio_codec_none; SendEvent(EVT_AUDIO_CONNECT_CFM,0); if(!the_app->bidirect_faststream) { /* Decide the plugin */ the_app->aghfp_audio_plugin = initScoPlugin(); ledSetProfile(LedTypeSCO,TRUE); /* Connect the audio plugin */ AudioConnect(the_app->aghfp_audio_plugin, audio_sink, the_app->sink_type, the_app->codecTask, 0x0a, 0, TRUE, AUDIO_MODE_CONNECTED, (void*)codec ); #ifdef KAL_MSG /* Switch the DSP to SCO mode */ PanicFalse(KalimbaSendMessage(KALIMBA_ENCODER_SELECT, EncoderSco, 0, 0, 0)); #endif AudioSetVolume(the_app->vgs,the_app->codecTask); CodecSetInputGainNow(the_app->codecTask,the_app->vgm,left_and_right_ch); the_app->active_encoder = EncoderSco; } } }
/**************************************************************************** NAME StartHearingDSP DESCRIPTION starts Hearing plugin and DSP with all the desired features, configurations and DAC gain RETURNS void */ void StartHearingDSP(void) { /* ensure sink is valid before trying to route audio */ TaskData *plugin = NULL; /* Configuring Audio features */ AudioPluginFeatures features; features.audio_output_type = OUTPUT_INTERFACE_TYPE_DAC; features.audio_input_routing = AUDIO_ROUTE_INTERNAL; features.use_one_mic_back_channel = 0; features.use_two_mic_back_channel = 0; features.stereo = (theSink.conf2->audio_routing_data.PluginFeatures.stereo) ? TRUE : FALSE; #ifdef HEP_1MIC plugin = (TaskData *)&alango_1mic_hearing_plugin; #elif defined(HEP_2MIC) plugin = (TaskData *)&alango_2mic_hearing_plugin; #endif AUD_DEBUG(("AUD: Start Hearing Mode\n")) ; /*Send works params*/ theSink.HearPhones_conf->Hearing.ActiveHearing = 1; /* connect audio using the audio plugin selected above */ AudioConnect ( plugin, 0 , theSink.profile_data[0].audio.link_type , theSink.codec_task , 10, 16000 , features , AUDIO_MODE_CONNECTED, AUDIO_ROUTE_INTERNAL, powerManagerGetLBIPM(), AUDIO_CONNECT_PARAMS, &theSink.task ); /* setting the desired volume */ AudioSetVolume ( theSink.HearPhones_conf->Hearing.volume , TonesGetToneVolume(FALSE), theSink.codec_task ) ; }
/**************************************************************************** NAME A2dpRouteAudio DESCRIPTION attempt to connect an audio connection from a2dp device via the passed in deviceID RETURNS */ void A2dpRouteAudio(uint8 Index, Sink sink) { AUD_DEBUG(("AudioA2dpRoute Index[%x] Sink[%x]\n", Index , (uint16) sink )) ; /* ensure sink is valid before attempting the connection */ if(sink) { a2dp_codec_settings * codec_settings; AUD_DEBUG(("AudioA2dpRoute Index[%d] DevId[%x]\n", Index , theSink.a2dp_link_data->device_id[Index] )) ; /* get the rate information for connection */ codec_settings = A2dpCodecGetSettings(theSink.a2dp_link_data->device_id[Index], theSink.a2dp_link_data->stream_id[Index]); /* ensure stream is valid */ if(codec_settings) { AudioPluginFeatures features; AUDIO_MODE_T mode = AUDIO_MODE_CONNECTED; uint16 a2dp_gain = theSink.conf1->gVolMaps[ theSink.a2dp_link_data->gAvVolumeLevel[Index] ].A2dpGain; /* determine additional features applicable for this audio plugin */ features.stereo = theSink.features.stereo; features.use_i2s_output = theSink.features.UseI2SOutputCapability; if (theSink.conf1->gVolMaps[ theSink.a2dp_link_data->gAvVolumeLevel[Index] ].A2dpGain == VOLUME_A2DP_MUTE_GAIN) { mode = AUDIO_MODE_MUTE_SPEAKER; } else { /* must take off 1 when passing to audio plugin if not mute; 0 = MUTE, 1 = Gain 0, 2 = Gain 1, etc. */ a2dp_gain--; } /* initialise the AudioConnect extra parameters required to pass in additional codec information */ theSink.a2dp_link_data->a2dp_audio_connect_params.packet_size = codec_settings->codecData.packet_size; /* Packet size retrieved from a2dp library */ theSink.a2dp_link_data->a2dp_audio_connect_params.content_protection = codec_settings->codecData.content_protection; /* content protection retrieved from a2dp library */ theSink.a2dp_link_data->a2dp_audio_connect_params.clock_mismatch = theSink.a2dp_link_data->clockMismatchRate[Index]; /* clock mismatch rate for this device */ theSink.a2dp_link_data->a2dp_audio_connect_params.mode_params = &theSink.a2dp_link_data->a2dp_audio_mode_params; /* EQ mode and Audio enhancements */ #ifdef INCLUDE_A2DP_EXTRA_CODECS #ifdef INCLUDE_FASTSTREAM theSink.a2dp_link_data->a2dp_audio_connect_params.voice_rate = codec_settings->codecData.voice_rate; /* voice rate retrieved from a2dp library */ theSink.a2dp_link_data->a2dp_audio_connect_params.bitpool = codec_settings->codecData.bitpool; /* bitpool retrieved from a2dp library */ theSink.a2dp_link_data->a2dp_audio_connect_params.format = codec_settings->codecData.format; /* format retrieved from a2dp library */ #endif #ifdef INCLUDE_APTX theSink.a2dp_link_data->a2dp_audio_connect_params.channel_mode = codec_settings->channel_mode; /* aptX channel mode */ #endif #ifdef INCLUDE_APTX_ACL_SPRINT theSink.a2dp_link_data->a2dp_audio_connect_params.aptx_sprint_params = codec_settings->codecData.aptx_sprint_params; /* aptX LL params */ #endif #endif #ifdef ENABLE_SOUNDBAR theSink.a2dp_link_data->seid[Index] = codec_settings->seid; #endif /* ENABLE_SOUNDBAR */ #ifdef ENABLE_SUBWOOFER /* set the sub woofer link type prior to passing to audio connect */ theSink.a2dp_link_data->a2dp_audio_connect_params.sub_woofer_type = AUDIO_SUB_WOOFER_NONE; theSink.a2dp_link_data->a2dp_audio_connect_params.sub_sink = NULL; /* bits inverted in dsp plugin */ sinkAudioSetEnhancement(MUSIC_CONFIG_SUB_WOOFER_BYPASS,TRUE); #else /* no subwoofer support, set the sub woofer bypass bit in music config message sent o dsp */ sinkAudioSetEnhancement(MUSIC_CONFIG_SUB_WOOFER_BYPASS,FALSE); #endif AUD_DEBUG(("AudioA2dpRoute Index[%d] DevId[%x] Gain[%x] Codec[%x] ClkMismatch[%x] EQ[%x] packet_size[%u]\n", Index , theSink.a2dp_link_data->device_id[Index], a2dp_gain, codec_settings->seid, theSink.a2dp_link_data->a2dp_audio_connect_params.clock_mismatch, (uint16)theSink.a2dp_link_data->a2dp_audio_connect_params.mode_params, theSink.a2dp_link_data->a2dp_audio_connect_params.packet_size)) ; audioIndicateCodec( codec_settings->seid ); #ifdef ENABLE_SOUNDBAR /* Set the LE SCAN priority to Low since we are Streaming It is possible that we might be receiving less or no LE adverts when streaming is in progress*/ InquirySetPriority(inquiry_low_priority); #endif /* ENABLE_SOUNDBAR */ /* connect the audio via the audio plugin */ AudioConnect( getA2dpPlugin(codec_settings->seid), sink , AUDIO_SINK_AV , theSink.codec_task, a2dp_gain, codec_settings->rate, features , mode, AUDIO_ROUTE_INTERNAL, powerManagerGetLBIPM(), &theSink.a2dp_link_data->a2dp_audio_connect_params, &theSink.task); audioControlLowPowerCodecs (FALSE) ; /* caller responsible for freeing memory */ freePanic(codec_settings); #ifdef ENABLE_AVRCP if(theSink.features.avrcp_enabled) { /* any AVRCP commands should be targeted to the device which has A2DP audio routed */ sinkAvrcpSetActiveConnection(&theSink.a2dp_link_data->bd_addr[Index]); } #endif } /* update the current sink being routed */ theSink.routed_audio = sink; } }
/**************************************************************************** NAME A2dpRouteAudio DESCRIPTION attempt to connect an audio connection from a2dp device via the passed in deviceID RETURNS */ void A2dpRouteAudio(uint8 Index, Sink sink) { AUD_DEBUG(("AudioA2dpRoute Index[%x] Sink[%x]\n", Index , (uint16) sink )) ; /* ensure sink is valid before attempting the connection */ if(sink) { /* Use an instance of A2DP message structure for initial volume setting */ AUDIO_PLUGIN_SET_VOLUME_A2DP_MSG_T volumeInitAudio; a2dp_codec_settings * codec_settings; AUD_DEBUG(("AudioA2dpRoute Index[%d] DevId[%x]\n", Index , theSink.a2dp_link_data->device_id[Index] )) ; /* get the rate information for connection */ codec_settings = A2dpCodecGetSettings(theSink.a2dp_link_data->device_id[Index], theSink.a2dp_link_data->stream_id[Index]); /* ensure stream is valid */ if(codec_settings) { AUDIO_MODE_T mode = AUDIO_MODE_CONNECTED; int16 a2dp_gain_dB; /* determine additional features applicable for this audio plugin */ /* Volume info is sent to DSP in dB units */ a2dp_gain_dB = VolumeConvertStepsToDB(theSink.volume_levels->a2dp_volume[Index].masterVolume, &theSink.conf1->volume_config.volume_control_config, DSP_DB_SCALE); /* check for MUTE volume level and mute as appropriate */ if (theSink.volume_levels->a2dp_volume[Index].masterVolume == VOLUME_A2DP_MUTE_GAIN) { mode = AUDIO_MODE_MUTE_SPEAKER; } /* initialise the AudioConnect extra parameters required to pass in additional codec information */ if (codec_settings->codecData.latency_reporting) /* latency reporting retrieved from a2dp library */ { /* TODO: obtain settings from PS, probably based on codec type */ theSink.a2dp_link_data->a2dp_audio_connect_params.latency.last = 150; theSink.a2dp_link_data->a2dp_audio_connect_params.latency.target = 150/5; theSink.a2dp_link_data->a2dp_audio_connect_params.latency.change = 10/5; theSink.a2dp_link_data->a2dp_audio_connect_params.latency.period = 500/100; } theSink.a2dp_link_data->a2dp_audio_connect_params.packet_size = codec_settings->codecData.packet_size; /* Packet size retrieved from a2dp library */ theSink.a2dp_link_data->a2dp_audio_connect_params.content_protection = codec_settings->codecData.content_protection; /* content protection retrieved from a2dp library */ theSink.a2dp_link_data->a2dp_audio_connect_params.clock_mismatch = theSink.a2dp_link_data->clockMismatchRate[Index]; /* clock mismatch rate for this device */ theSink.a2dp_link_data->a2dp_audio_connect_params.mode_params = &theSink.a2dp_link_data->a2dp_audio_mode_params; /* EQ mode and Audio enhancements */ #ifdef INCLUDE_A2DP_EXTRA_CODECS #ifdef INCLUDE_FASTSTREAM theSink.a2dp_link_data->a2dp_audio_connect_params.voice_rate = codec_settings->codecData.voice_rate; /* voice rate retrieved from a2dp library */ theSink.a2dp_link_data->a2dp_audio_connect_params.bitpool = codec_settings->codecData.bitpool; /* bitpool retrieved from a2dp library */ theSink.a2dp_link_data->a2dp_audio_connect_params.format = codec_settings->codecData.format; /* format retrieved from a2dp library */ #endif #ifdef INCLUDE_APTX theSink.a2dp_link_data->a2dp_audio_connect_params.channel_mode = codec_settings->channel_mode; /* aptX channel mode */ #endif #ifdef INCLUDE_APTX_ACL_SPRINT theSink.a2dp_link_data->a2dp_audio_connect_params.aptx_sprint_params = codec_settings->codecData.aptx_sprint_params; /* aptX LL params */ #endif #endif #ifdef ENABLE_SOUNDBAR theSink.a2dp_link_data->seid[Index] = codec_settings->seid; #endif /* ENABLE_SOUNDBAR */ #ifdef ENABLE_SUBWOOFER /* set the sub woofer link type prior to passing to audio connect */ theSink.a2dp_link_data->a2dp_audio_connect_params.sub_woofer_type = AUDIO_SUB_WOOFER_NONE; theSink.a2dp_link_data->a2dp_audio_connect_params.sub_sink = NULL; /* bits inverted in dsp plugin */ sinkAudioSetEnhancement(MUSIC_CONFIG_SUB_WOOFER_BYPASS,TRUE); #else /* no subwoofer support, set the sub woofer bypass bit in music config message sent o dsp */ sinkAudioSetEnhancement(MUSIC_CONFIG_SUB_WOOFER_BYPASS,FALSE); #endif AUD_DEBUG(("AudioA2dpRoute Index[%d] DevId[%x] Gain[%x] Codec[%x] ClkMismatch[%x] EQ[%x] packet_size[%u]\n", Index , theSink.a2dp_link_data->device_id[Index], a2dp_gain_dB, codec_settings->seid, theSink.a2dp_link_data->a2dp_audio_connect_params.clock_mismatch, (uint16)theSink.a2dp_link_data->a2dp_audio_connect_params.mode_params, theSink.a2dp_link_data->a2dp_audio_connect_params.packet_size)) ; audioIndicateCodec( codec_settings->seid ); #ifdef ENABLE_SOUNDBAR /* Set the LE SCAN priority to Low since we are Streaming It is possible that we might be receiving less or no LE adverts when streaming is in progress*/ InquirySetPriority(inquiry_low_priority); #endif /* ENABLE_SOUNDBAR */ /* We need to set A2DP volume info as the audio is in mute state after connection */ volumeInitAudio.volume_type = theSink.conf1->volume_config.volume_control_config.volume_type; volumeInitAudio.codec_task = theSink.codec_task; volumeInitAudio.master_gain = a2dp_gain_dB; volumeInitAudio.system_gain = theSink.conf1->volume_config.volume_control_config.system_volume; volumeInitAudio.trim_gain_left = theSink.conf1->volume_config.volume_control_config.trim_volume_left; volumeInitAudio.trim_gain_right= theSink.conf1->volume_config.volume_control_config.trim_volume_right; volumeInitAudio.device_trim_master = theSink.conf1->volume_config.volume_control_config.device_trim_master; volumeInitAudio.device_trim_slave = theSink.conf1->volume_config.volume_control_config.device_trim_slave; volumeInitAudio.tones_gain = VolumeConvertStepsToDB(((TonesGetToneVolume(FALSE) * theSink.conf1->volume_config.volume_control_config.no_of_steps)/VOLUME_NUM_VOICE_STEPS), &theSink.conf1->volume_config.volume_control_config, DSP_DB_SCALE); volumeInitAudio.mute_active = theSink.sink_enable_present; /* connect the audio via the audio plugin */ AudioConnect(getA2dpPlugin(codec_settings->seid), sink , AUDIO_SINK_AV , theSink.codec_task, volumeInitAudio.tones_gain, codec_settings->rate, theSink.conf2->audio_routing_data.PluginFeatures , mode, AUDIO_ROUTE_INTERNAL, powerManagerGetLBIPM(), &theSink.a2dp_link_data->a2dp_audio_connect_params, FALSE, &theSink.task); AudioSetVolumeA2DP(&volumeInitAudio); #ifdef ENABLE_SUBWOOFER /* set subwoofer volume level */ updateSwatVolume(theSink.volume_levels->a2dp_volume[Index].masterVolume); SWAT_DEBUG(("SW : Send sample rate to Sub, rate is %ld\n",codec_settings->rate)); /* send sample rate to sub */ sendSampleRateToSub(codec_settings->rate); #endif audioControlLowPowerCodecs (FALSE) ; /* caller responsible for freeing memory */ freePanic(codec_settings); #ifdef ENABLE_AVRCP if(theSink.features.avrcp_enabled) { UpdateAvrpcMessage_t * lUpdateMessage = mallocPanic ( sizeof(UpdateAvrpcMessage_t) ) ; lUpdateMessage->bd_addr = theSink.a2dp_link_data->bd_addr[Index]; /* any AVRCP commands should be targeted to the device which has A2DP audio routed */ MessageSend( &theSink.task, EventSysSetActiveAvrcpConnection, lUpdateMessage); } #endif } /* update the current sink being routed */ theSink.routed_audio = sink; } }
/**************************************************************************** NAME sinkFmRxAudioConnect DESCRIPTION connects the I2S FM audio via the FM audio plugin which allows tones play and volume control RETURNS nothing */ void sinkFmRxAudioConnect(void) { AUDIO_PLUGIN_SET_VOLUME_A2DP_MSG_T volumeDsp; uint16 volume_dB = VolumeConvertStepsToDB(theSink.volume_levels->fm_volume.masterVolume, &theSink.conf1->volume_config.volume_control_config, DSP_DB_SCALE); uint16 mode = (theSink.volume_levels->fm_volume.masterVolume == VOLUME_A2DP_MUTE_GAIN) ? AUDIO_MODE_MUTE_SPEAKER : AUDIO_MODE_CONNECTED; FM_DEBUG(("sinkFmRxAudioConnect \n")); theSink.volume_levels->fm_volume.tonesVolume = VolumeConvertStepsToDB(((TonesGetToneVolume(FALSE) * theSink.conf1->volume_config.volume_control_config.no_of_steps)/VOLUME_NUM_VOICE_STEPS), &theSink.conf1->volume_config.volume_control_config, DSP_DB_SCALE); /* Make sure we're using correct parameters for FM audio */ theSink.a2dp_link_data->a2dp_audio_connect_params.mode_params = &theSink.a2dp_link_data->a2dp_audio_mode_params; #ifdef ENABLE_SUBWOOFER /* set the sub woofer link type prior to passing to audio connect */ theSink.a2dp_link_data->a2dp_audio_connect_params.sub_woofer_type = AUDIO_SUB_WOOFER_NONE; theSink.a2dp_link_data->a2dp_audio_connect_params.sub_sink = NULL; /* bits inverted in dsp plugin */ sinkAudioSetEnhancement(MUSIC_CONFIG_SUB_WOOFER_BYPASS,TRUE); #else /* no subwoofer support, set the sub woofer bypass bit in music config message sent o dsp */ sinkAudioSetEnhancement(MUSIC_CONFIG_SUB_WOOFER_BYPASS,FALSE); #endif FM_DEBUG(("FM: Routing (Vol %d)\n", theSink.volume_levels->fm_volume.masterVolume)); AudioConnect((TaskData *)&csr_fm_decoder_plugin, theSink.routed_audio, AUDIO_SINK_FM, theSink.codec_task, volume_dB, FM_RATE, theSink.conf2->audio_routing_data.PluginFeatures, mode, AUDIO_ROUTE_INTERNAL, powerManagerGetLBIPM(), &theSink.a2dp_link_data->a2dp_audio_connect_params, &theSink.task); audioControlLowPowerCodecs (FALSE) ; /* update volume via a2dp common plugin */ volumeDsp.volume_type = theSink.conf1->volume_config.volume_control_config.volume_type; volumeDsp.codec_task = theSink.codec_task; volumeDsp.master_gain = volume_dB; volumeDsp.tones_gain = theSink.volume_levels->fm_volume.tonesVolume; volumeDsp.system_gain = theSink.conf1->volume_config.volume_control_config.system_volume; volumeDsp.trim_gain_left = theSink.conf1->volume_config.volume_control_config.trim_volume_left; volumeDsp.trim_gain_right= theSink.conf1->volume_config.volume_control_config.trim_volume_right; volumeDsp.device_trim_master = theSink.conf1->volume_config.volume_control_config.device_trim_master; volumeDsp.device_trim_slave = theSink.conf1->volume_config.volume_control_config.device_trim_slave; volumeDsp.mute_active = theSink.sink_mute_status; AudioSetVolumeA2DP ( &volumeDsp); #ifdef ENABLE_SUBWOOFER /* set subwoofer volume level */ updateSwatVolume(volume_dB); #endif /* tune to stored frequency after initilising the I2S interface otherwise FM receiver may be in an unknown state which may not work reliably */ fmRxTuneFrequency(theSink.conf2->sink_fm_data.fmRxTunedFreq); }
/**************************************************************************** NAME a2dpStreamConnectA2dpAudio DESCRIPTION To connnect the audio plugin for a2dp audio streaming; */ void a2dpStreamConnectA2dpAudio(Sink media_sink) { uint16 i, counter = 0; Sink media_sink_arr[MAX_NUM_DEV_CONNECTIONS]; DEBUG_A2DP(("a2dpStreamConnectA2dpAudio\n")); MessageCancelAll(&the_app->task, APP_CONNECT_A2DP_AUDIO); if (the_app->active_encoder == EncoderAv) { /* This indicates streaming is already active and now a second audio connection has to be routed. Use the AudioSetMode function to start the second audio stream. */ dualstream_mode_params *dual_mode = (dualstream_mode_params *)PanicUnlessMalloc(sizeof(dualstream_mode_params)); dual_mode->connect_sink = TRUE; /* Indicate the audio is being connected */ dual_mode->media_sink = media_sink; /* Supply the second media sink that is being connected */ AudioSetMode(AUDIO_MODE_CONNECTED, (void*)dual_mode); DEBUG_A2DP(("AudioSetMode connect_sink:0x%x \n",(uint16)media_sink)); } else { /* No audio is currently active, so route the audio for all active streams */ for (i = 0; i < MAX_NUM_DEV_CONNECTIONS; i++) { if ((the_app->dev_inst[i] != NULL) && (the_app->dev_inst[i]->a2dp_state == A2dpStateStreaming)) { DEBUG_A2DP(("*** streaming found i:%d a2dp:0x%x sink:0x%x ***\n",i,(uint16)the_app->dev_inst[i]->a2dp, (uint16)the_app->dev_inst[i]->a2dp_media_sink)); media_sink_arr[counter++] = the_app->dev_inst[i]->a2dp_media_sink; } } /* Pass the second media sink as a parameter into the AudioConnect function that the audio plugin can recognise. */ if (counter > 1) { the_app->a2dp_data.codecData.media_sink_b = media_sink_arr[1]; } else { the_app->a2dp_data.codecData.media_sink_b = 0; } /* Connect the audio plugin */ AudioConnect(the_app->a2dp_audio_plugin , media_sink_arr[0] , AUDIO_SINK_AV , the_app->codecTask, 0x0a , the_app->a2dp_sample_rate , (TRUE), AUDIO_MODE_CONNECTED, (source_codec_data_type *) &the_app->a2dp_data.codecData ) ; the_app->active_encoder = EncoderAv; DEBUG_A2DP(("AudioConnect devices:%d\n",counter)); } }
/**************************************************************************** NAME audio_a2dp_connect - Route A2DP audio */ void audio_a2dp_connect(Sink sink, uint16 device_id, uint16 stream_id) { uint8 bitpool; uint8 bad_link_bitpool; bool multiple_streams; /* start audio active timer */ audio_start_active_timer(); /* remove any AGHFP audio */ audio_aghfp_disconnect(); AUDIO_DEBUG(("AUDIO: audio_a2dp_connect\n")); if (theSource->audio_data.audio_routed == AUDIO_ROUTED_NONE) { theSource->audio_data.audio_a2dp_connect_params.input_source = usb_get_speaker_source(); /* Set the USB Source, not used for Analogue */ theSource->audio_data.audio_a2dp_connect_params.input_sink = usb_get_mic_sink(); /* Set the USB Sink, not used for Analogue */ theSource->audio_data.audio_a2dp_connect_params.a2dp_sink[device_id] = sink; /* Set the A2DP media Sink */ AUDIO_DEBUG((" audio_routed [%d] input_source [0x%x] input_sink [0x%x] a2dp_sink_0 [0x%x] a2dp_sink_1 [0x%x]\n", theSource->audio_data.audio_routed, (uint16)theSource->audio_data.audio_a2dp_connect_params.input_source, (uint16)theSource->audio_data.audio_a2dp_connect_params.input_sink, (uint16)theSource->audio_data.audio_a2dp_connect_params.a2dp_sink[0], (uint16)theSource->audio_data.audio_a2dp_connect_params.a2dp_sink[1])); if (theSource->audio_data.audio_a2dp_connect_params.a2dp_sink[0] || theSource->audio_data.audio_a2dp_connect_params.a2dp_sink[1]) { AudioPluginFeatures features = {0,0,0}; /* no stereo or i2s output */ a2dp_codec_settings *codec_settings = A2dpCodecGetSettings(device_id, stream_id); if (codec_settings) { AUDIO_DEBUG((" codec ; voice_rate[0x%lx] packet_size[0x%x] bitpool[0x%x] format[0x%x] CP[0x%x]\n", codec_settings->codecData.voice_rate, codec_settings->codecData.packet_size, codec_settings->codecData.bitpool, codec_settings->codecData.format, codec_settings->codecData.content_protection )); theSource->audio_data.audio_a2dp_connect_params.rate = codec_settings->codecData.voice_rate; theSource->audio_data.audio_a2dp_connect_params.packet_size = codec_settings->codecData.packet_size; if (a2dp_get_sbc_bitpool(&bitpool, &bad_link_bitpool, &multiple_streams)) { theSource->audio_data.audio_a2dp_connect_params.bitpool = bitpool; theSource->audio_data.audio_a2dp_connect_params.bad_link_bitpool = bad_link_bitpool; } else { theSource->audio_data.audio_a2dp_connect_params.bitpool = codec_settings->codecData.bitpool; } theSource->audio_data.audio_a2dp_connect_params.format = codec_settings->codecData.format; theSource->audio_data.audio_a2dp_mode_params.eq_mode = theSource->volume_data.eq_index; theSource->audio_data.audio_a2dp_connect_params.mode = &theSource->audio_data.audio_a2dp_mode_params; /* turn on content protection if negotiated */ theSource->audio_data.audio_a2dp_connect_params.content_protection = codec_settings->codecData.content_protection; /* remember if the remote device supports bidirectional audio, i.e. has a MIC back channel */ theSource->audio_data.audio_remote_bidir_support = audio_is_bidir_supported(codec_settings) ? 1 : 0; theSource->audio_data.audio_routed = AUDIO_ROUTED_A2DP; audio_a2dp_get_plugin(); AudioConnect(audio_a2dp_get_plugin(), 0, AUDIO_SINK_AV, theSource->codec, /*a2dp_gain*/10, codec_settings->rate, features, /* stereo supported, no i2s output */ volume_get_mute_mode(), AUDIO_ROUTE_INTERNAL, /*power*/0, &theSource->audio_data.audio_a2dp_connect_params, &theSource->audioTask); /* free the codec_settings memory that the A2DP library allocated */ memory_free(codec_settings); } } } else if (theSource->audio_data.audio_routed == AUDIO_ROUTED_A2DP) { /* connecting additional A2DP device */ theSource->audio_data.audio_a2dp_connect_params.a2dp_sink[device_id] = sink; theSource->audio_data.audio_a2dp_mode_params.connect_sink = sink; if (a2dp_get_sbc_bitpool(&bitpool, &bad_link_bitpool, &multiple_streams)) { theSource->audio_data.audio_a2dp_mode_params.bitpool = bitpool; theSource->audio_data.audio_a2dp_mode_params.bad_link_bitpool = bad_link_bitpool; } AUDIO_DEBUG((" audio_routed [%d] connect_sink [0x%x] bitpool [%d] bad_link_bitpool [%d]\n", theSource->audio_data.audio_routed, (uint16)sink, bitpool, bad_link_bitpool)); audio_update_mode_parameters(); } }