/****************************************************************************
DESCRIPTION
	Indicate the volume has changed
*/
void CsrA2dpDecoderPluginSetVolume(A2dpPluginTaskdata *task, uint16 volume )
{
    if (volume > 0xf)
      volume = 0xf;
    if (volume < 0)
       volume = 0;
      
    KalimbaSendMessage(MUSIC_VOLUME_MSG, 0, 0, volume, volume);      
}
/****************************************************************************
NAME 
    a2dpStreamStartDsp

DESCRIPTION
    To load the corresponding DSP kap file for the selected audio plugin, and set 
    the encoder mode.
    
    As the same dsp kap file is used for both USB source and Analogue source, it is 
    better to load the kap file in application instead of plugin library.
 
*/
void a2dpStreamStartDsp(bool isA2DPstreaming)
{    
#ifdef KAL_MSG
    uint16 codec_type = CodecSbc;
    FILE_INDEX index  = FILE_NONE;
    
    DEBUG_A2DP(("a2dpStreamStartDsp %d\n",isA2DPstreaming));

    /* Power off the kalimba first before load the Kap file again */
    KalimbaPowerOff() ;
     
    /* This will be changed if one kap file supports both usb and analogue source types */
    if (isA2DPstreaming)
    {
        Task audio_plugin = initA2dpPlugin(the_app->a2dp_active_seid);
    
        the_app->a2dp_audio_plugin = audio_plugin;
    
        /* Select the corresponding kap file */
        if ( (audio_plugin == (TaskData *)&csr_sbc_encoder_plugin) )
        {
            index = FileFind(FILE_ROOT, sbc_encoder, sizeof(sbc_encoder)-1); 
            codec_type = CodecSbc;
        }
    }
    else
    {    
        /* we should load the source type, and can not set as the default type: SourceUsb*/
        the_app->aghfp_audio_plugin  = initScoPlugin();
        
        /* Select the corresponding kap file */
        index = FileFind(FILE_ROOT, sbc_encoder, sizeof(sbc_encoder)-1);
    }

    /* Load the DSP Kap file */
    if (index == FILE_NONE)
        Panic();
    if (!KalimbaLoad(index))
        Panic();    

    DEBUG_A2DP(("KalimbaLoad %s\n",sbc_encoder));
    
    /* Register the Kalimba message */
    MessageKalimbaTask(&the_app->task);
    
    /* send the codec type to kalimba, this is necessary as codecs share kap files */
    if (codec_type != CodecMp3) 
    {
        if (!KalimbaSendMessage(KALIMBA_CODEC_TYPE_MESSAGE, codec_type,0,0,0))
        {
            Panic();
        }
    }
#else
    DEBUG_A2DP(("a2dpStreamStartDsp %d\n",isA2DPstreaming));
#endif	
}
/****************************************************************************
DESCRIPTION
	handles the internal cvc messages /  messages from the dsp
*/
void CsrA2dpDecoderPluginInternalMessage( A2dpPluginTaskdata *task ,uint16 id , Message message )
{
	switch(id)
	{
        case MESSAGE_FROM_KALIMBA:
		{
			const DSP_REGISTER_T *m = (const DSP_REGISTER_T *) message;
	        PRINT(("DECODER: msg id[%x] a[%x] b[%x] c[%x] d[%x]\n", m->id, m->a, m->b, m->c, m->d));

            switch ( m->id )
			{
              case MUSIC_READY_MSG:
                {
					if (DECODER)
					{
                    	KalimbaSendMessage(MUSIC_LOADPARAMS_MSG, MUSIC_PS_BASE, 0, 0, 0);

                    	/*A2dp is now loaded, signal that tones etc can be scheduled*/
                    	AUDIO_BUSY = NULL ;

                    	PRINT(("DECODER: DECODER_READY \n"));

                     CsrA2dpDecoderPluginSetMode(DECODER->mode, task, 0);

                    	MusicConnectAudio (task, DECODER->stereo);
					}
                }
                break;
			    case MUSIC_CODEC_MSG:
	            {
                    uint16 lOutput_gain_l = m->a;
                    uint16 lOutput_gain_r = m->b;

					if (DECODER)
					{
                    	CodecSetOutputGainNow(DECODER->codec_task, lOutput_gain_l, left_ch);
                    	CodecSetOutputGainNow(DECODER->codec_task, lOutput_gain_r, right_ch);
					}
	            }
                break;
				case KALIMBA_MSG_SOURCE_CLOCK_MISMATCH_RATE:
				{
					MAKE_AUDIO_MESSAGE(AUDIO_PLUGIN_DSP_MSG);
					message->id = KALIMBA_MSG_SOURCE_CLOCK_MISMATCH_RATE;
					message->value = m->a;
					MessageSend(DECODER->app_task, AUDIO_PLUGIN_DSP_MSG, message);
					break;
				}
            }
		}
		break;

        default:
        break ;
	}
}
/****************************************************************************
DESCRIPTION
	Sets the audio mode
*/
void CsrA2dpDecoderPluginSetMode ( AUDIO_MODE_T mode , A2dpPluginTaskdata *task , const void * params )
{
    if (!DECODER)
       	Panic() ;

    DECODER->mode = mode;

    PRINT(("DECODER: Set Mode\n"));

	 switch (mode)
    {
		case AUDIO_MODE_MUTE_SPEAKER:
	   	{
         KalimbaSendMessage (MUSIC_SETMODE_MSG , MUSIC_SYSMODE_FULLPROC , 1, 0, 0);
			PRINT(("DECODER: Set Mode SYSMODE_FULLPROC eq 2\n"));
       	}
	   	break ;
	   	case AUDIO_MODE_CONNECTED:
       	{
         KalimbaSendMessage (MUSIC_SETMODE_MSG , MUSIC_SYSMODE_PASSTHRU , 0, 0, 0 ) ;
   	   PRINT(("DECODER: Set Mode SYSMODE_PASSTHRU\n"));
       	}
	   	break ;
	      case AUDIO_MODE_MUTE_MIC:
	   	{
       	KalimbaSendMessage (MUSIC_SETMODE_MSG , MUSIC_SYSMODE_FULLPROC , 0, 0, 0);
			PRINT(("DECODER: Set Mode SYSMODE_FULLPROC eq 1\n"));
	   	}
	   	break ;
	   	case AUDIO_MODE_MUTE_BOTH:
    	{
      	KalimbaSendMessage (MUSIC_SETMODE_MSG , MUSIC_SYSMODE_FULLPROC , 2, 0, 0);
		/*	PRINT(("DECODER: Set Mode SYSMODE_FULLPROC eq 3\n"));*/
    	}
    	break;
    	default:
    	{
    		PRINT(("DECODER: Set Mode Invalid [%x]\n" , mode ));
		}
		break ;
   	}
}
void CsrSubwooferPluginSetMode(subwooferPluginModeParams * params)
{
    if (params)
    {
        if (plugin_data->input == SUBWOOFER_INPUT_ADC)
        {
            /* Check params */
            
            /*
            r2 (bank_state) can be 0, 1, or 2:
                0 = do not advance to next EQ bank
                1 = advance to next EQ bank
                2 = use eq Bank that is specified in r3
            r3 (eq_bank) is only used if r2 = 2:
                valid range: 1 through 3 (choose which EQ bank to use); 0 is flat curve (LPF disabled).
            */

            if (params->cycle_eq)
            {
                PRINT(("[SW_PLUGIN] : Set mode (Cycle to the next EQ bank)\n"));
                KalimbaSendMessage(MUSIC_SETMODE_MSG, 0, 1, 0, 0);
            }
            else
            {
                PRINT(("[SW_PLUGIN] : Set mode (Use EQ Bank[%d])\n", params->eq_bank));
                KalimbaSendMessage(MUSIC_SETMODE_MSG, 0, 2, params->eq_bank, 0);
            }
        }
        else
        {
            /* Set mode message is used to set the sample rate for the DSP */
            CsrSubwooferPluginSetSampleRate( params->sample_rate );
        }
    }
    else
    {
        PRINT(("[SW_PLUGIN] : ERROR - Set mode (params are NULL)\n"));
    }
}
void CsrSubwooferPluginSetVolume(uint16 volume)
{
    if (plugin_data->input == SUBWOOFER_INPUT_ADC)
    {
        /* Use ADC volume */
        plugin_data->adc_volume_index = volume;
        
        PRINT(("[SW_PLUGIN] : Set ADC volume VOLUME[%x]\n", plugin_data->adc_volume_index));
        
        KalimbaSendMessage(MUSIC_VOLUME_MSG, 0, 0, plugin_data->adc_volume_index, 0);
    }
    else
    {
        /* Update the System gain and subwoofer trim */
        plugin_data->swat_system_volume_db  = volume & 0xFF;
        plugin_data->swat_trim_gain_db      = volume >> 8;
        
        PRINT(("[SW_PLUGIN] : Set volume SWAT_SYSTEM_VOLUME[%x] SUBWOOFER_TRIM[%x]\n", plugin_data->swat_system_volume_db, plugin_data->swat_trim_gain_db));
        
        KalimbaSendMessage(MUSIC_VOLUME_MSG, plugin_data->swat_system_volume_db, plugin_data->swat_trim_gain_db, 0, 0);
    }
}
void CsrSubwooferPluginSetSampleRate(uint16 sample_rate)
{
    /* Update the sample rate stored by the plugin (only if new sample rate is different) */
    if (plugin_data->dsp_set_sample_rate != sample_rate)
    {
        PRINT(("[SW_PLUGIN] : Update sample rate from [%u] to [%u]\n", plugin_data->sample_rate, sample_rate));
        
        /* Send sample rate to the Kalimba */
        KalimbaSendMessage(MESSAGE_SET_DAC_SAMPLE_RATE, sample_rate/10, 0,0,0);
        
        /* Store the new sample rate */
        plugin_data->dsp_set_sample_rate = sample_rate;
    }
    else
    {
        PRINT(("[SW_PLUGIN] : Sample rate not changed [%u]\n", plugin_data->sample_rate));
    }
}
/****************************************************************************
NAME
    disconnectAudio

DESCRIPTION
    Disconnects the specified SCO/eSCO channel from the DSP.

*/
static void disconnectAudio (devInstanceTaskData *inst)
{
    DEBUG_AGHFP(("    disconnectAudio(0x%X)\n", (uint16)inst->audio_sink));
    if (inst->audio_sink)
    {
		SendEvent(EVT_AUDIO_DISCONNECT_IND,0);
		
        if (the_app->active_encoder == EncoderSco)
        {
			ledSetProfile(LedTypeSCO,FALSE);
            AudioDisconnect();    
#ifdef KAL_MSGxx
            /* Switch the DSP to IDLE mode */ 
            PanicFalse(KalimbaSendMessage(KALIMBA_ENCODER_SELECT, EncoderNone, 0, 0, 0));
#endif
            the_app->active_encoder = EncoderNone;
        }
        
        inst->audio_sink = 0;
        
    }
}
/****************************************************************************
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;
        }
    }
}
Beispiel #10
0
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));
}
void handleInternalPluginMessage(Task task, MessageId id, Message message)
{
    switch(id)
    {
        case MESSAGE_FROM_KALIMBA:
        {
            const DSP_REGISTER_T *msg = (const DSP_REGISTER_T *)message;
            
            /* Handle the message sent from Kalimba */
            switch(msg->id)
            {
                case MUSIC_READY_MSG:
                {
                    PRINT(("[SW_PLUGIN] : MUSIC_READY_MSG a[%x] b[%x] c[%x] d[%x]\n", msg->a, msg->b, msg->c, msg->d));
                    if (plugin_data)
                    {
                        /* Send parameters PSKEY to DSP */
                        KalimbaSendMessage(MUSIC_LOADPARAMS_MSG, MUSIC_PS_BASE, 0, 0, 0);
                    }
                    else
                    {
                        SetCurrentDspStatus(DSP_ERROR);
                    }
                }
                break;
                case MUSIC_PARAMS_LOADED_MSG:
                {
                    /* Send a message to the app to inform the number of subwoofer volume gains (for ADC mode) */
                    AUDIO_PLUGIN_DSP_IND_T * message = PanicUnlessNew(AUDIO_PLUGIN_DSP_IND_T);
                    message->id = SUB_PLUGIN_NUM_VOL_GAINS;
                    message->size_value = 1;
                    message->value[0] = msg->a;
                    MessageSend(plugin_data->app_task, AUDIO_PLUGIN_DSP_IND, message);
                    
                    PRINT(("[SW_PLUGIN] : MUSIC_PARAMS_LOADED_MSG a[%x] b[%x] c[%x] d[%x]\n", msg->a, msg->b, msg->c, msg->d));
                    
                    /* Connect input and output streams */
                    connectAudioStreams();
                    
                    /* Send Volume to DSP */
                    KalimbaSendMessage(MUSIC_VOLUME_MSG, plugin_data->swat_system_volume_db, plugin_data->swat_trim_gain_db, 0, plugin_data->adc_volume_index);
                    
                    /* Set the DSP status */
                    SetCurrentDspStatus(DSP_RUNNING);
                    
                    /* Send GO to DSP */
                    PanicFalse(KalimbaSendMessage(KALIMBA_MSG_GO, 0, 0, 0, 0));
                    
                    /* Send a message to the app to inform that the plugin is ready to recieve audio data */
                    MessageSend(plugin_data->app_task, AUDIO_PLUGIN_DSP_READY_FOR_DATA, 0);
                }
                break;
                case MUSIC_CODEC_MSG:
                {
                    PRINT(("[SW_PLUGIN] : MUSIC_CODEC_MSG a[%x] b[%x] c[%x] d[%x]\n", msg->a, msg->b, msg->c, msg->d));
                    
                    /* Parameters for this message :                */
                    /* msg->a BITS[0-3] = input gain                */
                    /* msg->a BIT[15]   = enable/disable mic preamp */
                    /* msg->b = output gain                         */
                    
                    /* Only set the input gain if using the ADC input (ESCO/L2CAP inputs don't use the ADC) */
                    if (plugin_data->input == SUBWOOFER_INPUT_ADC)
                    {
                        PRINT(("[SW PLUGIN] : Set ADC input GAIN[%x] Pre-amp enable[%x]\n", (msg->a & 0x1F), (msg->a>>15) & 0x1));
                        AudioPluginSetMicGain(plugin_data->audio_source, FALSE, (msg->a & 0x1F), (msg->a>>15) & 0x1);
                    }
                    
                    PRINT(("[SW PLUGIN] : Set DAC GAIN[%x]\n", msg->b));

                    /* Set the codec output gain according to what the DSP sent */
                    if (plugin_data->output == SUBWOOFER_OUTPUT_I2S)
                    {
                        CsrI2SAudioOutputSetVolume(FALSE, msg->b, msg->b, FALSE);
                    }
                    else
                    {
                        CodecSetOutputGainNow(plugin_data->codec_task, msg->b, left_and_right_ch);
                    }
                }
                break;
                case MUSIC_CUR_EQ_BANK:
                {
                    PRINT(("[SW_PLUGIN] : MUSIC_CUR_EQ_BANK a[%x] b[%x] c[%x] d[%x]\n", msg->a, msg->b, msg->c, msg->d));
                    
                    /* TODO */
                }
                break;
                case MUSIC_SIGNAL_DETECT_STATUS:
                {
                    /* msg->a = 1 if playing audio, 0 if audio is silent */
                    PRINT(("[SW_PLUGIN] : MUSIC_SIGNAL_DETECT_STATUS a[%x]\n", msg->a));
                    
                    if (msg->a)
                    {
                        /* Audio on wired input has been detected - Inform client task */
                        AUDIO_PLUGIN_DSP_IND_T * message = PanicUnlessNew(AUDIO_PLUGIN_DSP_IND_T);
                        message->id = SUB_PLUGIN_ADC_SIGNAL_ACTIVE;
                        message->size_value = 1;
                        message->value[0] = 0;
                        MessageSend(plugin_data->app_task, AUDIO_PLUGIN_DSP_IND, message);
                    }
                    else
                    {
                        /* Audio on wired input is now silent - Inform client task */
                        AUDIO_PLUGIN_DSP_IND_T * message = PanicUnlessNew(AUDIO_PLUGIN_DSP_IND_T);
                        message->id = SUB_PLUGIN_ADC_SIGNAL_IDLE;
                        message->size_value = 1;
                        message->value[0] = 0;
                        MessageSend(plugin_data->app_task, AUDIO_PLUGIN_DSP_IND, message);
                    }
                 }
                break;
                default:
                {
                    PRINT(("[SW_PLUGIN] : Unhandled message from Kalimba ID[%x]\n", msg->id));
                }
                break;
            }
        }
        break;
        default:
        {
            PRINT(("[SW_PLUGIN] : Unhandled internal message ID[%x]\n", id));
        }
        break;
    }
