/**************************************************************************** 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 usbGetVolume DESCRIPTION Extract USB volume setting from USB lib levels RETURNS Volume to pass to csr_usb_audio_plugin */ static uint16 usbGetVolume(AUDIO_MODE_T* mode) { uint16 result; bool mic_muted; bool spk_muted = FALSE; /* Get vol settings from USB lib */ usb_device_class_audio_levels levels; UsbDeviceClassGetValue(USB_DEVICE_CLASS_GET_VALUE_AUDIO_LEVELS, (uint16*)&levels); /* limit check volume levels returned */ if((levels.out_l_vol < 0)||(levels.out_l_vol > VOLUME_A2DP_MAX_LEVEL)) levels.out_l_vol = VOLUME_A2DP_MAX_LEVEL; if((levels.out_r_vol < 0)||(levels.out_r_vol > VOLUME_A2DP_MAX_LEVEL)) levels.out_r_vol = VOLUME_A2DP_MAX_LEVEL; USB_DEBUG(("USB: Gain L %X R %X\n", levels.out_l_vol, levels.out_r_vol)); USB_DEBUG(("USB: Mute M %X S %X\n", levels.in_mute, levels.out_mute)); if(theSink.usb.config.plugin_type == usb_plugin_stereo) { /* Use A2DP gain mappings */ uint8 l_vol = theSink.conf1->gVolMaps[ levels.out_l_vol ].A2dpGain; uint8 r_vol = theSink.conf1->gVolMaps[ levels.out_r_vol ].A2dpGain; /* Convert A2DP gain setting to mute/gain */ spk_muted = (r_vol == 0 && l_vol == 0); if(r_vol > 0) r_vol --; if(l_vol > 0) l_vol --; /* Pack result */ result = ((l_vol << 8) | r_vol); displayUpdateVolume((levels.out_l_vol + levels.out_r_vol + 1) / 2); #ifdef ENABLE_SUBWOOFER updateSwatVolume((levels.out_l_vol + levels.out_r_vol + 1) / 2); #endif } else { /* Use HFP gain mappings */ result = theSink.conf1->gVolMaps[ levels.out_l_vol ].VolGain; displayUpdateVolume(levels.out_l_vol); #ifdef ENABLE_SUBWOOFER updateSwatVolume(levels.out_l_vol); #endif } /* Mute if muted by host or not supported */ mic_muted = levels.in_mute || !USB_CLASS_ENABLED(USB_DEVICE_CLASS_TYPE_AUDIO_MICROPHONE); spk_muted = spk_muted || levels.out_mute || !USB_CLASS_ENABLED(USB_DEVICE_CLASS_TYPE_AUDIO_SPEAKER); if(mode) { if(mic_muted && spk_muted) *mode = AUDIO_MODE_MUTE_BOTH; else if(mic_muted) *mode = AUDIO_MODE_MUTE_MIC; else if(spk_muted) *mode = AUDIO_MODE_MUTE_SPEAKER; else *mode = AUDIO_MODE_CONNECTED; } return result; }
/**************************************************************************** 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); }