static tsk_size_t tdav_consumer_audiounit_get(tdav_consumer_audiounit_t* self, void* data, tsk_size_t size)
{
	tsk_ssize_t retSize = 0;
	
#if DISABLE_JITTER_BUFFER
	retSize = speex_buffer_read(self->ring.buffer, data, size);
	if(retSize < size){
		memset(((uint8_t*)data)+retSize, 0, (size - retSize));
	}
#else
	self->ring.leftBytes += size;
	while (self->ring.leftBytes >= self->ring.chunck.size) {
		self->ring.leftBytes -= self->ring.chunck.size;
		retSize =  (tsk_ssize_t)tdav_consumer_audio_get(TDAV_CONSUMER_AUDIO(self), self->ring.chunck.buffer, self->ring.chunck.size);
		tdav_consumer_audio_tick(TDAV_CONSUMER_AUDIO(self));
		speex_buffer_write(self->ring.buffer, self->ring.chunck.buffer, retSize);
	}
	// IMPORTANT: looks like there is a bug in speex: continously trying to read more than avail
	// many times can corrupt the buffer. At least on OS X 1.5
	if(speex_buffer_get_available(self->ring.buffer) >= size){
		retSize = speex_buffer_read(self->ring.buffer, data, size);
	}
	else{
		memset(data, 0, size);
	}
#endif

	return retSize;
}
Пример #2
0
/* destructor */
static tsk_object_t* tdav_consumer_dsound_dtor(tsk_object_t * self)
{ 
	tdav_consumer_dsound_t *dsound = self;
	if(dsound){
		tsk_size_t i;

		/* stop */
		if(dsound->started){
			tdav_consumer_dsound_stop(self);
		}

		/* deinit base */
		tdav_consumer_audio_deinit(TDAV_CONSUMER_AUDIO(dsound));
		/* deinit self */
		// Delete secondary buffer
		if(dsound->primaryBuffer){
			IDirectSoundBuffer_Release(dsound->primaryBuffer);
		}
		if(dsound->secondaryBuffer){
			IDirectSoundBuffer_Release(dsound->secondaryBuffer);
		}
		if(dsound->device){
			IDirectSound_Release(dsound->device);
		}
		for(i = 0; i<sizeof(dsound->notifEvents)/sizeof(HANDLE); i++){
			if(dsound->notifEvents[i]){
				CloseHandle(dsound->notifEvents[i]);
			}
		}
	}

	return self;
}
Пример #3
0
/* destructor */
static tsk_object_t* tdav_consumer_audioqueue_dtor(tsk_object_t * self)
{ 
	tdav_consumer_audioqueue_t *consumer = self;
	if(consumer){
		// Stop the consumer if not done
		if(consumer->started){
			tdav_consumer_audioqueue_stop(self);
		}
		
		// Free all buffers and dispose the queue
        if (consumer->queue) {
			tsk_size_t i;
			
			for(i=0; i<CoreAudioPlayBuffers; i++){
				AudioQueueFreeBuffer(consumer->queue, consumer->buffers[i]);
			}
			
            AudioQueueDispose(consumer->queue, true);
        }
        
		/* deinit base */
		tdav_consumer_audio_deinit(TDAV_CONSUMER_AUDIO(consumer));
	}
	
	return self;
}
/* destructor */
static tsk_object_t* tdav_consumer_audiounit_dtor(tsk_object_t * self)
{ 
	tdav_consumer_audiounit_t *consumer = self;
	if(consumer){
		/* deinit self */
		// Stop the consumer if not done
		if(consumer->started){
			tdav_consumer_audiounit_stop(self);
		}
		// destroy handle
		if(consumer->audioUnitHandle){
			tdav_audiounit_handle_destroy(&consumer->audioUnitHandle);
		}
		TSK_FREE(consumer->ring.chunck.buffer);
		if(consumer->ring.buffer){
			speex_buffer_destroy(consumer->ring.buffer);
		}
		if(consumer->ring.mutex){
			tsk_mutex_destroy(&consumer->ring.mutex);
		}
        
		/* deinit base */
		tdav_consumer_audio_deinit(TDAV_CONSUMER_AUDIO(consumer));
	}
	
	return self;
}
Пример #5
0
static void* TSK_STDCALL _tdav_consumer_oss_playback_thread(void *param)
{
	tdav_consumer_oss_t*  p_oss = (tdav_consumer_oss_t*)param;
	int err;
	void* p_buffer = ((p_oss->n_bits_per_sample == 8) ? (void*)p_oss->p_buff16_ptr: (void*)p_oss->p_buff_ptr);
	tsk_size_t n_buffer_in_bytes = (p_oss->n_bits_per_sample == 8) ?  p_oss->n_buff16_size_in_bytes :  p_oss->n_buff_size_in_bytes;
	tsk_size_t n_buffer_in_samples = p_oss->n_buff_size_in_samples;

	const void* _p_buffer;
	tsk_size_t _n_buffer_in_bytes;

	OSS_DEBUG_INFO("__playback_thread -- START");

	tsk_thread_set_priority_2(TSK_THREAD_PRIORITY_TIME_CRITICAL);
	
	while (p_oss->b_started) {
		tsk_safeobj_lock(p_oss);
		err = tdav_consumer_audio_get(TDAV_CONSUMER_AUDIO(p_oss), p_buffer, n_buffer_in_bytes); // requires 16bits, thread-safe
		if (err >= 0) {
			_p_buffer = p_buffer;
			_n_buffer_in_bytes = n_buffer_in_bytes;
			if (err < n_buffer_in_bytes) {
				memset(((uint8_t*)p_buffer) + err, 0, (n_buffer_in_bytes - err));
			}
			if (p_oss->n_bits_per_sample == 8) {
				__oss_from_16bits_to_8bits(p_buffer, p_oss->p_buff_ptr, n_buffer_in_samples);
				_p_buffer = p_oss->p_buff_ptr;
				_n_buffer_in_bytes >>= 1; 
			}
			if ((err = write(p_oss->fd, _p_buffer, _n_buffer_in_bytes)) != _n_buffer_in_bytes) {
				OSS_DEBUG_ERROR ("Failed to read data from audio interface failed (%d -> %s)", err , strerror(errno));
				tsk_safeobj_unlock(p_oss);
				goto bail;
			}
		}
Пример #6
0
static void __handle_output_buffer(void *userdata, AudioQueueRef queue, AudioQueueBufferRef buffer) {
    tdav_consumer_audioqueue_t* consumer = (tdav_consumer_audioqueue_t*)userdata;
	
    if (!consumer->started) {
        return;
    }
    
	if(!tdav_consumer_audio_get(TDAV_CONSUMER_AUDIO(consumer), buffer->mAudioData, consumer->buffer_size)){
		// Put silence
		memset(buffer->mAudioData, 0, consumer->buffer_size);
	}
    
    // Re-enqueue the buffer
    AudioQueueEnqueueBuffer(consumer->queue, buffer, 0, NULL);
	// alert the jitter buffer
	tdav_consumer_audio_tick(TDAV_CONSUMER_AUDIO(consumer));
}
Пример #7
0
/* constructor */
static tsk_object_t* tdav_consumer_audioqueue_ctor(tsk_object_t * self, va_list * app)
{
	tdav_consumer_audioqueue_t *consumer = self;
	if(consumer){
		/* init base */
		tdav_consumer_audio_init(TDAV_CONSUMER_AUDIO(consumer));
	}
	return self;
}
Пример #8
0
int tdav_consumer_dsound_consume(tmedia_consumer_t* self, void** buffer, tsk_size_t size, const tsk_object_t* proto_hdr)
{
	tdav_consumer_dsound_t* dsound = (tdav_consumer_dsound_t*)self;

	if(!dsound || !buffer || !*buffer || !size){
		TSK_DEBUG_ERROR("Invalid parameter");
		return -1;
	}
	/* buffer is already decoded */
	return tdav_consumer_audio_put(TDAV_CONSUMER_AUDIO(dsound), buffer, size, proto_hdr);
}
Пример #9
0
int tdav_consumer_audioqueue_consume(tmedia_consumer_t* self, const void* buffer, tsk_size_t size, const tsk_object_t* proto_hdr)
{
	tdav_consumer_audioqueue_t* consumer = (tdav_consumer_audioqueue_t*)self;
	
	if(!consumer || !buffer || !size){
		TSK_DEBUG_ERROR("Invalid parameter");
		return -1;
	}
	// buffer is already decoded
	return tdav_consumer_audio_put(TDAV_CONSUMER_AUDIO(consumer), buffer, size, proto_hdr);
}
/* ============ Media Consumer Interface ================= */
int tdav_consumer_audiounit_set(tmedia_consumer_t* self, const tmedia_param_t* param)
{
    tdav_consumer_audiounit_t* consumer = (tdav_consumer_audiounit_t*)self;
    if (param->plugin_type == tmedia_ppt_consumer) {
        if (param->value_type == tmedia_pvt_int32) {
            if (tsk_striequals(param->key, "interrupt")) {
                int32_t interrupt = *((uint8_t*)param->value) ? 1 : 0;
                return tdav_audiounit_handle_interrupt(consumer->audioUnitHandle, interrupt);
            }
            else if (tsk_striequals(param->key, "pause") || tsk_striequals(param->key, "hold")) {
                int32_t pause = *((uint8_t*)param->value) ? 1 : 0;
                return pause ? tdav_consumer_audiounit_pause(self) : tdav_consumer_audiounit_resume(self);
            }
        }
    }
    return tdav_consumer_audio_set(TDAV_CONSUMER_AUDIO(self), param);
}
/* destructor */
static tsk_object_t* tdav_consumer_audiounit_dtor(tsk_object_t * self)
{
    tdav_consumer_audiounit_t *consumer = self;
    if(consumer) {
        /* deinit self */
        tdav_consumer_audiounit_deinit(TMEDIA_CONSUMER(self));
        TSK_FREE(consumer->ring.chunck.buffer);
        if(consumer->ring.buffer) {
            speex_buffer_destroy(consumer->ring.buffer);
        }
        if(consumer->ring.mutex) {
            tsk_mutex_destroy(&consumer->ring.mutex);
        }

        /* deinit base */
        tdav_consumer_audio_deinit(TDAV_CONSUMER_AUDIO(consumer));
        TSK_DEBUG_INFO("*** AudioUnit Consumer destroyed ***");
    }

    return self;
}
Пример #12
0
static void __handle_output_buffer(void *userdata, AudioQueueRef queue, AudioQueueBufferRef buffer) {
    OSStatus ret;
	void *data;
	tsk_size_t out_size = 0;
    tdav_consumer_coreaudio_t* consumer = (tdav_consumer_coreaudio_t*)userdata;

    if (!consumer->started) {
        return;
    }
    
	if((data = tdav_consumer_audio_get(TDAV_CONSUMER_AUDIO(consumer), &out_size))){
        // If we can get audio to play, then copy in the buffer
		memcpy(buffer->mAudioData, data, TSK_MIN(consumer->buffer_size, out_size));
		TSK_FREE(data);
	} else{
        // Put silence if there is no audio to play
        memset(buffer->mAudioData, 0, consumer->buffer_size);
	}
    
    // Re-enqueue the buffer
    ret = AudioQueueEnqueueBuffer(consumer->queue, buffer, 0, NULL);
}
static int tdav_consumer_audiounit_consume(tmedia_consumer_t* self, const void* buffer, tsk_size_t size, const tsk_object_t* proto_hdr)
{	
	tdav_consumer_audiounit_t* consumer = (tdav_consumer_audiounit_t*)self;
	if(!consumer || !buffer || !size){
		TSK_DEBUG_ERROR("Invalid parameter");
		return -1;
	}
#if DISABLE_JITTER_BUFFER
	{
		if(consumer->ring.buffer){
			tsk_mutex_lock(consumer->ring.mutex);
			speex_buffer_write(consumer->ring.buffer, (void*)buffer, size);
			tsk_mutex_unlock(consumer->ring.mutex);
			return 0;
		}
		return -2;
	}
#else
	{
		return tdav_consumer_audio_put(TDAV_CONSUMER_AUDIO(consumer), buffer, size, proto_hdr);
	}
#endif
}
/* ============ Media Consumer Interface ================= */
int tdav_consumer_audiounit_set(tmedia_consumer_t* self, const tmedia_param_t* param)
{
	return tdav_consumer_audio_set(TDAV_CONSUMER_AUDIO(self), param);
}
Пример #15
0
/**
* Generic function to compare two consumers.
* @param consumer1 The first consumer to compare.
* @param consumer2 The second consumer to compare.
* @retval Returns an integral value indicating the relationship between the two consumers:
* <0 : @a consumer1 less than @a consumer2.<br>
* 0  : @a consumer1 identical to @a consumer2.<br>
* >0 : @a consumer1 greater than @a consumer2.<br>
*/
int tdav_consumer_audio_cmp(const tsk_object_t* consumer1, const tsk_object_t* consumer2)
{	
	return (TDAV_CONSUMER_AUDIO(consumer1) - TDAV_CONSUMER_AUDIO(consumer2));
}
Пример #16
0
int tdav_consumer_coreaudio_prepare(tmedia_consumer_t* self, const tmedia_codec_t* codec)
{
    OSStatus ret;
	tsk_size_t i;
	tdav_consumer_coreaudio_t* consumer = (tdav_consumer_coreaudio_t*)self;

	if(!consumer || !codec && codec->plugin){
		TSK_DEBUG_ERROR("Invalid parameter");
		return -1;
	}
	
	TDAV_CONSUMER_AUDIO(consumer)->channels = codec->plugin->audio.channels;
	TDAV_CONSUMER_AUDIO(consumer)->rate = codec->plugin->rate;
	/* codec should have ptime */

	// Set audio category
	UInt32 category = kAudioSessionCategory_PlayAndRecord; 
	AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(category), &category);
	
    // Create the audio stream description
    AudioStreamBasicDescription *description = &(consumer->description);
    description->mSampleRate = TDAV_CONSUMER_AUDIO(consumer)->rate;
    description->mFormatID = kAudioFormatLinearPCM;
    description->mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
    description->mChannelsPerFrame = TDAV_CONSUMER_AUDIO(consumer)->channels;
    description->mFramesPerPacket = 1;
    description->mBitsPerChannel = TDAV_CONSUMER_AUDIO(consumer)->bits_per_sample;
    description->mBytesPerPacket = description->mBitsPerChannel / 8 * description->mChannelsPerFrame;
    description->mBytesPerFrame = description->mBytesPerPacket;
    description->mReserved = 0;
    
    int packetperbuffer = 1000 / TDAV_CONSUMER_AUDIO(consumer)->ptime;
    consumer->buffer_size = description->mSampleRate * description->mBytesPerFrame / packetperbuffer;
    
    // Create the playback audio queue
    ret = AudioQueueNewOutput(&(consumer->description),
                              __handle_output_buffer,
                              consumer,
                              NULL, 
                              NULL,
                              0,
                              &(consumer->queue));
    
    for(i = 0; i < CoreAudioPlayBuffers; i++) {
        // Create the buffer for the queue
        ret = AudioQueueAllocateBuffer(consumer->queue, consumer->buffer_size, &(consumer->buffers[i]));
        if (ret) {
            break;
        }
        
        // Clear the data
        memset(consumer->buffers[i]->mAudioData, 0, consumer->buffer_size);
        consumer->buffers[i]->mAudioDataByteSize = consumer->buffer_size;
        
        // Enqueue the buffer
        ret = AudioQueueEnqueueBuffer(consumer->queue, consumer->buffers[i], 0, NULL);
        if (ret) {
            break;
        }
    }
	
	return ret;
}
Пример #17
0
/* ============ Media Consumer Interface ================= */
int tdav_consumer_dsound_prepare(tmedia_consumer_t* self, const tmedia_codec_t* codec)
{
	HRESULT hr;
	HWND hWnd;

	WAVEFORMATEX wfx = {0};
	DSBUFFERDESC dsbd = {0};

	tdav_consumer_dsound_t* dsound = (tdav_consumer_dsound_t*)self;

	if(!dsound){
		TSK_DEBUG_ERROR("Invalid parameter");
		return -1;
	}

	if(dsound->device || dsound->primaryBuffer || dsound->secondaryBuffer){
		TSK_DEBUG_ERROR("Consumer already prepared");
		return -2;
	}

	TDAV_CONSUMER_AUDIO(dsound)->channels = codec->plugin->audio.channels;
	TDAV_CONSUMER_AUDIO(dsound)->rate = codec->plugin->rate;

	/* Create sound device */
	if((hr = DirectSoundCreate(NULL, &dsound->device, NULL) != DS_OK)){
		tdav_win32_print_error("DirectSoundCreate", hr);
		return -3;
	}

	/* Set CooperativeLevel */
	if((hWnd = GetConsoleWindow()) || (hWnd = GetDesktopWindow()) || (hWnd = GetForegroundWindow())){
		if((hr = IDirectSound_SetCooperativeLevel(dsound->device, hWnd, DSSCL_PRIORITY)) != DS_OK){
			tdav_win32_print_error("IDirectSound_SetCooperativeLevel", hr);
		}
	}

	/* Creates the primary buffer and apply format */
	wfx.wFormatTag = WAVE_FORMAT_PCM;
	wfx.nChannels = TDAV_CONSUMER_AUDIO(dsound)->channels;
	wfx.nSamplesPerSec = TDAV_CONSUMER_AUDIO(dsound)->rate;
	wfx.wBitsPerSample = TDAV_CONSUMER_AUDIO(dsound)->bits_per_sample;
	wfx.nBlockAlign = (wfx.nChannels * wfx.wBitsPerSample/8);
	wfx.nAvgBytesPerSec = (wfx.nSamplesPerSec * wfx.nBlockAlign);

	/* Average bytes (count) for each notification */
	dsound->bytes_per_notif = ((wfx.nAvgBytesPerSec * TDAV_CONSUMER_AUDIO(dsound)->ptime)/1000);

	dsbd.dwSize = sizeof(DSBUFFERDESC);
	dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
	dsbd.dwBufferBytes = 0;
	dsbd.lpwfxFormat = NULL;

	if((hr = IDirectSound_CreateSoundBuffer(dsound->device, &dsbd, &dsound->primaryBuffer, NULL)) != DS_OK){
		tdav_win32_print_error("IDirectSound_CreateSoundBuffer", hr);
		return -4;
	}
	if((hr = IDirectSoundBuffer_SetFormat(dsound->primaryBuffer, &wfx)) != DS_OK){
		tdav_win32_print_error("IDirectSoundBuffer_SetFormat", hr);
		return -5;
	}

	/* Creates the secondary buffer and apply format */
	dsbd.dwFlags = (DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GLOBALFOCUS);
	dsbd.dwBufferBytes = (TDAV_DSOUNS_CONSUMER_NOTIF_POS_COUNT * dsound->bytes_per_notif);
	dsbd.lpwfxFormat = &wfx;

	if((hr = IDirectSound_CreateSoundBuffer(dsound->device, &dsbd, &dsound->secondaryBuffer, NULL)) != DS_OK){
		tdav_win32_print_error("IDirectSound_CreateSoundBuffer", hr);
		return -6;
	}
	

	return 0;
}
Пример #18
0
static void *__playback_thread(void *param)
{
	tdav_consumer_dsound_t* dsound = (tdav_consumer_dsound_t*)param; 

	HRESULT hr;
	LPVOID lpvAudio1, lpvAudio2;
	DWORD dwBytesAudio1, dwBytesAudio2;

	void* data;
	int index;

	TSK_DEBUG_INFO("__playback_thread -- START");

	SetPriorityClass(GetCurrentThread(), REALTIME_PRIORITY_CLASS);

	for(;;){
		DWORD dwEvent = WaitForMultipleObjects(sizeof(dsound->notifEvents)/sizeof(HANDLE), dsound->notifEvents, FALSE, INFINITE);

		if(!dsound->started){
			break;
		}
		else {
			tsk_size_t out_size = 0;
			data = tdav_consumer_audio_get(TDAV_CONSUMER_AUDIO(dsound), &out_size);
			index = (dwEvent == (TDAV_DSOUNS_CONSUMER_NOTIF_POS_COUNT-1)) ? 0 : (dwEvent + 1);
			
			// lock
			if((hr = IDirectSoundBuffer_Lock(dsound->secondaryBuffer, (index * dsound->bytes_per_notif), dsound->bytes_per_notif, &lpvAudio1, &dwBytesAudio1, &lpvAudio2, &dwBytesAudio2, 0)) != DS_OK){
				tdav_win32_print_error("IDirectSoundBuffer_Lock", hr);
				goto next;
			}

			if(data){
				// copy data to dsound buffers
				memcpy(lpvAudio1, data, TSK_MIN(dwBytesAudio1, out_size));
				if(lpvAudio2){
					memcpy(lpvAudio2, ((LPBYTE*)data) + dwBytesAudio1, dwBytesAudio2);
				}
			}
			else{
				// Put silence
				memset(lpvAudio1, 0, dwBytesAudio1);
				if(lpvAudio2){
					memset(lpvAudio2, 0, dwBytesAudio2);
				}
			}

			// unlock
			if((hr = IDirectSoundBuffer_Unlock(dsound->secondaryBuffer, lpvAudio1, dwBytesAudio1, lpvAudio2, dwBytesAudio2)) != DS_OK){
				tdav_win32_print_error("IDirectSoundBuffer_UnLock", hr);
				goto next;
			}
next:
			TSK_FREE(data);
		}
	}

	TSK_DEBUG_INFO("__playback_thread -- STOP");
	

	return tsk_null;
}