/****************************************************************************
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();
	}
	*/
}
static void CsrVoicePresencesPluginPlayDigit(void) 
{
    Source lSource ;
    voice_prompt prompt;
    
    /* Get the prompt data*/
    lSource = csrVoicePresencesGetPrompt(&prompt, koovox_phrase_data);
    if(!lSource) Panic();
    
    SetAudioBusy((TaskData*) &csr_voice_presences_plugin);

    /* Stash the source */
    koovox_phrase_data->source = lSource;
    koovox_phrase_data->decompression = prompt.decompression;
    koovox_phrase_data->stereo = prompt.stereo;
    koovox_phrase_data->playback_rate =  (prompt.playback_rate ? prompt.playback_rate : 8000);
    koovox_phrase_data->mixing = FALSE;    /* overridden later if this prompt is mixed */
    
    SetVpPlaying(TRUE);

	PRINT(("==decompression:%d===\n", prompt.decompression));

    /* Connect the stream to the DAC */
    switch(prompt.decompression)
    {
        case voice_prompts_codec_ima_adpcm:
        case voice_prompts_codec_none:     
        case voice_prompts_codec_tone:  
        {
            Sink lSink = NULL;
            Task taskdata = NULL;
            
            /* if DSP is already running, the voice prompt can be mixed with the dsp
               audio via the kalimba mixing port (3), either the CVC plugin or
               the music plugin will have already determined the output source and connected the 
               appropriate ports to the hardware, the volume will already have been set, it is not
               necessary to do it again */
            if(GetCurrentDspStatus())
            {            
                /* Configure tone or prompt playback */    
                if(prompt.decompression == voice_prompts_codec_tone)
                {
                    PRINT(("PRESENT: play tone\n"));
                    KalimbaSendMessage(MESSAGE_SET_TONE_RATE_MESSAGE_ID, koovox_phrase_data->playback_rate , 0/*Mono Bit 0 =0, TONE BIT 1 = 0*/, 0, 0); 
                }                    
                else
                {
                    PRINT(("PRESENT: play adpcm\n"));
                    KalimbaSendMessage(MESSAGE_SET_TONE_RATE_MESSAGE_ID, koovox_phrase_data->playback_rate , /*PROMPT_MONO*/PROMPT_ISPROMPT, 0, 0);                                  
                }
                /* stream voice prompt data to the DSP tone mixing port */                
                koovox_phrase_data->mixing = TRUE;
                lSink = StreamKalimbaSink(PRESENT_DSP_PORT);
                PRINT(("PRESENT: play dsp mix lSink = %x lSource = %x\n",(uint16)lSink,(uint16)lSource));
                SinkConfigure(lSink, STREAM_CODEC_OUTPUT_RATE, koovox_phrase_data->playback_rate);
                
                /* Get messages when source has finished */
                taskdata = MessageSinkTask( lSink , (TaskData*) &csr_voice_presences_plugin);

                /* connect the kalimba port to the audio_prompt */
                if(prompt.decompression == voice_prompts_codec_ima_adpcm)
                {   
                    PanicFalse(TransformStart(TransformAdpcmDecode(lSource, lSink)));
                }
                else
                {                      
                    PanicFalse(StreamConnect(lSource, lSink)); 
                }   
                
            }
			else
			{
				CsrVoicePresencesPluginStopPhrase();
			}
        }
        break;
        
        case voice_prompts_codec_pcm:        
        {    
            Sink lSink = NULL;
            Task taskdata = NULL;
            
            /* determine whether the prompt is being played as a mixed with audio via the dsp, if the dsp is being
               used for audio mixing there is no need to set the volume as this will already have been performed 
               plugin used to load the dsp for audio processing */            
            if(GetCurrentDspStatus())
            {
                /* store that this PCM prompt is mixing */
                koovox_phrase_data->mixing = TRUE;
                
                /* stream voice prompt data to the DSP tone mixing port */                
                lSink = StreamKalimbaSink(PRESENT_DSP_PORT);
                PRINT(("PRESENT: play dsp mix lSink = %x lSource = %x\n",(uint16)lSink,(uint16)lSource));
                SinkConfigure(lSink, STREAM_CODEC_OUTPUT_RATE, koovox_phrase_data->playback_rate);                               
                
                /* Get messages when source has finished */
                taskdata = MessageSinkTask( lSink , (TaskData*) &csr_voice_presences_plugin);

				PRINT(("PRESENT: sink task now %x was %x.\n",(uint16)&csr_voice_presences_plugin,(uint16)taskdata));
                /* Configure PCM prompt playback */    
                KalimbaSendMessage(MESSAGE_SET_TONE_RATE_MESSAGE_ID, koovox_phrase_data->playback_rate , (koovox_phrase_data->stereo?PROMPT_STEREO:0)|PROMPT_ISPROMPT, 0, 0);        
                
                /* Connect source to PCM */
                PanicFalse(StreamConnect(lSource, lSink));
            }
        }
        break;

        default:
            PRINT(("PRESENT: Codec Invalid\n"));
            Panic();
        break;
    }

}
/****************************************************************************
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);
}