예제 #1
0
static int brcm_omx_vc03_start(void)
{
	struct snd_pcm_runtime *runtime;
	OMX_ERRORTYPE error=OMX_ErrorNone;
		
	DEBUG("\n %lx:brcm_omx_vc03_start %d\n",jiffies,alsa_pcm_event);
	
	//return if stopped by ALSA
	if ( ((alsa_pcm_event & PCM_EVENT_PLAY_START) == 0) &&
		 ((alsa_pcm_event & PCM_EVENT_RECD_START) == 0) )
		return 0;
		
	//check if init?
	if (client==NULL)
	{
		client = ilclient_init();
		if (client==NULL)
		{
			DEBUG("\n %lx:ilclient_init failed\n",jiffies);
			return -1;
		}	
		
		//		
		error = OMX_Init();
		ERROR_RETURN("OMX_Init",error);
	}	
	
	//init playback
	if ( (alsa_pcm_event & PCM_EVENT_PLAY_START) && (play_init==0))
	{
		play_init=1;		 
		brcm_omx_vc03_play_init();
		ilclient_set_empty_buffer_done_callback(client,empty_buffer_done_cb,NULL);
	}
	
	//init record
	if ( (alsa_pcm_event & PCM_EVENT_RECD_START) && (recd_init==0))
	{
		recd_init=1;		 
		brcm_omx_vc03_recd_init();
		ilclient_set_fill_buffer_done_callback(client,fill_buffer_done_cb,NULL);
	}	
				
	if (alsa_pcm_event & PCM_EVENT_PLAY_START)
	{
		//do volume control
		if (g_brcm_alsa_chip->pcm_param_changed & PCM_EVENT_PLAY_VOLM)
		{
			OMX_AUDIO_CONFIG_VOLUMETYPE param;
			
			memset(&param, 0, sizeof(OMX_AUDIO_CONFIG_VOLUMETYPE));
			param.nSize = sizeof(OMX_AUDIO_CONFIG_VOLUMETYPE);
			param.nVersion.nVersion = OMX_VERSION;
			param.nPortIndex = 100;
			
			error = OMX_GetParameter(st_play.comp, OMX_IndexConfigAudioVolume, &param);
			ERROR_RETURN("OMX_GetParameter play volume param",error);
			
			param.bLinear = 1;
			param.sVolume.nValue = g_brcm_alsa_chip->pcm_playback_volume;
					
			error = OMX_SetParameter(st_play.comp, OMX_IndexConfigAudioVolume, &param);
			ERROR_RETURN("OMX_SetParameter play volume param",error);	
			
			error = OMX_GetParameter(st_play.comp, OMX_IndexConfigAudioVolume, &param);
			ERROR_RETURN("OMX_GetParameter play volume param",error);
			
			DEBUG("\n play volume=%d %d %d %d\n",g_brcm_alsa_chip->pcm_playback_volume,
				(int)param.sVolume.nValue,(int)param.sVolume.nMin,(int)param.sVolume.nMax);
			//reset: i don't think we need a lock here
			g_brcm_alsa_chip->pcm_param_changed &= ~PCM_EVENT_PLAY_VOLM;
		}
		
		//do mute
		if (g_brcm_alsa_chip->pcm_param_changed & PCM_EVENT_PLAY_MUTE)
		{
			OMX_AUDIO_CONFIG_MUTETYPE   param;
			
			memset(&param, 0, sizeof(OMX_AUDIO_CONFIG_MUTETYPE));
			param.nSize = sizeof(OMX_AUDIO_CONFIG_MUTETYPE);
			param.nVersion.nVersion = OMX_VERSION;
			param.nPortIndex = 100;			
			param.bMute = g_brcm_alsa_chip->pcm_playback_mute;
					
			error = OMX_SetParameter(st_play.comp, OMX_IndexConfigAudioMute, &param);
			ERROR_RETURN("OMX_SetParameter play mute param",error);	
					
			DEBUG("\n play mute = %d\n",g_brcm_alsa_chip->pcm_playback_mute);
			//reset: i don't think we need a lock here
			g_brcm_alsa_chip->pcm_param_changed &= ~PCM_EVENT_PLAY_MUTE;
		}
		
		runtime = g_brcm_alsa_chip->substream[0]->runtime;
		play_buffer = st_play.out_list;				
		play_buffer->nOffset = 0;
		play_buffer->nFilledLen = g_brcm_alsa_chip->period_bytes[0];
		play_buffer->pBuffer = &(runtime->dma_area[g_brcm_alsa_chip->pcm_ptr[0]]);
	
		error = OMX_EmptyThisBuffer(st_play.comp, play_buffer);
		ERROR_RETURN("OMX_EmptyThisBuffer",error);
				
		DEBUG("\n %lx:playback wait to be done\n",jiffies);
	}

	if (alsa_pcm_event & PCM_EVENT_RECD_START)
	{
		//do volume control
		//?
		
		runtime = g_brcm_alsa_chip->substream[1]->runtime;
			
		recd_buffer->nOffset = 0;		
		recd_buffer->nFilledLen = g_brcm_alsa_chip->period_bytes[1];
		recd_buffer->pBuffer = &(runtime->dma_area[g_brcm_alsa_chip->pcm_ptr[1]]);
		
		DEBUG("\n %lx:record do OMX_FillThisBuffer %x %x\n",jiffies,(int)recd_buffer,(int)recd_buffer);
		error = OMX_FillThisBuffer(st_recd.comp, recd_buffer);
		ERROR_RETURN("OMX_FillThisBuffer",error);
		
		DEBUG("\n %lx:record wait to be done OMX_FillThisBuffer %x\n",jiffies,(int)recd_buffer->pBuffer);
		
		//circular would be nicer
		recd_buffer = (OMX_BUFFERHEADERTYPE*)st_recd.out_list->pAppPrivate;
		if (recd_buffer==NULL)		
			recd_buffer = st_recd.out_list;				
	}
		
	return 0;
}
예제 #2
0
/* -------------------------------------------------
/	audioplay_create() 
/              Create audio decoder & render & other hardware component
/---------------------------------------------------*/
static INT32 audioplay_create(
	AUDIOPLAY_STATE_T	**handle,
	UINT32			sample_rate,
	UINT32			num_channels,
	UINT32			bit_depth,
	UINT32			num_buffers,	///< 100
	UINT32			buffer_size	///< 480*(16/8)*2 = 1920 
){
	
	OMX_AUDIO_PARAM_PCMMODETYPE	pcm;
	UINT32	bytes_per_sample = (bit_depth * num_channels) >> 3;
	INT32	ret = -1;
	int rv;

	*handle = NULL;
	
	/* TODO basic sanity check on arguments */
	if(sample_rate >= 8000 && sample_rate <= 96000 &&
	   (num_channels == 1 || num_channels == 2 || num_channels == 4 || num_channels == 8) &&
	   (bit_depth == 16 || bit_depth == 32) && 
	   (num_buffers > 0) &&
           (buffer_size >= bytes_per_sample)){


		/* TODO  buffer length must be 16 bytes aligned for VCHI  */
		int size = (buffer_size + 15) & ~15;

		/* TODO  buffer length must be 16 bytes aligned for VCHI  */
		st = calloc(1, sizeof(AUDIOPLAY_STATE_T));
		assert(st != NULL);

		OMX_ERRORTYPE	error;
		OMX_PARAM_PORTDEFINITIONTYPE	param;
		INT32	s;

		ret = 0;
		
		/* TODO combine with st = calloc()?*/
		*handle = st;

		/* create and start up audio codec hardware component */
		/* TODO semaphore  */
		s = sem_init(&st->sema, 0 ,1);
		assert(s == 0);
	
		st->bytes_per_sample = bytes_per_sample;
		st->num_buffers = num_buffers;
		st->client = ilclient_init();
		assert(st->client != NULL);

		/*TODO input_buffer_callback*/
		ilclient_set_empty_buffer_done_callback(st->client, input_buffer_callback, st);

		error = OMX_Init();
		assert(error == OMX_ErrorNone);
		
		/* Create audio render */
		ilclient_create_component(st->client,
					  &(st->audio_render),
					  "audio_render",
					  ILCLIENT_ENABLE_INPUT_BUFFERS | ILCLIENT_DISABLE_ALL_PORTS);
		assert(st->audio_render != NULL);
		st->list[0] = st->audio_render;
		
		/* Create clock component */
		ilclient_create_component(st->client,
					  &(st->clock),
					  "clock",
					  ILCLIENT_DISABLE_ALL_PORTS);
		assert(st->clock != NULL);
		st->list[1] = st->clock;
	
		/* Configure clock */
		OMX_TIME_CONFIG_CLOCKSTATETYPE	cstate;
		memset(&cstate, 0, sizeof(cstate));
		cstate.nSize				= sizeof(cstate);
		cstate.nVersion.nVersion		= OMX_VERSION;
		cstate.eState				= OMX_TIME_ClockStateWaitingForStartTime;
		cstate.nWaitMask			= 1;	//TODO
		
		error = OMX_SetParameter(ILC_GET_HANDLE(st->clock),
					 OMX_IndexConfigTimeClockState,
					&cstate); 	
		assert(error == 0);
		
		/* Setup tunnel to connect clock and audio render */
		set_tunnel(&st->tunnel, st->clock, 80, st->audio_render, 101);
		
		rv = ilclient_setup_tunnel(&st->tunnel, 0, 0);
		assert(rv == 0);

		/* kick off clock */
		ilclient_change_component_state(st->clock, OMX_StateExecuting);

		/* Set audio render port definition */
		/* Set up the number/size of buffers */
		memset(&param, 0, sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
		param.nSize			= sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
		param.nVersion.nVersion		= OMX_VERSION;
		param.nPortIndex		= 100;

		error = OMX_GetParameter(ILC_GET_HANDLE(st->audio_render), OMX_IndexParamPortDefinition, &param);
		assert(error == OMX_ErrorNone);
	
		param.nBufferSize		= size;
		param.nBufferCountActual	= num_buffers;
		
		error = OMX_SetParameter(ILC_GET_HANDLE(st->audio_render), OMX_IndexParamPortDefinition, &param);
		assert(error == OMX_ErrorNone);

		/* Set audio render PCM definition */
		memset(&pcm, 0, sizeof(OMX_AUDIO_PARAM_PCMMODETYPE));
		pcm.nSize			= sizeof(OMX_AUDIO_PARAM_PCMMODETYPE);
		pcm.nVersion.nVersion		= OMX_VERSION;
		pcm.nPortIndex			= 100;
		pcm.nChannels			= num_channels;
		pcm.eNumData			= OMX_NumericalDataSigned; //TODO
		pcm.eEndian			= OMX_EndianLittle;
		pcm.nSamplingRate		= sample_rate;
		pcm.bInterleaved		= OMX_TRUE;
		pcm.nBitPerSample		= bit_depth;
		pcm.ePCMMode			= OMX_AUDIO_PCMModeLinear;
		
		switch(num_channels){
			case 1:
			{
				pcm.eChannelMapping[0] = OMX_AUDIO_ChannelCF;
				break;
			}
			case 8:
			{	/*TODO*/
				pcm.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
				pcm.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
				pcm.eChannelMapping[2] = OMX_AUDIO_ChannelCF;
				pcm.eChannelMapping[3] = OMX_AUDIO_ChannelLFE;
				pcm.eChannelMapping[4] = OMX_AUDIO_ChannelLR;
				pcm.eChannelMapping[5] = OMX_AUDIO_ChannelRR;
				pcm.eChannelMapping[6] = OMX_AUDIO_ChannelLS;
				pcm.eChannelMapping[7] = OMX_AUDIO_ChannelRS;
				break;
			}
			case 4:
			{
				pcm.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
				pcm.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
				pcm.eChannelMapping[2] = OMX_AUDIO_ChannelLR;
				pcm.eChannelMapping[3] = OMX_AUDIO_ChannelRR;
				break;
			}
			case 2:
			{
				pcm.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
				pcm.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
				break;
			}
		}
		error = OMX_SetParameter(ILC_GET_HANDLE(st->audio_render), 
					 OMX_IndexParamAudioPcm, 
					 &pcm);
		assert(error == OMX_ErrorNone);

		/* Set audio reference clock  */
		OMX_CONFIG_BOOLEANTYPE	ref_clock;
		memset(&ref_clock, 0, sizeof(OMX_CONFIG_BOOLEANTYPE));
		param.nSize			= sizeof(OMX_CONFIG_BOOLEANTYPE);
		param.nVersion.nVersion		= OMX_VERSION;
		param.bEnabled			= OMX_FALSE;

		error = OMX_SetConfig(ILC_GET_HANDLE(st->audio_render),
				      OMX_IndexConfigBrcmClockReferenceSource,
				      &ref_clock);
		assert(error == OMX_ErrorNone);

		/* Enable audio render  */
		ilclient_change_component_state(st->audio_render, OMX_StateIdle);
		if(ilclient_enable_port_buffers(st->audio_render, 100, NULL, NULL, NULL) < 0){
			
			/* Error situation */
			ilclient_change_component_state(st->audio_render, OMX_StateLoaded);
			ilclient_cleanup_components(st->list);

			error = OMX_Deinit();
			assert(error == OMX_ErrorNone);

			ilclient_destroy(st->client);
			
			sem_destroy(&st->sema);
			free(st);
			*handle = NULL;
			return -1;
			
		}
		
		ilclient_change_component_state(st->audio_render, OMX_StateExecuting);		
	}
	return ret;
}
예제 #3
0
static int decodeJpeg(JPEG_DECODER * decoder, FILE *sourceImage, IMAGE *jpeg){
	
	char pSettingsChanged = 0, end = 0, eos = 0, bFilled = 0;
	int bufferIndex = 0;
	int retVal = OMX_IMAGE_OK;
	struct timespec wait;
	
	OMX_BUFFERHEADERTYPE *pBufHeader = decoder->ppInputBufferHeader[bufferIndex];
	ilclient_set_empty_buffer_done_callback(decoder->client, emptyBufferDone, decoder);
	
	bufferIndex^=1;
	
	pBufHeader->nFilledLen = fread(pBufHeader->pBuffer, 1, pBufHeader->nAllocLen, sourceImage);
	
	pBufHeader->nOffset = 0;
	pBufHeader->nFlags = 0;
	
	if(feof(sourceImage)){
		pBufHeader->nFlags = OMX_BUFFERFLAG_EOS;
	}else if( pBufHeader->nFilledLen !=  pBufHeader->nAllocLen){
		retVal|=OMX_IMAGE_ERROR_READING;
		end=1;
	}
	
	pthread_mutex_init(&decoder->lock, NULL);
	pthread_cond_init(&decoder->cond, NULL);
	
	while(end == 0 && retVal == OMX_IMAGE_OK){
		decoder->emptyBDone=0;
		// We've got an eos event early this usually means that we are done decoding
		if(ilclient_remove_event(decoder->component, OMX_EventBufferFlag, decoder->outPort, 
				0, OMX_BUFFERFLAG_EOS, 0 )==0){
				eos=1;
				break;
		}		
		int ret = OMX_EmptyThisBuffer(decoder->handle, pBufHeader);
		if (ret != OMX_ErrorNone) {
			retVal|=OMX_IMAGE_ERROR_MEMORY;
			break;
		}
		
		if(!feof(sourceImage)){
			
			pBufHeader = decoder->ppInputBufferHeader[bufferIndex];
			
			bufferIndex^=1;
		
			pBufHeader->nFilledLen = fread(pBufHeader->pBuffer, 1, pBufHeader->nAllocLen, sourceImage);
			
			pBufHeader->nOffset = 0;
			pBufHeader->nFlags = 0;
		
			if(feof(sourceImage)){
				pBufHeader->nFlags = OMX_BUFFERFLAG_EOS;
			}else if( pBufHeader->nFilledLen !=  pBufHeader->nAllocLen){
				retVal|=OMX_IMAGE_ERROR_READING;
				break;
			}
			
		}else{
			end=1;
		}
		
		if(pSettingsChanged == 0 && ilclient_remove_event(decoder->component,
				OMX_EventPortSettingsChanged, decoder->outPort, 0, 0, 1 ) == 0){
					pSettingsChanged=1;
					retVal|=portSettingsChanged(decoder, jpeg);
		}
		
		if(!decoder->emptyBDone){
			clock_gettime(CLOCK_REALTIME, &wait);
			wait.tv_nsec += MAX_EMPTY_BUFFER_WAIT_MS*1000000L;
			wait.tv_sec += wait.tv_nsec/1000000000L;
			wait.tv_nsec %= 1000000000L;
			if(!decoder->emptyBDone){
				decoder->emptyBDone=2;
				pthread_mutex_lock(&decoder->lock);
				pthread_cond_timedwait(&decoder->cond, &decoder->lock, &wait);
				pthread_mutex_unlock(&decoder->lock);
			}
		}
		
		if(pSettingsChanged == 0 && ilclient_wait_for_event(decoder->component,
				OMX_EventPortSettingsChanged,decoder->outPort, 0, 0, 1, 
				ILCLIENT_EVENT_ERROR | ILCLIENT_PARAMETER_CHANGED, 10) == 0){	 
			
			pSettingsChanged=1;
			retVal|=portSettingsChanged(decoder, jpeg);
		}
			
			
		if (bFilled == 0 && pSettingsChanged==1 && retVal == OMX_IMAGE_OK) {
		
			ret = OMX_FillThisBuffer(decoder->handle, decoder->pOutputBufferHeader);
			if (ret != OMX_ErrorNone) {
				retVal|=OMX_IMAGE_ERROR_MEMORY;
				break;
			}
			bFilled = 1;
		}
	}
	ilclient_set_empty_buffer_done_callback(decoder->client, NULL, NULL);
	
	if( bFilled == 1 && !eos && ilclient_wait_for_event(decoder->component, OMX_EventBufferFlag, 
				decoder->outPort, 0, OMX_BUFFERFLAG_EOS, 0, ILCLIENT_BUFFER_FLAG_EOS, TIMEOUT_MS) != 0 ){
		retVal|=OMX_IMAGE_ERROR_NO_EOS;
	}
	
	pthread_mutex_destroy(&decoder->lock);
	pthread_cond_destroy(&decoder->cond);
		
	int i = 0;
	for (i = 0; i < DECODER_BUFFER_NUM; i++) {
		int ret = OMX_FreeBuffer(decoder->handle,decoder->inPort, decoder->ppInputBufferHeader[i]);
		if(ret!= OMX_ErrorNone){
			retVal|=OMX_IMAGE_ERROR_MEMORY;
		}
	}
	
	int ret=OMX_SendCommand(decoder->handle, OMX_CommandPortDisable, decoder->inPort, NULL);
	
	if(ret!= OMX_ErrorNone){
		retVal|=OMX_IMAGE_ERROR_PORTS;
	}
			
	ilclient_wait_for_event(decoder->component, OMX_EventCmdComplete, 
			OMX_CommandPortDisable, 0, decoder->inPort, 0, 
			ILCLIENT_PORT_DISABLED, TIMEOUT_MS);		
	
	if(bFilled==1){	
		OMX_SendCommand(decoder->handle, OMX_CommandFlush, decoder->outPort, NULL);
			
		ilclient_wait_for_event(decoder->component,OMX_EventCmdComplete, OMX_CommandFlush, 
			0, decoder->outPort, 0, ILCLIENT_PORT_FLUSH ,TIMEOUT_MS);	
				
		ret= OMX_FreeBuffer(decoder->handle, decoder->outPort, decoder->pOutputBufferHeader);
		
		if(ret!= OMX_ErrorNone){
			retVal|=OMX_IMAGE_ERROR_MEMORY;
		}
		
	}
	
	if(pSettingsChanged==1){
		ret= OMX_SendCommand(decoder->handle, OMX_CommandPortDisable, decoder->outPort, NULL);
		
		if(ret!= OMX_ErrorNone){
			retVal|=OMX_IMAGE_ERROR_PORTS;
		}
	}
	
	ilclient_change_component_state(decoder->component, OMX_StateIdle);
	ilclient_change_component_state(decoder->component, OMX_StateLoaded);
					
	return retVal;
}
예제 #4
0
파일: core.c 프로젝트: cromarty/ttsprojects
int32_t ilctts_create(
	TTSRENDER_STATE_T **component,
	uint32_t sample_rate,
	uint32_t num_channels,
	uint32_t bit_depth,
	uint32_t num_buffers,
	uint32_t buffer_size_ms,
	BUFFER_SIZE_TYPE_T buffer_size_type,
	uint32_t ringbuffer_length
)
{
	ENTER(LOGLEVEL_1, "ilctts_create");

	SHOW(LOGLEVEL_5, "Sample rate: %d", sample_rate);
	SHOW(LOGLEVEL_5, "Number of channels: %d", num_channels);
	SHOW(LOGLEVEL_5, "Bit depth: %d", bit_depth);
	SHOW(LOGLEVEL_5, "Number of buffers: %d", num_buffers);
	SHOW(LOGLEVEL_5, "Buffer size: %d", buffer_size_ms);
	SHOW(LOGLEVEL_5, "Ring buffer length: %d", ringbuffer_length);

	int32_t ret;
	uint32_t buffer_size;

		OMX_ERRORTYPE omx_err;
	TTSRENDER_STATE_T *st;

	*component = NULL;

	st = calloc(1, sizeof(TTSRENDER_STATE_T));
	OMX_PARAM_PORTDEFINITIONTYPE param;
	OMX_AUDIO_PARAM_PCMMODETYPE pcm;
	int32_t s;

	*component = st;

	// create and start up everything

	// initialise buffer list semaphore
	s = sem_init(&st->buffer_list_sema, 0, 1);
	if (s < 0) {
		ERROR("sem_init returned error initializing buffer list semaphore in ilctts_create: %d", s);
		return -1;
	}

	// initial value of ringbuffer_empty_sema is 1 because at startup there is space
	s = sem_init(&st->ringbuffer_empty_sema, 0, 1);
	if (s < 0) {
		ERROR("sem_init returned error initializing ringbuffer_empty_sema in ilctts_create: %d", s);
		return -1;
	}

	// initial value of ringbuffer_data_sema is 0 because at startup there is no data
	s = sem_init(&st->ringbuffer_data_sema, 0, 0);
	if (s < 0) {
		ERROR("sem_init returned error initializing ringbuffer_data_sema in ilctts_create: %d", s);
		return -1;
	}

	// free_buffer mutex and cv
	pthread_mutex_init(&st->free_buffer_mutex, NULL);
	pthread_cond_init(&st->free_buffer_cv, NULL);

	// ringbuffer mutex
	pthread_mutex_init(&st->ringbuffer_mutex, NULL);
	//pthread_cond_init(&st->ringbuffer_cv, NULL);

	st->sample_rate = sample_rate;
	st->num_channels = num_channels;
	st->bit_depth = bit_depth;
	st->bytes_per_sample = (bit_depth * OUT_CHANNELS(num_channels)) >> 3;

	if (buffer_size_type == BS_MILLISECONDS) {
		// supplied buffer size was in milliseconds, calculate the byte size
		// note: calc_buffer_size_from_ms returns buffer size aligned for VCHI
		buffer_size = calc_buffer_size_from_ms(sample_rate, bit_depth, num_channels, buffer_size_ms, 1);
	} else {
		// supplied buffer size was in bytes
		// buffer size must be 16 byte aligned for VCHI
		buffer_size = (buffer_size_ms + 15) & ~15;
	}

	SHOW(LOGLEVEL_5, "Bytes per sample: %d", st->bytes_per_sample);
	SHOW(LOGLEVEL_5, "Calculated buffer size: %d", buffer_size);

	st->num_buffers = num_buffers;
	st->client = ilclient_init();
	st->tts_stop = 0;
	st->tts_pause_state = TTS_PAUSE_OFF;

	st->ringbuffer = ringbuffer_init(ringbuffer_length);
	if (st->ringbuffer == NULL) {
		ERROR("ringbuffer_init failed in ilctts_create", "");
		return -1;
	}

	// set up callbacks
	ilclient_set_empty_buffer_done_callback(st->client, input_buffer_callback, st);
	//ilclient_set_configchanged_callback(st->client, config_changed_callback, st);
	//ilclient_set_port_settings_callback(st->client, port_settings_changed_callback, st);

	ret = ilclient_create_component(st->client, &st->audio_render, "audio_render", ILCLIENT_ENABLE_INPUT_BUFFERS | ILCLIENT_DISABLE_ALL_PORTS);
	if (ret == -1) {
		ERROR("ilclcient_create_component returned error in ilctts_create: %d", ret);
		return ret;
	}

	st->list[0] = st->audio_render;

	// set up the number/size of buffers
		OMX_INIT_STRUCTURE(param);
	param.nPortIndex = 100;
	omx_err = OMX_GetParameter(ILC_GET_HANDLE(st->audio_render), OMX_IndexParamPortDefinition, &param);
	if (omx_err != OMX_ErrorNone) {
		ERROR("OMX_GetParameter returned error in ilctts_create: %d", omx_err);
		return -1;
	}

	// set the buffer size to the requested size, or the minimum size returned, whichever is greater
	st->buffer_size = max(buffer_size, param.nBufferSize);
	SHOW(LOGLEVEL_3, "Buffer size set to: %d", st->buffer_size);
	param.nBufferSize = st->buffer_size;
	param.nBufferCountActual = max(st->buffer_count, param.nBufferCountMin);

	omx_err = OMX_SetParameter(ILC_GET_HANDLE(st->audio_render), OMX_IndexParamPortDefinition, &param);
	if (omx_err != OMX_ErrorNone) {
		ERROR("OMX_SetParameter returned error in ilctts_create: %d", omx_err);
		return -1;
	}

	// set the pcm parameters
	OMX_INIT_STRUCTURE(pcm);
	pcm.nPortIndex = 100;
	pcm.nChannels = OUT_CHANNELS(num_channels);
	pcm.eNumData = OMX_NumericalDataSigned;
	pcm.eEndian = OMX_EndianLittle;
	pcm.nSamplingRate = sample_rate;
	pcm.bInterleaved = OMX_TRUE;
	pcm.nBitPerSample = bit_depth;
	pcm.ePCMMode = OMX_AUDIO_PCMModeLinear;

	switch(st->num_channels) {
		case 1:
			pcm.eChannelMapping[0] = OMX_AUDIO_ChannelCF;
			break;
		case 3:
			pcm.eChannelMapping[2] = OMX_AUDIO_ChannelCF;
			pcm.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
			pcm.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
			break;
		case 8:
			pcm.eChannelMapping[7] = OMX_AUDIO_ChannelRS;
		case 7:
			pcm.eChannelMapping[6] = OMX_AUDIO_ChannelLS;
		case 6:
			pcm.eChannelMapping[5] = OMX_AUDIO_ChannelRR;
		case 5:
			pcm.eChannelMapping[4] = OMX_AUDIO_ChannelLR;
		case 4:
			pcm.eChannelMapping[3] = OMX_AUDIO_ChannelLFE;
			pcm.eChannelMapping[2] = OMX_AUDIO_ChannelCF;
		case 2:
			pcm.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
		pcm.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
			break;
	}

	omx_err = OMX_SetParameter(ILC_GET_HANDLE(st->audio_render), OMX_IndexParamAudioPcm, &pcm);
	if (omx_err != OMX_ErrorNone) {
		ERROR("OMX_SetParameter returned error in ilctts_create: %d", omx_err);
		return -1;
	}

	// this function waits for the command to complete
	ret = ilclient_change_component_state(st->audio_render, OMX_StateIdle);
	if (ret < 0) {
		ERROR("ilctts_change_component_state returned error in ilctts_create: %d", ret);
		return -1;
	}

	ret = ilclient_enable_port_buffers(st->audio_render, 100, NULL, NULL, NULL);
	if (ret < 0) {
		ERROR("ilclient_enable_port_buffers returned error in ilctts_create: %d", ret);
		ilclient_change_component_state(st->audio_render, OMX_StateLoaded);
		ilclient_cleanup_components(st->list);
		omx_err = OMX_Deinit();
		ilclient_destroy(st->client);
		destroy_semaphores(st);
		destroy_mutexes(st);
		ringbuffer_destroy(st->ringbuffer);
		// need to destroy and free other stuff here?
		free(st);
		*component = NULL;
		return -1;
	}

	INFO(LOGLEVEL_1, "Setting state to executing in ilctts_create");
	return ilclient_change_component_state(st->audio_render, OMX_StateExecuting);

} // end ilctts_create