/**************************************************************************** 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 ; }
/**************************************************************************** DESCRIPTION Stop prompt where DSP has not been loaded by the plugin, e.g. (adpcm or pcm) Prompt is either mixing in an existing DSP app or not using the DSP. */ static void CsrVoicePresencesPluginStopPhraseMixable ( void ) { Sink lSink=NULL; Task taskdata = NULL; /* Check for DSP mixing */ if(GetCurrentDspStatus()) { lSink = StreamKalimbaSink(PRESENT_DSP_PORT); /* reset the volume levels of the dsp plugin */ if(GetAudioPlugin()) MessageSend( GetAudioPlugin(), AUDIO_PLUGIN_RESET_VOLUME_MSG, 0 ) ; } else /* Must be ADPCM not mixing */ { switch(koovox_phrase_data->features.audio_output_type) { /* is the I2S required? */ case OUTPUT_INTERFACE_TYPE_I2S: { CsrI2SAudioOutputDisconnect( koovox_phrase_data->features.stereo); } break; /* spdif output? */ case OUTPUT_INTERFACE_TYPE_SPDIF: { Sink rSink = NULL; /* obtain source to SPDIF hardware and disconnect it */ lSink = StreamAudioSink(AUDIO_HARDWARE_SPDIF, AUDIO_INSTANCE_0, SPDIF_CHANNEL_A ); rSink = StreamAudioSink(AUDIO_HARDWARE_SPDIF, AUDIO_INSTANCE_0, SPDIF_CHANNEL_B ); StreamDisconnect(0, lSink); StreamDisconnect(0, rSink); SinkClose(lSink); SinkClose(rSink); } break; /* use built in codec */ default: { lSink = StreamAudioSink(AUDIO_HARDWARE_CODEC,AUDIO_INSTANCE_0, (koovox_phrase_data->features.stereo ? AUDIO_CHANNEL_A_AND_B : AUDIO_CHANNEL_A)); /* Disconnect PCM source/sink */ StreamDisconnect(StreamSourceFromSink(lSink), lSink); } } } /* close sink and cancel any messages if valid */ if(lSink) { /* Cancel all the messages relating to VP that have been sent */ taskdata = MessageSinkTask(lSink, NULL); SinkClose(lSink); } PRINT(("PRESENT: SinkTask now NULL was %x\n",(uint16)taskdata)); MessageCancelAll((TaskData*) &csr_voice_presences_plugin, MESSAGE_STREAM_DISCONNECT); }
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 Stop a tone from currently playing */ void CsrA2dpDecoderPluginStopTone ( void ) { if (!DECODER) Panic() ; StreamDisconnect ( 0 , StreamKalimbaSink(3) ) ; }
/**************************************************************************** DESCRIPTION Disconnect Sync audio */ void CsrA2dpDecoderPluginDisconnect( void ) { if (!DECODER) Panic() ; /*disconnect the pcm streams*/ StreamDisconnect(StreamPcmSource(0), StreamPcmSink(0)); StreamDisconnect(StreamPcmSource(1), StreamPcmSink(1)); /* For sinks disconnect the source in case its currently being disposed. */ StreamDisconnect(StreamSourceFromSink(DECODER->media_sink ), 0); StreamConnectDispose (StreamSourceFromSink(DECODER->media_sink)) ; KalimbaPowerOff() ; free (DECODER); DECODER = NULL ; }
void CsrSubwooferPluginConnect(Sink audio_sink, Task codec_task, Task app_task, subwooferPluginConnectParams * params) { FILE_INDEX index; /* Update the current DSP status */ SetCurrentDspStatus(DSP_LOADING); /* Give Kalimba the plugin task so it knows where to send messages */ (void) MessageCancelAll( (TaskData*)&csr_subwoofer_plugin, MESSAGE_FROM_KALIMBA); MessageKalimbaTask( (TaskData*)&csr_subwoofer_plugin ); /* Load the Subwofoer DSP application - Panic if it could not be loaded */ index = PanicFalse( FileFind(FILE_ROOT, kal, sizeof(kal) - 1) ); PanicFalse( KalimbaLoad(index) ); /* update current DSP status */ SetCurrentDspStatus(DSP_LOADED_IDLE); /* Allocate memory to store the plugin data */ plugin_data = (subwooferPluginData*)PanicUnlessMalloc(sizeof(subwooferPluginData)); /* Initialise the plugin data based on parameters supplied by the application */ plugin_data->audio_source = StreamSourceFromSink(audio_sink); plugin_data->swat_system_volume_db = params->swat_system_volume_db; plugin_data->swat_trim_gain_db = params->swat_trim_gain_db; plugin_data->adc_volume_index = params->adc_volume; plugin_data->input = params->input; plugin_data->output = params->output; plugin_data->sample_rate = params->sample_rate; plugin_data->adc_sample_rate = params->adc_sample_rate; plugin_data->codec_task = codec_task; plugin_data->app_task = app_task; plugin_data->dsp_set_sample_rate = 0; /* set later in response to AUDIO_PLUGIN_SET_MODE_MSG */ /* Zero the codecs output gain */ CodecSetOutputGainNow(plugin_data->codec_task, 0, left_and_right_ch); CodecSetInputGainNow(plugin_data->codec_task, 0, left_and_right_ch); /* If using the ADC, set the ADC source */ if (plugin_data->input == SUBWOOFER_INPUT_ADC) { /* Get the ADC source */ plugin_data->audio_source = StreamAudioSource(AUDIO_HARDWARE_CODEC, AUDIO_INSTANCE_0, AUDIO_CHANNEL_A); } /* Disconnect the source in case it's currently being disposed */ StreamDisconnect(StreamSourceFromSink(audio_sink), 0); PRINT(("[SW_PLUGIN] : CsrSubwooferPluginConnect - complete\n")); }
/**************************************************************************** NAME hidConnDisconnected DESCRIPTION Called to put the specified connection into the disconnected state. RETURNS void */ void hidConnDisconnected(HID *hid, Sink sink) { hidConnection *conn = NULL; /* Find connection structure */ if (((hid->connection[HID_CON_CONTROL].state == hidConConnected) || (hid->connection[HID_CON_CONTROL].state == hidConDisconnecting)) && (sink == hid->connection[HID_CON_CONTROL].con.sink)) conn = &hid->connection[HID_CON_CONTROL]; else if (((hid->connection[HID_CON_INTERRUPT].state == hidConConnected) || (hid->connection[HID_CON_INTERRUPT].state == hidConDisconnecting)) && (sink == hid->connection[HID_CON_INTERRUPT].con.sink)) conn = &hid->connection[HID_CON_INTERRUPT]; else Panic(); /* Dispose of any messages left in the l2cap sources to ensure the buffers are destroyed */ StreamDisconnect(StreamSourceFromSink(sink), 0); StreamConnectDispose(StreamSourceFromSink(sink)); /* Move connection into disconnected state */ conn->state = hidConDisconnected; }
/**************************************************************************** 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; } } }
/**************************************************************************** DESCRIPTION Stop a prompt from currently playing */ void CsrVoicePresencesPluginStopPhrase ( void ) { if(!koovox_phrase_data) Panic(); PRINT(("PRESENT: Terminated\n")); if(koovox_phrase_data->mixing) { /* If DSP already loaded and the prompt was mixed */ CsrVoicePresencesPluginStopPhraseMixable(); } /* Make sure prompt source is disposed */ if(SourceIsValid(koovox_phrase_data->source)) StreamDisconnect(koovox_phrase_data->source, NULL); /* Tidy up */ free(koovox_phrase_data); koovox_phrase_data = NULL; SetAudioBusy(NULL) ; SetVpPlaying(FALSE); }
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" )); }
/**************************************************************************** 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 This function connects a synchronous audio stream to the pcm subsystem */ void CsrA2dpDecoderPluginConnect( A2dpPluginTaskdata *task, Sink audio_sink , Task codec_task , uint16 volume , uint32 rate , bool stereo , AUDIO_MODE_T mode , const void * params , Task app_task ) { FILE_INDEX index = FILE_NONE; char* kap_file = NULL ; /* Only need to read the PS Key value once */ if (!pskey_read) { if (PsFullRetrieve(PSKEY_MAX_CLOCK_MISMATCH, &val_pskey_max_mismatch, sizeof(uint16)) == 0) val_pskey_max_mismatch = 0; pskey_read = TRUE; } switch ((A2DP_DECODER_PLUGIN_TYPE_T)task->a2dp_plugin_variant) { case SBC_DECODER: kap_file = "sbc_decoder/sbc_decoder.kap"; break; case MP3_DECODER: kap_file = "mp3_decoder/mp3_decoder.kap"; break; case AAC_DECODER: kap_file = "aac_decoder/aac_decoder.kap"; break; case FASTSTREAM_SINK: kap_file = "faststream_sink/faststream_sink.kap"; break; default: Panic(); break; } /*ensure that the messages received are from the correct kap file*/ (void) MessageCancelAll( (TaskData*) task, MESSAGE_FROM_KALIMBA); MessageKalimbaTask( (TaskData*) task ); index = FileFind(FILE_ROOT,(const char *) kap_file ,strlen(kap_file)); if (index == FILE_NONE) Panic(); if (!KalimbaLoad(index)) Panic(); DECODER = (DECODER_t*)PanicUnlessMalloc (sizeof (DECODER_t) ) ; DECODER->media_sink = audio_sink ; DECODER->codec_task = codec_task ; DECODER->volume = volume; DECODER->mode = mode; DECODER->stereo = stereo; DECODER->params = (uint16) params; DECODER->rate = rate; DECODER->app_task = app_task; if ((A2DP_DECODER_PLUGIN_TYPE_T)task->a2dp_plugin_variant == AAC_DECODER) { /* Workaround for AAC+ sources that negotiate sampling frequency at half the actual value */ if (rate < 32000) DECODER->rate = rate * 2; } CodecSetOutputGainNow(DECODER->codec_task, 0, left_and_right_ch); StreamDisconnect(StreamPcmSource(0), StreamPcmSink(0)); StreamDisconnect(StreamPcmSource(1), StreamPcmSink(1)); PanicFalse(PcmClearRouting(0)); PanicFalse(PcmClearRouting(1)); /* For sinks disconnect the source in case its currently being disposed. */ StreamDisconnect(StreamSourceFromSink(audio_sink), 0); PRINT(("DECODER: CsrA2dpDecoderPluginConnect completed\n")); }
/**************************************************************************** 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); }