/**@ingroup tsk_condwait_group * Wakes up all threads that are currently waiting for the condition. * @param handle CondWait handle created using @ref tsk_condwait_create. * @retval Zero if succeed and non-zero otherwise. * @sa @ref tsk_condwait_signal. */ int tsk_condwait_broadcast(tsk_condwait_handle_t* handle) { int ret = EINVAL; tsk_condwait_t *condwait = (tsk_condwait_t*)handle; if(!condwait){ TSK_DEBUG_ERROR("Invalid parameter"); return -1; } #if TSK_UNDER_WINDOWS if(ret = ((SetEvent(condwait->pcond) && ResetEvent(condwait->pcond)) ? 0 : -1)){ ret = GetLastError(); TSK_DEBUG_ERROR("SetEvent function failed: %d", ret); } #else if(condwait && condwait->mutex){ tsk_mutex_lock(condwait->mutex); if((ret = pthread_cond_broadcast(condwait->pcond))){ TSK_DEBUG_ERROR("pthread_cond_broadcast function failed: %d", ret); } tsk_mutex_unlock(condwait->mutex); } #endif return ret; }
static OSStatus __handle_output_buffer(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) { OSStatus status = noErr; // tsk_size_t out_size; tdav_consumer_audiounit_t* consumer = (tdav_consumer_audiounit_t* )inRefCon; if(!consumer->started || consumer->paused){ goto done; } if(!ioData){ TSK_DEBUG_ERROR("Invalid argument"); status = kNoDataError; goto done; } // read from jitter buffer and fill ioData buffers tsk_mutex_lock(consumer->ring.mutex); for(int i=0; i<ioData->mNumberBuffers; i++){ /* int ret = */ tdav_consumer_audiounit_get(consumer, ioData->mBuffers[i].mData, ioData->mBuffers[i].mDataByteSize); } tsk_mutex_unlock(consumer->ring.mutex); done: return status; }
/**@ingroup tsk_condwait_group * Block the current thread until the condition is opened. * @param handle CondWait handle created using @ref tsk_condwait_create. * @retval Zero if succeed and non-zero otherwise. * @sa @ref tsk_condwait_timedwait. */ int tsk_condwait_wait(tsk_condwait_handle_t* handle) { int ret = EINVAL; tsk_condwait_t *condwait = (tsk_condwait_t*)handle; if(!condwait){ TSK_DEBUG_ERROR("Invalid parameter"); return -1; } #if TSK_UNDER_WINDOWS if((ret = (WaitForSingleObject(condwait->pcond, INFINITE) == WAIT_FAILED) ? -1 : 0)){ TSK_DEBUG_ERROR("WaitForSingleObject function failed: %d", ret); } #else if(condwait && condwait->mutex){ tsk_mutex_lock(condwait->mutex); if((ret = pthread_cond_wait(condwait->pcond, (pthread_mutex_t*)condwait->mutex))) { TSK_DEBUG_ERROR("pthread_cond_wait function failed: %d", ret); } tsk_mutex_unlock(condwait->mutex); } #endif return ret; }
static OSStatus __handle_input_buffer(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) { OSStatus status = noErr; tdav_producer_audiounit_t* producer = (tdav_producer_audiounit_t*)inRefCon; // holder AudioBuffer buffer; buffer.mData = tsk_null; buffer.mDataByteSize = 0; buffer.mNumberChannels = TMEDIA_PRODUCER(producer)->audio.channels; // list of holders AudioBufferList buffers; buffers.mNumberBuffers = 1; buffers.mBuffers[0] = buffer; // render to get frames from the system status = AudioUnitRender(tdav_audiounit_handle_get_instance(producer->audioUnitHandle), ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, &buffers); if(status == 0){ tsk_mutex_lock(producer->ring.mutex); speex_buffer_write(producer->ring.buffer, buffers.mBuffers[0].mData, buffers.mBuffers[0].mDataByteSize); tsk_mutex_unlock(producer->ring.mutex); } return status; }
/**@ingroup tsk_list_group * Locks the @ref tsk_list_t "list" to avoid concurrent access. The @ref tsk_list_t "list" must be unlocked using @ref tsk_list_unlock(). <br /> * For more information about thread-safety see @ref _Anchor_TinySAK_Linked_List_Thread_Safety "here". * @param list The list to lock. * @return 0 if succeed and non-zero error code otherwise. * @sa @ref tsk_list_unlock */ int tsk_list_lock(tsk_list_t* list) { if(list){ if(!list->mutex){ list->mutex = tsk_mutex_create(); } return tsk_mutex_lock(list->mutex); } else{ TSK_DEBUG_ERROR("Invalid parameter"); return -1; } }
/**@ingroup tsk_condwait_group * Block the current thread until the condition is opened or until @a ms milliseconds have passed. * @param handle condwait handle created using @ref tsk_condwait_create. * @param ms The number of milliseconds to wait for a given condition. * @retval Zero if succeed and non-zero error code otherwise. * @sa @ref tsk_condwait_wait. */ int tsk_condwait_timedwait(tsk_condwait_handle_t* handle, uint64_t ms) { #if TSK_UNDER_WINDOWS DWORD ret = WAIT_FAILED; #else int ret = EINVAL; #endif tsk_condwait_t *condwait = (tsk_condwait_t*)handle; #if TSK_UNDER_WINDOWS if((ret = WaitForSingleObject(condwait->pcond, (DWORD)ms)) != WAIT_OBJECT_0){ if(ret == TIMED_OUT){ /* TSK_DEBUG_INFO("WaitForSingleObject function timedout: %d", ret); */ } else{ TSK_DEBUG_ERROR("WaitForSingleObject function failed: %d", ret); } return ((ret == TIMED_OUT) ? 0 : ret); } #else if(condwait && condwait->mutex){ struct timespec ts = {0, 0}; struct timeval tv = {0, 0}; /*int rc =*/ tsk_gettimeofday(&tv, 0); ts.tv_sec = ( tv.tv_sec + ((long)ms/1000) ); ts.tv_nsec += ( (tv.tv_usec * 1000) + ((long)ms % 1000 * 1000000) ); if(ts.tv_nsec > 999999999) ts.tv_sec+=1, ts.tv_nsec = ts.tv_nsec % 1000000000; tsk_mutex_lock(condwait->mutex); if((ret = pthread_cond_timedwait(condwait->pcond, (pthread_mutex_t*)condwait->mutex, &ts))){ if(ret == TIMED_OUT){ /* TSK_DEBUG_INFO("pthread_cond_timedwait function timedout: %d", ret); */ } else{ TSK_DEBUG_ERROR("pthread_cond_timedwait function failed: %d", ret); } } tsk_mutex_unlock(condwait->mutex); return ((ret == TIMED_OUT) ? 0 : ret); } #endif return ret; }
static void *__sender_thread(void *param) { TSK_DEBUG_INFO("__sender_thread::ENTER"); tdav_producer_audiounit_t* producer = (tdav_producer_audiounit_t*)param; uint32_t ptime = TMEDIA_PRODUCER(producer)->audio.ptime; tsk_ssize_t avail; // interval to sleep when using nonosleep() instead of conditional variable struct timespec interval; interval.tv_sec = (long)(ptime/1000); interval.tv_nsec = (long)(ptime%1000) * 1000000; // change thread priority //#if TARGET_OS_IPHONE __sender_thread_set_realtime(TMEDIA_PRODUCER(producer)->audio.ptime); //#endif // starts looping for (;;) { // wait for "ptime" milliseconds if(ptime <= kMaxPtimeBeforeUsingCondVars){ nanosleep(&interval, 0); } else { tsk_condwait_timedwait(producer->senderCondWait, (uint64_t)ptime); } // check state if(!producer->started){ break; } // read data and send them if(TMEDIA_PRODUCER(producer)->enc_cb.callback) { tsk_mutex_lock(producer->ring.mutex); avail = speex_buffer_get_available(producer->ring.buffer); while (producer->started && avail >= producer->ring.chunck.size) { avail -= speex_buffer_read(producer->ring.buffer, producer->ring.chunck.buffer, producer->ring.chunck.size); TMEDIA_PRODUCER(producer)->enc_cb.callback(TMEDIA_PRODUCER(producer)->enc_cb.callback_data, producer->ring.chunck.buffer, producer->ring.chunck.size); } tsk_mutex_unlock(producer->ring.mutex); } else; } TSK_DEBUG_INFO("__sender_thread::EXIT"); return tsk_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 }