/**************************************************************************** DESCRIPTION connect the subwoofer if a subwoofer link has been established */ void CsrA2dpDecoderPluginConnectSubwoofer(A2dpPluginConnectParams *codecData) { DECODER_t * DECODER = CsrA2dpDecoderGetDecoderData(); PRINT(("DECODER:Try to connect sub\n")); /* ensure the decoder is loaded */ if(codecData) { /* if the sub woofer is available at connection time? */ if(codecData->sub_woofer_type != AUDIO_SUB_WOOFER_NONE) { /* determine the sub link type */ switch(codecData->sub_woofer_type) { /* SUB using esco as its bt link, connect to dsp port 2 */ case AUDIO_SUB_WOOFER_ESCO: /* ensure the correct ype of link is requested */ if(DECODER->sink_type != AUDIO_SINK_AV) { PRINT(("DECODER: connect esco sub\n")); /* connect SUB output from dsp, source port 2, to esco sink */ StreamConnect(StreamKalimbaSource(DSP_ESCO_SUB_PORT),codecData->sub_sink); /* update port connection status */ codecData->sub_connection_port = DSP_ESCO_SUB_PORT; /* set volume levels to desired level */ SubConnectedNowUnmuteVolume(DECODER); } else PRINT(("DECODER: connect esco sub - ***wrong type***\n")); break; /* SUB using l2cap as its bt link, connect to dsp port 3 */ case AUDIO_SUB_WOOFER_L2CAP: /* ensure the correct ype of link is requested */ if(DECODER->sink_type == AUDIO_SINK_AV) { PRINT(("DECODER: connect l2cap sub\n")); /* connect SUB output from dsp, source port 3, to l2cap sink */ StreamConnect(StreamKalimbaSource(DSP_L2CAP_SUB_PORT),codecData->sub_sink); /* update port connection status */ codecData->sub_connection_port = DSP_L2CAP_SUB_PORT; /* set volume levels to desired level */ SubConnectedNowUnmuteVolume(DECODER); } else PRINT(("DECODER: connect l2cap sub - ***wrong type***\n")); break; default: break; } } } }
/**************************************************************************** DESCRIPTION Disconnect Sync audio */ void CsrSbcEncoderPluginDisconnect( void ) { uint16 i; if (!SBC) Panic() ; /* StreamDisconnect(0, StreamKalimbaSink(0)); KalimbaPowerOff() ; */ for (i = 0; i < MAX_AUDIO_SINKS; i++) { if (SBC->media_sink[i] != 0) { /* Disconnect the Kalimba source from the media sink */ StreamDisconnect(StreamKalimbaSource(i+2), SBC->media_sink[i]); PRINT(("Audio Plugin: Disconnect media i:%d sink:0x%x\n",i,(uint16)SBC->media_sink[i])); /* clear the audio sink */ SBC->media_sink[i] = 0; } } free (SBC); SBC = NULL ; }
void CsrSubwooferPluginDisconnect(void) { /* Disconnect the appropriate input to Kalimba */ if (plugin_data->input == SUBWOOFER_INPUT_ADC) { PRINT(("[SW_PLUGIN : Disconnect ADC to Kalimba\n")); StreamDisconnect(plugin_data->audio_source, StreamKalimbaSink(DSP_INPUT_PORT_ADC)); } else if (plugin_data->input == SUBWOOFER_INPUT_ESCO) { PRINT(("[SW_PLUGIN] Disconnect eSCO to Kalimba\n")); StreamDisconnect(plugin_data->audio_source, StreamKalimbaSink(DSP_INPUT_PORT_ESCO)); StreamConnectDispose(plugin_data->audio_source); } else if (plugin_data->input == SUBWOOFER_INPUT_L2CAP) { PRINT(("[SW_PLUGIN] Disconnect L2CAP to Kalimba\n")); StreamDisconnect(plugin_data->audio_source, StreamKalimbaSink(DSP_INPUT_PORT_L2CAP)); StreamConnectDispose(plugin_data->audio_source); } /* Disconnect the appropriate output from Kalimba */ if (plugin_data->output == SUBWOOFER_OUTPUT_DAC) { PRINT(("[SW_PLUGIN] Disconnect Kalimba to DAC\n")); StreamDisconnect(StreamKalimbaSource(DSP_OUTPUT_PORT_DAC), plugin_data->codec_sink); } else if (plugin_data->output == SUBWOOFER_OUTPUT_I2S) { PRINT(("[SW_PLUGIN] Disconnect Kalimba to I2S\n")); CsrI2SAudioOutputDisconnect(TRUE); } /* dispose of any remaining messages in the queue */ (void) MessageCancelAll( (TaskData*)&csr_subwoofer_plugin, MESSAGE_FROM_KALIMBA); MessageKalimbaTask( NULL ); /* Everything has been disconnected so power down Kalimba */ KalimbaPowerOff(); /* reset flags */ SetAudioInUse(FALSE); SetCurrentDspStatus(DSP_NOT_LOADED); /* Free the memory allocated to use for the plugin as it's no longer valid */ free(plugin_data); plugin_data = NULL; }
/**************************************************************************** DESCRIPTION disconnect the subwoofer if currently connected */ void CsrA2dpDecoderPluginDisconnectSubwoofer(void) { DECODER_t * DECODER = CsrA2dpDecoderGetDecoderData(); /* ensure the decoder is loaded */ if(DECODER) { A2dpPluginConnectParams *codecData = (A2dpPluginConnectParams *) DECODER->params; /* if the sub woofer is connected then disconnect it */ if(codecData->sub_connection_port != DSP_SUB_PORT_NOT_CONNECTED) { PRINT(("DECODER: CsrA2dpDecoderPluginDisconnect disconnect sub\n")); /* disconnect kalimba port, this causes dsp app to switch clock source internally */ StreamDisconnect(StreamKalimbaSource(codecData->sub_connection_port), codecData->sub_sink ); /* update connected ports state */ codecData->sub_connection_port = DSP_SUB_PORT_NOT_CONNECTED; } } }
void A2dpStartKalimbaStreaming(const A2DP *a2dp, uint16 media_sink) { FILE_INDEX index = FILE_NONE; #ifdef BUILD_FOR_23FW Transform t; #else Transform t, l_t, r_t; Source l_src = StreamAudioSource(AUDIO_HARDWARE_CODEC, AUDIO_INSTANCE_0, AUDIO_CHANNEL_A); Source r_src = StreamAudioSource(AUDIO_HARDWARE_CODEC, AUDIO_INSTANCE_1, AUDIO_CHANNEL_B); Sink l_snk = StreamAudioSink(AUDIO_HARDWARE_CODEC, AUDIO_INSTANCE_0, AUDIO_CHANNEL_A); Sink r_snk = StreamAudioSink(AUDIO_HARDWARE_CODEC, AUDIO_INSTANCE_1, AUDIO_CHANNEL_B); #endif /* load SBC codec */ index = FileFind(FILE_ROOT, sbc_encoder, sizeof(sbc_encoder)-1); if (!KalimbaLoad(index)) /* codec load failure, Panic as the test isn't going to work now */ Panic(); /* Init and configure RTP */ t = TransformRtpSbcEncode(StreamKalimbaSource(0), (Sink)media_sink); TransformConfigure(t, VM_TRANSFORM_RTP_SBC_ENCODE_PACKET_SIZE, 668); TransformConfigure(t, VM_TRANSFORM_RTP_SBC_ENCODE_MANAGE_TIMING, FALSE); (void)TransformStart(t); /* Configure SBC encoding format */ (void)PanicFalse(KalimbaSendMessage(KALIMBA_MSG_SBCENC_SET_PARAMS, 0x00bd, 0, 0, 0)); (void)PanicFalse(KalimbaSendMessage(KALIMBA_MSG_SBCENC_SET_BITPOOL, 0x0030, 0, 0, 0)); #ifdef BUILD_FOR_23FW StreamDisconnect(StreamPcmSource(0), StreamPcmSink(0)); StreamDisconnect(StreamPcmSource(1), StreamPcmSink(1)); /* set up ADCs */ (void)PcmClearAllRouting(); (void)PanicFalse(PcmRateAndRoute(0, PCM_NO_SYNC, 44100, 44100, VM_PCM_INTERNAL_A)); (void)PanicFalse(PcmRateAndRoute(1, 0, 44100, 44100, VM_PCM_INTERNAL_B)); (void)PanicFalse(StreamConnect(StreamPcmSource(0),StreamKalimbaSink(0))); (void)PanicFalse(StreamConnect(StreamPcmSource(1),StreamKalimbaSink(1))); #else SourceClose(l_src); SourceClose(r_src); SinkClose(l_snk); SinkClose(r_snk); (void) SourceConfigure(l_src, STREAM_CODEC_INPUT_RATE, 44100); (void) SourceConfigure(r_src, STREAM_CODEC_INPUT_RATE, 44100); (void) SourceSynchronise(l_src, r_src); /* set up ADCs */ l_t = StreamConnect(l_src, StreamKalimbaSink(0)); r_t = StreamConnect(r_src, StreamKalimbaSink(1)); (void)TransformStart(l_t); (void)TransformStart(r_t); #endif /* Start decode */ (void) PanicFalse(KalimbaSendMessage(KALIMBA_MSG_GO,0,0,0,0)); }
/**************************************************************************** DESCRIPTION configure the sub woofer and connect its audio if present */ void CsrA2dpDecoderPluginSetSubWoofer(AUDIO_SUB_TYPE_T sub_type, Sink sub_sink) { DECODER_t * DECODER = CsrA2dpDecoderGetDecoderData(); /* ensure the decoder is loaded */ if(DECODER) { A2dpPluginConnectParams *codecData = (A2dpPluginConnectParams *) DECODER->params; /* update the decoder params with the new sub woofer status */ codecData->sub_woofer_type = sub_type; codecData->sub_sink = sub_sink; /* determine sub woofer type and connect (or disconnect if gone away) the sink to the appropriate dsp port */ switch(sub_type) { /* SUB no longer available, disconnect port if still connected */ case AUDIO_SUB_WOOFER_NONE: PRINT(("DECODER: Disconnect woofer\n" )); /* if source is still connected then disconnect it */ if(codecData->sub_connection_port != DSP_SUB_PORT_NOT_CONNECTED) { /* determine if the subwoofer has connected after the decoder was loaded, configured and unmuted */ if(codecData->sub_is_available == FALSE) { /* mute the outputs whilst the subwoofer port is connected and decoder restarted */ csrA2dpDecoderPluginOutputMute(multi_channel_group_all, AUDIO_MUTE_ENABLE); } PRINT(("DECODER: Disconnect kalimba port %x\n", codecData->sub_connection_port)); StreamDisconnect(StreamKalimbaSource(codecData->sub_connection_port), 0); /* update connected ports state */ codecData->sub_connection_port = DSP_SUB_PORT_NOT_CONNECTED; /* set volume levels to desired level */ SubConnectedNowUnmuteVolume(DECODER); /* determine if the subwoofer has connected after the decoder was loaded, configured and unmuted */ if(codecData->sub_is_available == FALSE) { /* unmute the outputs again */ csrA2dpDecoderPluginOutputMute(multi_channel_group_all, AUDIO_MUTE_DISABLE); } } break; /* SUB using esco as its bt link, connect to dsp port 2 */ case AUDIO_SUB_WOOFER_ESCO: PRINT(("DECODER: connect esco dsp port 2, sub_sink = %x\n", (uint16)sub_sink )); /* ensure the correct ype of link is requested */ if(DECODER->sink_type != AUDIO_SINK_AV) { /* connect SUB output from dsp, source port 2, to esco sink */ if(codecData->sub_connection_port != DSP_ESCO_SUB_PORT) { /* determine if the subwoofer has connected after the decoder was loaded, configured and unmuted */ if(codecData->sub_is_available == FALSE) { /* mute the outputs whilst the subwoofer port is connected and decoder restarted */ csrA2dpDecoderPluginOutputMute(multi_channel_group_all, AUDIO_MUTE_ENABLE); } /* if not already connected */ if(codecData->sub_connection_port == DSP_L2CAP_SUB_PORT) { /* wrong port connected, disconnect it first */ StreamDisconnect(StreamKalimbaSource(codecData->sub_connection_port), 0); PRINT(("DECODER: Disconnect kalimba port %x\n", codecData->sub_connection_port)); } /* ensure sink is valid */ if(SinkIsValid(sub_sink)) { /* connect esco (2) port */ if(StreamConnect(StreamKalimbaSource(DSP_ESCO_SUB_PORT),sub_sink)) { /* update connected ports state */ codecData->sub_connection_port = DSP_ESCO_SUB_PORT; PRINT(("DECODER: Connect kalimba port %x\n", codecData->sub_connection_port)); /* set volume levels to desired level */ SubConnectedNowUnmuteVolume(DECODER); } else PRINT(("DECODER: connect esco dsp port 2 FAILED\n" )); } else { PRINT(("DECODER: connect esco dsp port 2, sub_sink = %x NOT VALID\n", (uint16)sub_sink )); } /* determine if the subwoofer has connected after the decoder was loaded, configured and unmuted */ if(codecData->sub_is_available == FALSE) { /* unmute the outputs again */ csrA2dpDecoderPluginOutputMute(multi_channel_group_all, AUDIO_MUTE_DISABLE); } } } else PRINT(("DECODER: ESCO - ****wrong link type****\n")); break; /* SUB using l2cap as its bt link, connect to dsp port 3 */ case AUDIO_SUB_WOOFER_L2CAP: PRINT(("DECODER: connect l2cap dsp port 3, sub_sink = %x\n", (uint16)sub_sink )); /* ensure the correct ype of link is requested */ if(DECODER->sink_type == AUDIO_SINK_AV) { /* connect SUB output from dsp, source port 2, to esco sink */ if(codecData->sub_connection_port != DSP_L2CAP_SUB_PORT) { /* determine if the subwoofer has connected after the decoder was loaded, configured and unmuted */ if(codecData->sub_is_available == FALSE) { /* mute the outputs whilst the subwoofer port is connected and decoder restarted */ csrA2dpDecoderPluginOutputMute(multi_channel_group_all, AUDIO_MUTE_ENABLE); } /* if not already connected */ if(codecData->sub_connection_port == DSP_ESCO_SUB_PORT) { /* wrong port connected, disconnect it first */ StreamDisconnect(StreamKalimbaSource(codecData->sub_connection_port), 0); PRINT(("DECODER: Disconnect kalimba port %x\n", codecData->sub_connection_port)); } /* ensure sink is valid */ if(SinkIsValid(sub_sink)) { /* connect l2cap (3) port */ if(StreamConnect(StreamKalimbaSource(DSP_L2CAP_SUB_PORT),sub_sink)) { /* update connected ports state */ codecData->sub_connection_port = DSP_L2CAP_SUB_PORT; PRINT(("DECODER: Connect kalimba port %x\n", codecData->sub_connection_port)); /* set volume levels to desired level */ SubConnectedNowUnmuteVolume(DECODER); } else PRINT(("DECODER: connect l2cap dsp port 3 FAILED\n" )); } else { PRINT(("DECODER: connect l2cap dsp port 3, sub_sink = %x NOT VALID\n", (uint16)sub_sink )); } /* determine if the subwoofer has connected after the decoder was loaded, configured and unmuted */ if(codecData->sub_is_available == FALSE) { /* unmute the outputs again */ csrA2dpDecoderPluginOutputMute(multi_channel_group_all, AUDIO_MUTE_DISABLE); } } } else PRINT(("DECODER: L2CAP - ****wrong link type****\n")); break; } } else PRINT(("DECODER: CsrA2dpDecoderPluginSetSubWoofer ERROR NO DECODER\n" )); }
/**************************************************************************** NAME connectAudioStreams DESCRIPTION Helper function to connect the audio streams */ static void connectAudioStreams(void) { /* Connect the appropriate input stream to Kalimba */ if (plugin_data->input == SUBWOOFER_INPUT_ADC) { PRINT(("[SW_PLUGIN] : Plugging ADC to Kalimba [%u]\n", plugin_data->adc_sample_rate)); /* Configure the ADC */ PanicFalse( SourceConfigure(plugin_data->audio_source, STREAM_CODEC_INPUT_RATE, plugin_data->adc_sample_rate) ); /* Plug the ADC sink into the Kalimba */ PanicFalse( StreamConnect(plugin_data->audio_source, StreamKalimbaSink(DSP_INPUT_PORT_ADC)) ); } else if (plugin_data->input == SUBWOOFER_INPUT_ESCO) { /* Enable meta-data on the audio input */ if ( SourceConfigure(plugin_data->audio_source, VM_SOURCE_SCO_METADATA_ENABLE, 1)) { /* Plug the eSCO sink into the Kalimba */ if ( !StreamConnect(plugin_data->audio_source, StreamKalimbaSink(DSP_INPUT_PORT_ESCO)) ) { PRINT(("[SW_PLUGIN] : Plugging ESCO to Kalimba [FAILED]\n")); sendErrorToClient(); /* Nothing more can be done here */ return; } else { PRINT(("[SW_PLUGIN] : ESCO connected to Kalimba\n")); } } else { PRINT(("[SW_PLUGIN] : Plugging ESCO to Kalimba [FAILED]\n")); sendErrorToClient(); /* Nothing more can be done here */ return; } } else if (plugin_data->input == SUBWOOFER_INPUT_L2CAP) { /* Plug the L2CAP sink into the Kalimba */ if ( !StreamConnect(plugin_data->audio_source, StreamKalimbaSink(DSP_INPUT_PORT_L2CAP)) ) { PRINT(("[SW_PLUGIN] : Plugging L2CAP to Kalimba [FAILED]\n")); sendErrorToClient(); /* Nothing more can be done here */ return; } else { PRINT(("[SW_PLUGIN] : L2CAP connected to Kalimba\n")); } } else { PRINT(("[SW_PLUGIN] : Plugin parameter INPUT[%x] is invalid\n", plugin_data->input)); Panic(); } /* Connect Kalimba to the appropriate output stream */ if (plugin_data->output == SUBWOOFER_OUTPUT_DAC) { /* Get the Codec DAC sink & Configure output rate */ plugin_data->codec_sink = StreamAudioSink(AUDIO_HARDWARE_CODEC, AUDIO_INSTANCE_0, AUDIO_CHANNEL_A_AND_B); if ( !SinkConfigure(plugin_data->codec_sink, STREAM_CODEC_OUTPUT_RATE, plugin_data->sample_rate) ) { PRINT(("[SW_PLUGIN] : Could not configure DAC [%u]\n", plugin_data->sample_rate)); sendErrorToClient(); /* Nothing more can be done here */ return; } /* Plug the audio route from Kalimba to the DAC */ if ( !StreamConnect(StreamKalimbaSource(DSP_OUTPUT_PORT_DAC), plugin_data->codec_sink) ) { PRINT(("[SW_PLUGIN] : Could not connect DAC to Kalimba[%u]\n", plugin_data->sample_rate)); sendErrorToClient(); /* Nothing more can be done here */ return; } PRINT(("[SW_PLUGIN] : Kalimba connected to DAC\n")); } else if (plugin_data->output == SUBWOOFER_OUTPUT_I2S) { PRINT(("[SW_PLUGIN] : Plugging Kalimba to I2S [%u]\n", plugin_data->sample_rate)); /* Is a specified output frequency required? use resampling */ if(CsrI2SMusicResamplingFrequency()) { CsrI2SAudioOutputConnect(CsrI2SMusicResamplingFrequency(), FALSE, StreamKalimbaSource(DSP_OUTPUT_PORT_I2S), NULL); } else { CsrI2SAudioOutputConnect(plugin_data->sample_rate, FALSE, StreamKalimbaSource(DSP_OUTPUT_PORT_I2S), NULL); } } else { PRINT(("[SW_PLUGIN] : Plugin parameter OUTPUT[%x] is invalid\n", plugin_data->output)); Panic(); } /* set dsp operating flags */ SetCurrentDspStatus(DSP_RUNNING); SetAudioInUse(TRUE); }
/**************************************************************************** DESCRIPTION This function connects a synchronous audio stream to the pcm subsystem */ void CsrSbcEncoderPluginConnect( Sink audio_sink , Task codec_task , uint16 volume , uint32 rate , bool stereo , AUDIO_MODE_T mode , const void * params ) { /* DSP Application loading and Transform starting is handled by a call to A2dpAudioCodecEnable in the application, so should not be done here. */ typedef struct { unsigned source_type:4; unsigned reserved:4; uint8 content_protection; uint32 voice_rate; unsigned bitpool:8; unsigned format:8; uint16 packet_size; Sink media_sink_b; } sbc_codec_data_type; sbc_codec_data_type *sbc_codecData = (sbc_codec_data_type *) params; if (!sbc_codecData) Panic(); SBC = (SBC_t*)PanicUnlessMalloc (sizeof (SBC_t) ) ; SBC->media_sink[0] = audio_sink ; SBC->codec_task = codec_task ; SBC->media_sink[1] = sbc_codecData->media_sink_b; SBC->packet_size = sbc_codecData->packet_size; StreamDisconnect(StreamKalimbaSource(2), 0); /* Initialise the RTP SBC encoder */ SBC->t[0] = TransformRtpSbcEncode(StreamKalimbaSource(2), audio_sink); /* Configure the RTP transform to generate the selected packet size */ TransformConfigure(SBC->t[0], VM_TRANSFORM_RTP_SBC_ENCODE_PACKET_SIZE, sbc_codecData->packet_size); /* Transform should not manage timings. */ TransformConfigure(SBC->t[0], VM_TRANSFORM_RTP_SBC_ENCODE_MANAGE_TIMING, FALSE); /* Start the transform */ (void) TransformStart(SBC->t[0]); PRINT(("Audio Plugin: TransformStart sink:0x%x\n",(uint16)audio_sink)); if (SBC->media_sink[1]) { /* There is a 2nd audio stream so initialise this transform */ StreamDisconnect(StreamKalimbaSource(3), 0); /* Initialise the RTP SBC encoder */ SBC->t[1] = TransformRtpSbcEncode(StreamKalimbaSource(3), SBC->media_sink[1]); /* Configure the RTP transform to generate the selected packet size */ TransformConfigure(SBC->t[1], VM_TRANSFORM_RTP_SBC_ENCODE_PACKET_SIZE, sbc_codecData->packet_size); /* Transform should not manage timings. */ TransformConfigure(SBC->t[1], VM_TRANSFORM_RTP_SBC_ENCODE_MANAGE_TIMING, FALSE); /* Start the transform */ (void) TransformStart(SBC->t[1]); PRINT(("Audio Plugin: TransformStart sink:0x%x\n",(uint16)SBC->media_sink[1])); } /* Configure SBC encoding format */ if (!KalimbaSendMessage(KALIMBA_MSG_SBCENC_SET_PARAMS, sbc_codecData->format, 0, 0, 0)) /* If message fails to get through, abort */ Panic(); /* Pass bit pool value to DSP */ if (!KalimbaSendMessage(KALIMBA_MSG_SBCENC_SET_BITPOOL, sbc_codecData->bitpool, 0, 0, 0)) /* If message fails to get through, abort */ Panic(); /* disard any data sent by the SNK */ StreamConnectDispose(StreamSourceFromSink(audio_sink)); if (SBC->media_sink[1]) { /* disard any data sent by the 2nd SNK */ StreamConnectDispose(StreamSourceFromSink(SBC->media_sink[1])); } /* select the source type */ if(sbc_codecData->source_type == SourceUsb) { PRINT(("Audio Plugin: SourceUsb\n")); /* Select the source type */ PanicFalse(KalimbaSendMessage(KALIMBA_ENCODER_SELECT, 0x0001, 0, 0, 0)); } else { PRINT(("Audio Plugin: SourceAnalog\n")); /* For analogue input source */ StreamDisconnect(StreamPcmSource(0), StreamPcmSink(0)); StreamDisconnect(StreamPcmSource(1), StreamPcmSink(1)); (void)PcmClearAllRouting(); if (CodecGetCodecType(codec_task) == codec_wm8731) { PRINT(("Audio Plugin: codec_wm8731\n")); /* configure slot 0 and 1 to be left and right channel and synchronise the offsets for stereo playback */ (void)PcmRateAndRoute(0, PCM_NO_SYNC, (uint32) rate, (uint32) rate, VM_PCM_EXTERNAL_I2S); (void)PcmRateAndRoute(1, 0, (uint32) rate, (uint32) rate, VM_PCM_EXTERNAL_I2S); } else { PRINT(("Audio Plugin: codec_internal\n")); /* configure slot 0 and 1 to be left and right channel and synchronise the offsets for stereo playback */ (void)PcmRateAndRoute(0, PCM_NO_SYNC, (uint32) rate, (uint32) rate, VM_PCM_INTERNAL_A); (void)PcmRateAndRoute(1, 0, (uint32) rate, (uint32) rate, VM_PCM_INTERNAL_B); } /* plug Left ADC into port 0 */ (void)StreamConnect(StreamPcmSource(0),StreamKalimbaSink(0)); /* plug Right ADC into port 1 */ (void)StreamConnect(StreamPcmSource(1),StreamKalimbaSink(1)); /* Select the source type */ PanicFalse(KalimbaSendMessage(KALIMBA_ENCODER_SELECT, 0x0002, 0, 0, 0)); if(!KalimbaSendMessage(KALIMBA_MSG_GO,0,0,0,0)) { PRINT(("SBC: Message KALIMBA_MSG_GO failed!\n")); Panic(); } } /* Select the source type */ /*PanicFalse(KalimbaSendMessage(KALIMBA_SOURCE_SELECT, SOURCE_USB, 0, 0, 0)); */ /*CsrSbcEncoderUsbPluginSetVolume(volume) ;*/ /*(void) StreamConnect(PanicNull(StreamUsbEndPointSource(end_point_iso_in)), StreamKalimbaSink(0)); */ /* Start decode */ /* if(!KalimbaSendMessage(KALIMBA_MSG_GO,0,0,0,0)) { PRINT(("SBC: Message KALIMBA_MSG_GO failed!\n")); Panic(); } */ }
/**************************************************************************** DESCRIPTION Set the mode */ void CsrSbcEncoderPluginSetMode ( AUDIO_MODE_T mode , const void * params ) { typedef struct { bool connect_sink; Sink media_sink; } sbc_mode_params; sbc_mode_params *sbc_mode = (sbc_mode_params *) params; uint16 i; if (!SBC) Panic() ; PRINT(("Audio Plugin: Set Mode\n")); if (sbc_mode->connect_sink) { /* A second audio sink has been connected */ for (i = 0; i < MAX_AUDIO_SINKS; i++) { if (SBC->media_sink[i] == 0) { /* store the audio sink */ SBC->media_sink[i] = sbc_mode->media_sink; /* Initialise the RTP SBC encoder */ SBC->t[i] = TransformRtpSbcEncode(StreamKalimbaSource(i+2), SBC->media_sink[i]); /* Configure the RTP transform to generate the selected packet size */ TransformConfigure(SBC->t[i], VM_TRANSFORM_RTP_SBC_ENCODE_PACKET_SIZE, SBC->packet_size); /* Transform should not manage timings. */ TransformConfigure(SBC->t[i], VM_TRANSFORM_RTP_SBC_ENCODE_MANAGE_TIMING, FALSE); /* Start the transform */ (void) TransformStart(SBC->t[i]); PRINT(("Audio Plugin: Start new Transform i:%d sink:0x%x\n",i,(uint16)SBC->media_sink[i])); } } } else { /* An audio sink has been disconnected */ for (i = 0; i < MAX_AUDIO_SINKS; i++) { if (SBC->media_sink[i] == sbc_mode->media_sink) { /* Disconnect the Kalimba source from the media sink */ StreamDisconnect(StreamKalimbaSource(i+2), SBC->media_sink[i]); PRINT(("Audio Plugin: Disconnect media i:%d sink:0x%x\n",i,(uint16)SBC->media_sink[i])); /* clear the audio sink */ SBC->media_sink[i] = 0; } } } free(sbc_mode); }
/**************************************************************************** DESCRIPTION Connect the encoded audio input and pcm audio output streams */ static void MusicConnectAudio (A2dpPluginTaskdata *task, bool stereo ) { plugin_codec_data_type *codecData = (plugin_codec_data_type *) DECODER->params; uint32 voice_rate = 0; val_clock_mismatch = codecData->clock_mismatch; if ((A2DP_DECODER_PLUGIN_TYPE_T)task->a2dp_plugin_variant == FASTSTREAM_SINK) { /* FastStream does not use RTP. L2CAP frames enter/leave via port 2 */ /* Initialise PCM. Output stereo at 44k1Hz or 48kHz, input from left ADC at 16kHz. */ /* If no voice rate is set just make the ADC rate equal to 16kHz */ if (!codecData->voice_rate) voice_rate = 16000; else voice_rate = codecData->voice_rate; PRINT(("FASTSTREAM: rate=0x%lx voice_rate=0x%lx\n format=0x%x bitpool=0x%x",DECODER->rate,codecData->voice_rate,codecData->format,codecData->bitpool)); PanicFalse(PcmRateAndRoute(0, PCM_NO_SYNC, (uint32)DECODER->rate, (uint32) voice_rate, VM_PCM_INTERNAL_A)); /* is it mono playback? */ if ( !stereo ) { PRINT(("DECODER: Mono\n")); /* Connect Kalimba to PCM */ if (DECODER->rate) { StreamDisconnect(StreamSourceFromSink(DECODER->media_sink), 0); PanicFalse(StreamConnect(StreamKalimbaSource(0),StreamPcmSink(0))); PanicFalse(StreamConnect(StreamSourceFromSink(DECODER->media_sink),StreamKalimbaSink(2))); } } else { PRINT(("DECODER: Stereo\n")); PanicFalse(PcmRateAndRoute(1, 0, (uint32)DECODER->rate, (uint32) voice_rate, VM_PCM_INTERNAL_B)); /* Connect Kalimba to PCM */ if (DECODER->rate) { StreamDisconnect(StreamSourceFromSink(DECODER->media_sink), 0); PanicFalse(StreamConnect(StreamKalimbaSource(0),StreamPcmSink(0))); PanicFalse(StreamConnect(StreamKalimbaSource(1),StreamPcmSink(1))); PanicFalse(StreamConnect(StreamSourceFromSink(DECODER->media_sink),StreamKalimbaSink(2))); } } if (codecData->voice_rate) { StreamDisconnect(0, DECODER->media_sink); /* configure parameters */ PanicFalse(KalimbaSendMessage(KALIMBA_MSG_SBCENC_SET_PARAMS, codecData->format, 0, 0, 0)); PanicFalse(KalimbaSendMessage(KALIMBA_MSG_SBCENC_SET_BITPOOL, codecData->bitpool, 0, 0, 0)); PanicFalse(StreamConnect(StreamPcmSource(0), StreamKalimbaSink(0))); PanicFalse(StreamConnect(StreamKalimbaSource(2),DECODER->media_sink)); } } else /* Not FastStream CODEC */ { uint8 content_protection = codecData->content_protection; uint16 scms_enabled = 0; Transform rtp_transform = 0; switch ((A2DP_DECODER_PLUGIN_TYPE_T)task->a2dp_plugin_variant) { case SBC_DECODER: rtp_transform = TransformRtpSbcDecode(StreamSourceFromSink(DECODER->media_sink) , StreamKalimbaSink(0)); break; case MP3_DECODER: rtp_transform = TransformRtpMp3Decode(StreamSourceFromSink(DECODER->media_sink) , StreamKalimbaSink(0)); break; case AAC_DECODER: rtp_transform = TransformRtpAacDecode(StreamSourceFromSink(DECODER->media_sink) , StreamKalimbaSink(0)); break; default: break; } /* Configure the content protection */ if (content_protection) scms_enabled = 1; TransformConfigure(rtp_transform, VM_TRANSFORM_RTP_SCMS_ENABLE, scms_enabled); /*start the transform decode*/ (void)TransformStart( rtp_transform ) ; /* is it mono playback? */ if ( !stereo ) { PcmRateAndRoute(0, PCM_NO_SYNC, DECODER->rate, (uint32) 8000, VM_PCM_INTERNAL_A) ; PRINT(("DECODER: Mono\n")); /* plug port 0 into both DACs */ (void) PanicFalse(StreamConnect(StreamKalimbaSource(0),StreamPcmSink(0))); } else { PRINT(("DECODER: Stereo\n")); PanicFalse(PcmRateAndRoute(0, PCM_NO_SYNC, DECODER->rate, (uint32) 8000, VM_PCM_INTERNAL_A)); PanicFalse(PcmRateAndRoute(1, 0, DECODER->rate, (uint32) 8000, VM_PCM_INTERNAL_B)); /* plug port 0 into Left DAC */ PanicFalse(StreamConnect(StreamKalimbaSource(0),StreamPcmSink(0))); /* plug port 1 into Right DAC */ PanicFalse(StreamConnect(StreamKalimbaSource(1),StreamPcmSink(1))); } } CsrA2dpDecoderPluginSetVolume(task,DECODER->volume) ; /* The DSP must know the sample rate for tone mixing */ KalimbaSendMessage(MESSAGE_SET_SAMPLE_RATE, DECODER->rate, val_pskey_max_mismatch, val_clock_mismatch, 0); PRINT(("DECODER: Send Go message to DSP now\n")); if(!KalimbaSendMessage(KALIMBA_MSG_GO,0,0,0,0)) { PRINT(("DECODER: Message KALIMBA_MSG_GO failed!\n")); Panic(); } }
/**************************************************************************** DESCRIPTION This function connects APTX low delay audio ****************************************************************************/ void MusicConnectAptxLowLatency(A2dpPluginConnectParams *codecData, uint8 content_protection) { Sink speaker_snk_a = NULL; Transform rtp_transform = 0; DECODER_t * DECODER = CsrA2dpDecoderGetDecoderData(); /* when configured for using back channel low latency apps */ if(isCodecLowLatencyBackChannel()) { /* if the back channel is required and the mic/line input is configured */ if (codecData->voice_rate) { /* Bidirectional channel uses faststream mono with the following settings */ /* Configure the SBC format for the microphone data 16kHz, Mono, Blocks 16, Sub-bands 8, Loudness, Bitpool = 32 (data rate = 72kbps, packet size = 3*72 + 4 = 220 <= DM5). */ codecData->format = 0x31; codecData->bitpool = 32; PRINT(("DECODER: apt-X Low Latency Bidirectional rate=0x%lx voice_rate=0x%lx\n format=0x%x\n",DECODER->rate,codecData->voice_rate,codecData->format)); } } /* ensure the sample rate is valid */ if (DECODER->rate) { /* disconnect media sink as it might be disposed */ StreamDisconnect(StreamSourceFromSink(DECODER->media_sink), 0); /* determine the output hardware type */ switch(DECODER->features.audio_output_type) { /* using the inbuilt dacs */ case OUTPUT_INTERFACE_TYPE_NONE: case OUTPUT_INTERFACE_TYPE_DAC: { /* configure built-in audio hardware channel A */ speaker_snk_a = StreamAudioSink(AUDIO_HARDWARE_CODEC, AUDIO_INSTANCE_0, AUDIO_CHANNEL_A); PanicFalse(SinkConfigure(speaker_snk_a, STREAM_CODEC_OUTPUT_RATE, DECODER->rate)); /* if STEREO mode configured then connect the output channel B */ if(DECODER->features.stereo) { Sink speaker_snk_b = NULL; PRINT(("DECODER: Stereo\n")); /* connect channels B */ speaker_snk_b = StreamAudioSink(AUDIO_HARDWARE_CODEC, AUDIO_INSTANCE_0, AUDIO_CHANNEL_B); /* configure channel to required rate */ PanicFalse(SinkConfigure(speaker_snk_b, STREAM_CODEC_OUTPUT_RATE, DECODER->rate)); /* synchronise both sinks for channels A & B */ PanicFalse(SinkSynchronise(speaker_snk_a, speaker_snk_b)); /* plug port 1 into Right DAC */ PanicFalse(StreamConnect(StreamKalimbaSource(AUDIO_OUT_FROM_DSP_LEFT),speaker_snk_a)); PanicFalse(StreamConnect(StreamKalimbaSource(AUDIO_OUT_FROM_DSP_RIGHT),speaker_snk_b)); } /* mono operation, only connect left port */ else { /* plug port 0 into Left DAC */ PanicFalse(StreamConnect(StreamKalimbaSource(AUDIO_OUT_FROM_DSP_LEFT),speaker_snk_a)); } } break; /* using the spdif digital output hardware */ case OUTPUT_INTERFACE_TYPE_SPDIF: { Sink speaker_snk_b = NULL; /* configure spdif audio hardware channel 0 */ speaker_snk_a = StreamAudioSink(AUDIO_HARDWARE_SPDIF, AUDIO_INSTANCE_0, SPDIF_CHANNEL_A); speaker_snk_b = StreamAudioSink(AUDIO_HARDWARE_SPDIF, AUDIO_INSTANCE_0, SPDIF_CHANNEL_B); /* configure channel to required rate */ PanicFalse(SinkConfigure(speaker_snk_a, STREAM_SPDIF_OUTPUT_RATE, DECODER->rate)); PanicFalse(SinkConfigure(speaker_snk_b, STREAM_SPDIF_OUTPUT_RATE, DECODER->rate)); /* connect channels B */ /* synchronise both sinks for channels A & B */ PanicFalse(SinkSynchronise(speaker_snk_a, speaker_snk_b)); /* plug port 1 into Right DAC */ PanicFalse(StreamConnect(StreamKalimbaSource(AUDIO_OUT_FROM_DSP_LEFT),speaker_snk_a)); PanicFalse(StreamConnect(StreamKalimbaSource(AUDIO_OUT_FROM_DSP_RIGHT),speaker_snk_b)); PRINT(("DECODER: Stereo\n")); } break; /* using the i2s digital output hardware */ case OUTPUT_INTERFACE_TYPE_I2S: { /* is a specified output frequency required? use resampling*/ if(CsrI2SMusicResamplingFrequency()) CsrI2SAudioOutputConnect(CsrI2SMusicResamplingFrequency(), DECODER->features.stereo, StreamKalimbaSource(AUDIO_OUT_FROM_DSP_LEFT), StreamKalimbaSource(AUDIO_OUT_FROM_DSP_RIGHT)); /* use the negotiated sample rate of the input, no resampling required */ else CsrI2SAudioOutputConnect(DECODER->rate, DECODER->features.stereo, StreamKalimbaSource(AUDIO_OUT_FROM_DSP_LEFT), StreamKalimbaSource(AUDIO_OUT_FROM_DSP_RIGHT)); } break; } /* if content protection is required feed the media sink through the rtp decoder transform */ if (content_protection) { rtp_transform = TransformRtpDecode(StreamSourceFromSink(DECODER->media_sink) , StreamKalimbaSink(LOW_LATENCY_CODEC_TO_DSP_PORT)); TransformConfigure(rtp_transform, VM_TRANSFORM_RTP_SCMS_ENABLE, content_protection); /*start the transform decode*/ PRINT(("aptX: RTP Transform \n")); (void)TransformStart( rtp_transform ) ; } /* connect the media sink to the dsp input port */ else { PanicFalse(StreamConnect(StreamSourceFromSink(DECODER->media_sink),StreamKalimbaSink(LOW_LATENCY_CODEC_TO_DSP_PORT))); } } /* Send parameters that configure the SRA and buffer settings */ PRINT(("aptX LL params: initial level=%d target level=%d sra max rate=%d/10000 sra avg time=%d good working buffer level=%d \n", codecData->aptx_sprint_params.target_codec_level,codecData->aptx_sprint_params.initial_codec_level, codecData->aptx_sprint_params.sra_max_rate,codecData->aptx_sprint_params.sra_avg_time, codecData->aptx_sprint_params.good_working_level)); KalimbaSendMessage(MESSAGE_SET_APTX_LL_PARAMS1, codecData->aptx_sprint_params.target_codec_level, codecData->aptx_sprint_params.initial_codec_level, codecData->aptx_sprint_params.sra_max_rate, /* Third field is scaled by 10000 */ codecData->aptx_sprint_params.sra_avg_time); KalimbaSendMessage(MESSAGE_SET_APTX_LL_PARAMS2, codecData->aptx_sprint_params.good_working_level, 0, 0, 0); /* update the current audio state */ SetAudioInUse(TRUE); }