Destroy audioUnit instance when call is put on hold to allow multiple audio sessions

This commit is contained in:
System Administrator 2016-10-21 04:05:06 +02:00
parent a4973c7fe3
commit 6b9f5f831a
85 changed files with 435 additions and 349 deletions

0
thirdparties/common/include/openssl/aes.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/asn1.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/asn1_mac.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/asn1t.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/bio.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/blowfish.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/bn.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/buffer.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/camellia.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/cast.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/cmac.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/cms.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/comp.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/conf.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/conf_api.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/crypto.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/des.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/des_old.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/dh.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/dsa.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/dso.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/dtls1.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/e_os2.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/ebcdic.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/ec.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/ecdh.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/ecdsa.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/engine.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/err.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/evp.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/hmac.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/idea.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/krb5_asn.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/kssl.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/lhash.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/md4.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/md5.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/mdc2.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/modes.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/obj_mac.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/objects.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/ocsp.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/opensslconf.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/opensslv.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/ossl_typ.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/pem.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/pem2.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/pkcs12.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/pkcs7.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/pqueue.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/rand.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/rc2.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/rc4.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/ripemd.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/rsa.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/safestack.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/seed.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/sha.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/srp.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/srtp.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/ssl.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/ssl2.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/ssl23.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/ssl3.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/stack.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/symhacks.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/tls1.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/ts.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/txt_db.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/ui.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/ui_compat.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/whrlpool.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/x509.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/x509_vfy.h Normal file → Executable file
View File

0
thirdparties/common/include/openssl/x509v3.h Normal file → Executable file
View File

0
thirdparties/iphone/lib/universal/libcrypto.a Normal file → Executable file
View File

0
thirdparties/iphone/lib/universal/libssl.a Normal file → Executable file
View File

0
thirdparties/mac/lib/universal/libcrypto.a Normal file → Executable file
View File

0
thirdparties/mac/lib/universal/libssl.a Normal file → Executable file
View File

View File

@ -48,8 +48,8 @@ typedef void* tdav_audiounit_handle_t;
tdav_audiounit_handle_t* tdav_audiounit_handle_create(uint64_t session_id);
AudioComponentInstance tdav_audiounit_handle_get_instance(tdav_audiounit_handle_t* self);
int tdav_audiounit_handle_signal_consumer_prepared(tdav_audiounit_handle_t* self);
int tdav_audiounit_handle_signal_producer_prepared(tdav_audiounit_handle_t* self);
int tdav_audiounit_handle_signal_consumer_ready(tdav_audiounit_handle_t* self);
int tdav_audiounit_handle_signal_producer_ready(tdav_audiounit_handle_t* self);
int tdav_audiounit_handle_start(tdav_audiounit_handle_t* self);
uint32_t tdav_audiounit_handle_get_frame_duration(tdav_audiounit_handle_t* self);
int tdav_audiounit_handle_configure(tdav_audiounit_handle_t* self, tsk_bool_t consumer, uint32_t ptime, AudioStreamBasicDescription* audioFormat);

View File

@ -42,6 +42,7 @@ typedef struct tdav_consumer_audiounit_s {
tdav_audiounit_handle_t* audioUnitHandle;
unsigned started:1;
unsigned paused:1;
unsigned ready:1;
struct {
struct {

View File

@ -41,7 +41,8 @@ typedef struct tdav_producer_audiounit_s {
tdav_audiounit_handle_t* audioUnitHandle;
unsigned started:1;
unsigned paused:1;
unsigned muted;
unsigned ready:1;
unsigned muted:1;
struct {
struct {

View File

@ -60,7 +60,7 @@ typedef struct tdav_audiounit_instance_s {
struct {
unsigned consumer:1;
unsigned producer:1;
} prepared;
} ready;
unsigned started:1;
unsigned interrupted:1;
@ -75,7 +75,7 @@ typedef tsk_list_t tdav_audiounit_instances_L_t;
static AudioComponent __audioSystem = tsk_null;
static tdav_audiounit_instances_L_t* __audioUnitInstances = tsk_null;
static int _tdav_audiounit_handle_signal_xxx_prepared(tdav_audiounit_handle_t* self, tsk_bool_t consumer)
static int _tdav_audiounit_handle_signal_xxx_ready(tdav_audiounit_handle_t* self, tsk_bool_t consumer)
{
tdav_audiounit_instance_t* inst = (tdav_audiounit_instance_t*)self;
if(!inst || !inst->audioUnit) {
@ -85,18 +85,18 @@ static int _tdav_audiounit_handle_signal_xxx_prepared(tdav_audiounit_handle_t* s
tsk_safeobj_lock(inst);
if(consumer) {
inst->prepared.consumer = tsk_true;
if (consumer) {
inst->ready.consumer = tsk_true;
}
else {
inst->prepared.producer = tsk_true;
inst->ready.producer = tsk_true;
}
OSStatus status;
// For iOS we are using full-duplex AudioUnit and we wait for both consumer and producer to be prepared
#if TARGET_OS_IPHONE
if(inst->prepared.consumer && inst->prepared.producer)
if(inst->ready.consumer && inst->ready.producer)
#endif
{
status = AudioUnitInitialize(inst->audioUnit);
@ -184,14 +184,14 @@ AudioComponentInstance tdav_audiounit_handle_get_instance(tdav_audiounit_handle_
return ((tdav_audiounit_instance_t*)self)->audioUnit;
}
int tdav_audiounit_handle_signal_consumer_prepared(tdav_audiounit_handle_t* self)
int tdav_audiounit_handle_signal_consumer_ready(tdav_audiounit_handle_t* self)
{
return _tdav_audiounit_handle_signal_xxx_prepared(self, tsk_true);
return _tdav_audiounit_handle_signal_xxx_ready(self, tsk_true);
}
int tdav_audiounit_handle_signal_producer_prepared(tdav_audiounit_handle_t* self)
int tdav_audiounit_handle_signal_producer_ready(tdav_audiounit_handle_t* self)
{
return _tdav_audiounit_handle_signal_xxx_prepared(self, tsk_false);
return _tdav_audiounit_handle_signal_xxx_ready(self, tsk_false);
}
int tdav_audiounit_handle_start(tdav_audiounit_handle_t* self)
@ -204,18 +204,23 @@ int tdav_audiounit_handle_start(tdav_audiounit_handle_t* self)
}
tsk_safeobj_lock(inst);
status = (OSStatus)tdav_apple_enable_audio();
if (status == noErr) {
if ((!inst->started || inst->interrupted) && (status = AudioOutputUnitStart(inst->audioUnit))) {
TSK_DEBUG_ERROR("AudioOutputUnitStart failed with status=%ld", (signed long)status);
if (inst->ready.consumer && inst->ready.producer) {
status = (OSStatus)tdav_apple_enable_audio();
if (status == noErr) {
if ((!inst->started || inst->interrupted) && (status = AudioOutputUnitStart(inst->audioUnit))) {
TSK_DEBUG_ERROR("AudioOutputUnitStart failed with status=%ld", (signed long)status);
}
}
else {
TSK_DEBUG_ERROR("tdav_apple_enable_audio() failed with status=%ld", (signed long)status);
}
inst->started = (status == noErr) ? tsk_true : tsk_false;
if (inst->started) {
inst->interrupted = 0;
}
}
else {
TSK_DEBUG_ERROR("tdav_apple_enable_audio() failed with status=%ld", (signed long)status);
}
inst->started = (status == noErr) ? tsk_true : tsk_false;
if (inst->started) {
inst->interrupted = 0;
TSK_DEBUG_INFO("AudioUnit producer(%d) or consumer(%d) not ready yet ...delaying start", (int)inst->ready.producer, (int)inst->ready.consumer);
}
tsk_safeobj_unlock(inst);
return status ? -2 : 0;
@ -223,7 +228,7 @@ int tdav_audiounit_handle_start(tdav_audiounit_handle_t* self)
uint32_t tdav_audiounit_handle_get_frame_duration(tdav_audiounit_handle_t* self)
{
if(self) {
if (self) {
return ((tdav_audiounit_instance_t*)self)->frame_duration;
}
return 0;
@ -349,28 +354,30 @@ int tdav_audiounit_handle_stop(tdav_audiounit_handle_t* self)
{
tdav_audiounit_instance_t* inst = (tdav_audiounit_instance_t*)self;
OSStatus status = noErr;
if(!inst || (inst->started && !inst->audioUnit)) {
if (!inst || (inst->started && !inst->audioUnit)) {
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
tsk_safeobj_lock(inst);
if(inst->started && (status = AudioOutputUnitStop(inst->audioUnit))) {
if (inst->started && (status = AudioOutputUnitStop(inst->audioUnit))) {
TSK_DEBUG_ERROR("AudioOutputUnitStop failed with status=%ld", (signed long)status);
}
inst->started = (status == noErr ? tsk_false : tsk_true);
inst->ready.consumer = tsk_false;
inst->ready.producer = tsk_false;
tsk_safeobj_unlock(inst);
return (status != noErr) ? -2 : 0;
}
int tdav_audiounit_handle_destroy(tdav_audiounit_handle_t** self)
{
if(!self || !*self) {
if (!self || !*self) {
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
tsk_list_lock(__audioUnitInstances);
if(tsk_object_get_refcount(*self)==1) {
if (tsk_object_get_refcount(*self)==1) {
tsk_list_remove_item_by_data(__audioUnitInstances, *self);
}
else {

View File

@ -39,6 +39,8 @@
static tsk_size_t tdav_consumer_audiounit_get(tdav_consumer_audiounit_t* self, void* data, tsk_size_t size);
static int tdav_consumer_audiounit_pause(tmedia_consumer_t* self);
static int tdav_consumer_audiounit_resume(tmedia_consumer_t* self);
static int tdav_consumer_audiounit_init(tmedia_consumer_t* self);
static int tdav_consumer_audiounit_deinit(tmedia_consumer_t* self);
static OSStatus __handle_output_buffer(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
@ -122,167 +124,23 @@ int tdav_consumer_audiounit_set(tmedia_consumer_t* self, const tmedia_param_t* p
static int tdav_consumer_audiounit_prepare(tmedia_consumer_t* self, const tmedia_codec_t* codec)
{
static UInt32 flagOne = 1;
AudioStreamBasicDescription audioFormat;
#define kOutputBus 0
tdav_consumer_audiounit_t* consumer = (tdav_consumer_audiounit_t*)self;
OSStatus status = noErr;
if(!consumer || !codec || !codec->plugin) {
if (!consumer || !codec || !codec->plugin) {
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
if(!consumer->audioUnitHandle) {
if(!(consumer->audioUnitHandle = tdav_audiounit_handle_create(TMEDIA_CONSUMER(consumer)->session_id))) {
TSK_DEBUG_ERROR("Failed to get audio unit instance for session with id=%lld", TMEDIA_CONSUMER(consumer)->session_id);
return -3;
}
}
// enable
status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(consumer->audioUnitHandle),
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Output,
kOutputBus,
&flagOne,
sizeof(flagOne));
if(status) {
TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioOutputUnitProperty_EnableIO) failed with status=%d", (int32_t)status);
return -4;
}
else {
#if !TARGET_OS_IPHONE // strange: TARGET_OS_MAC is equal to '1' on Smulator
UInt32 param;
// disable input
param = 0;
status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(consumer->audioUnitHandle), kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &param, sizeof(UInt32));
if(status != noErr) {
TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioOutputUnitProperty_EnableIO) failed with status=%ld", (signed long)status);
return -4;
}
// set default audio device
param = sizeof(AudioDeviceID);
AudioDeviceID outputDeviceID;
status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &param, &outputDeviceID);
if(status != noErr) {
TSK_DEBUG_ERROR("AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice) failed with status=%ld", (signed long)status);
return -4;
}
// set the current device to the default input unit
status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(consumer->audioUnitHandle),
kAudioOutputUnitProperty_CurrentDevice,
kAudioUnitScope_Global,
0,
&outputDeviceID,
sizeof(AudioDeviceID));
if(status != noErr) {
TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioOutputUnitProperty_CurrentDevice) failed with status=%ld", (signed long)status);
return -4;
}
#endif
TMEDIA_CONSUMER(consumer)->audio.ptime = TMEDIA_CODEC_PTIME_AUDIO_DECODING(codec);
TMEDIA_CONSUMER(consumer)->audio.in.channels = TMEDIA_CODEC_CHANNELS_AUDIO_DECODING(codec);
TMEDIA_CONSUMER(consumer)->audio.in.rate = TMEDIA_CODEC_RATE_DECODING(codec);
TSK_DEBUG_INFO("AudioUnit consumer: in.channels=%d, out.channles=%d, in.rate=%d, out.rate=%d, ptime=%d",
TMEDIA_CONSUMER(consumer)->audio.in.channels,
TMEDIA_CONSUMER(consumer)->audio.out.channels,
TMEDIA_CONSUMER(consumer)->audio.in.rate,
TMEDIA_CONSUMER(consumer)->audio.out.rate,
TMEDIA_CONSUMER(consumer)->audio.ptime);
audioFormat.mSampleRate = TMEDIA_CONSUMER(consumer)->audio.out.rate ? TMEDIA_CONSUMER(consumer)->audio.out.rate : TMEDIA_CONSUMER(consumer)->audio.in.rate;
audioFormat.mFormatID = kAudioFormatLinearPCM;
audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
audioFormat.mChannelsPerFrame = TMEDIA_CONSUMER(consumer)->audio.in.channels;
audioFormat.mFramesPerPacket = 1;
audioFormat.mBitsPerChannel = TMEDIA_CONSUMER(consumer)->audio.bits_per_sample;
audioFormat.mBytesPerPacket = audioFormat.mBitsPerChannel / 8 * audioFormat.mChannelsPerFrame;
audioFormat.mBytesPerFrame = audioFormat.mBytesPerPacket;
audioFormat.mReserved = 0;
status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(consumer->audioUnitHandle),
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
kOutputBus,
&audioFormat,
sizeof(audioFormat));
if(status) {
TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioUnitProperty_StreamFormat) failed with status=%ld", (signed long)status);
return -5;
}
else {
// configure
if(tdav_audiounit_handle_configure(consumer->audioUnitHandle, tsk_true, TMEDIA_CONSUMER(consumer)->audio.ptime, &audioFormat)) {
TSK_DEBUG_ERROR("tdav_audiounit_handle_set_rate(%d) failed", TMEDIA_CONSUMER(consumer)->audio.out.rate);
return -4;
}
// set callback function
AURenderCallbackStruct callback;
callback.inputProc = __handle_output_buffer;
callback.inputProcRefCon = consumer;
status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(consumer->audioUnitHandle),
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input,
kOutputBus,
&callback,
sizeof(callback));
if(status) {
TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioOutputUnitProperty_SetInputCallback) failed with status=%ld", (signed long)status);
return -6;
}
}
}
// allocate the chunck buffer and create the ring
consumer->ring.chunck.size = (TMEDIA_CONSUMER(consumer)->audio.ptime * audioFormat.mSampleRate * audioFormat.mBytesPerFrame) / 1000;
consumer->ring.size = kRingPacketCount * consumer->ring.chunck.size;
if(!(consumer->ring.chunck.buffer = tsk_realloc(consumer->ring.chunck.buffer, consumer->ring.chunck.size))) {
TSK_DEBUG_ERROR("Failed to allocate new buffer");
return -7;
}
if(!consumer->ring.buffer) {
consumer->ring.buffer = speex_buffer_init((int)consumer->ring.size);
}
else {
int ret;
if((ret = (int)speex_buffer_resize(consumer->ring.buffer, (int)consumer->ring.size)) < 0) {
TSK_DEBUG_ERROR("speex_buffer_resize(%d) failed with error code=%d", (int)consumer->ring.size, ret);
return ret;
}
}
if(!consumer->ring.buffer) {
TSK_DEBUG_ERROR("Failed to create a new ring buffer with size = %d", (int)consumer->ring.size);
return -8;
}
if(!consumer->ring.mutex && !(consumer->ring.mutex = tsk_mutex_create_2(tsk_false))) {
TSK_DEBUG_ERROR("Failed to create mutex");
return -9;
}
// set maximum frames per slice as buffer size
//UInt32 numFrames = (UInt32)consumer->ring.chunck.size;
//status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(consumer->audioUnitHandle),
// kAudioUnitProperty_MaximumFramesPerSlice,
// kAudioUnitScope_Global,
// 0,
// &numFrames,
// sizeof(numFrames));
//if(status){
// TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioUnitProperty_MaximumFramesPerSlice, %u) failed with status=%d", (unsigned)numFrames, (int32_t)status);
// return -6;
//}
TSK_DEBUG_INFO("AudioUnit consumer prepared");
return tdav_audiounit_handle_signal_consumer_prepared(consumer->audioUnitHandle);
// Initialize the decoder parameters without allocating AudioUnit resourses
TMEDIA_CONSUMER(consumer)->audio.ptime = TMEDIA_CODEC_PTIME_AUDIO_DECODING(codec);
TMEDIA_CONSUMER(consumer)->audio.in.channels = TMEDIA_CODEC_CHANNELS_AUDIO_DECODING(codec);
TMEDIA_CONSUMER(consumer)->audio.in.rate = TMEDIA_CODEC_RATE_DECODING(codec);
TSK_DEBUG_INFO("AudioUnit consumer prepared (ptime=%d, channels=%d, rate=%d)",
(int)TMEDIA_CONSUMER(consumer)->audio.ptime,
(int)TMEDIA_CONSUMER(consumer)->audio.in.channels,
(int)TMEDIA_CONSUMER(consumer)->audio.in.rate);
return 0;
}
static int tdav_consumer_audiounit_start(tmedia_consumer_t* self)
@ -293,16 +151,28 @@ static int tdav_consumer_audiounit_start(tmedia_consumer_t* self)
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
if(consumer->paused) {
if (consumer->paused) {
consumer->paused = tsk_false;
}
if(consumer->started) {
if (consumer->started) {
TSK_DEBUG_WARN("Already started");
return 0;
}
else {
int ret = tdav_audiounit_handle_start(consumer->audioUnitHandle);
if(ret) {
int ret;
// Initialize the consumer if not already done
if (!consumer->ready) {
ret = tdav_consumer_audiounit_init(self);
if (ret) {
tdav_consumer_audiounit_deinit(self);
TSK_DEBUG_ERROR("tdav_consumer_audiounit_init failed with error code=%d", ret);
return ret;
}
}
// Start the handle (will wait until producer is ready)
ret = tdav_audiounit_handle_start(consumer->audioUnitHandle);
if (ret) {
tdav_consumer_audiounit_deinit(self);
TSK_DEBUG_ERROR("tdav_audiounit_handle_start failed with error code=%d", ret);
return ret;
}
@ -344,14 +214,8 @@ static int tdav_consumer_audiounit_pause(tmedia_consumer_t* self)
return -1;
}
if (!consumer->paused) {
tdav_consumer_audiounit_deinit(self);
consumer->paused = tsk_true;
if (consumer->started) {
int ret = tdav_audiounit_handle_stop(consumer->audioUnitHandle);
if(ret) {
TSK_DEBUG_ERROR("tdav_audiounit_handle_stop failed with error code=%d", ret);
}
consumer->started = false;
}
}
TSK_DEBUG_INFO("AudioUnit consumer paused");
@ -366,13 +230,13 @@ static int tdav_consumer_audiounit_resume(tmedia_consumer_t* self)
return -1;
}
if (consumer->paused) {
consumer->paused = tsk_false;
consumer->paused = tsk_false; // *must* be before start()
if (!consumer->started) {
int ret = tdav_audiounit_handle_start(consumer->audioUnitHandle);
if(ret) {
TSK_DEBUG_ERROR("tdav_audiounit_handle_start failed with error code=%d", ret);
int ret = tdav_consumer_audiounit_start(self);
if (ret) {
TSK_DEBUG_ERROR("Failed to stop the consumer");
return ret;
}
consumer->started = true;
}
}
@ -382,34 +246,218 @@ static int tdav_consumer_audiounit_resume(tmedia_consumer_t* self)
static int tdav_consumer_audiounit_stop(tmedia_consumer_t* self)
{
tdav_consumer_audiounit_t* consumer = (tdav_consumer_audiounit_t*)self;
int ret = tdav_consumer_audiounit_deinit(self);
if (ret) {
TSK_DEBUG_ERROR("Failed to stop the consumer");
return ret;
}
TSK_DEBUG_INFO("AudioUnit consumer stoppped");
return 0;
}
static int tdav_consumer_audiounit_init(tmedia_consumer_t* self)
{
static UInt32 flagOne = 1;
AudioStreamBasicDescription audioFormat;
#define kOutputBus 0
tdav_consumer_audiounit_t* consumer = (tdav_consumer_audiounit_t*)self;
OSStatus status = noErr;
if (!consumer) {
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
if (consumer->ready) {
TSK_DEBUG_INFO("AudioUnit consumer already initialized");
return 0;
}
// create handle if not already done
if (!consumer->audioUnitHandle) {
if(!(consumer->audioUnitHandle = tdav_audiounit_handle_create(TMEDIA_CONSUMER(consumer)->session_id))) {
TSK_DEBUG_ERROR("Failed to get audio unit instance for session with id=%lld", TMEDIA_CONSUMER(consumer)->session_id);
return -2;
}
}
// enable
status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(consumer->audioUnitHandle),
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Output,
kOutputBus,
&flagOne,
sizeof(flagOne));
if(status) {
TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioOutputUnitProperty_EnableIO) failed with status=%d", (int32_t)status);
return -4;
}
else {
#if !TARGET_OS_IPHONE // strange: TARGET_OS_MAC is equal to '1' on Smulator
UInt32 param;
// disable input
param = 0;
status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(consumer->audioUnitHandle), kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &param, sizeof(UInt32));
if(status != noErr) {
TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioOutputUnitProperty_EnableIO) failed with status=%ld", (signed long)status);
return -4;
}
// set default audio device
param = sizeof(AudioDeviceID);
AudioDeviceID outputDeviceID;
status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &param, &outputDeviceID);
if(status != noErr) {
TSK_DEBUG_ERROR("AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice) failed with status=%ld", (signed long)status);
return -4;
}
// set the current device to the default input unit
status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(consumer->audioUnitHandle),
kAudioOutputUnitProperty_CurrentDevice,
kAudioUnitScope_Global,
0,
&outputDeviceID,
sizeof(AudioDeviceID));
if(status != noErr) {
TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioOutputUnitProperty_CurrentDevice) failed with status=%ld", (signed long)status);
return -4;
}
#endif
TSK_DEBUG_INFO("AudioUnit consumer: in.channels=%d, out.channles=%d, in.rate=%d, out.rate=%d, ptime=%d",
TMEDIA_CONSUMER(consumer)->audio.in.channels,
TMEDIA_CONSUMER(consumer)->audio.out.channels,
TMEDIA_CONSUMER(consumer)->audio.in.rate,
TMEDIA_CONSUMER(consumer)->audio.out.rate,
TMEDIA_CONSUMER(consumer)->audio.ptime);
audioFormat.mSampleRate = TMEDIA_CONSUMER(consumer)->audio.out.rate ? TMEDIA_CONSUMER(consumer)->audio.out.rate : TMEDIA_CONSUMER(consumer)->audio.in.rate;
audioFormat.mFormatID = kAudioFormatLinearPCM;
audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
audioFormat.mChannelsPerFrame = TMEDIA_CONSUMER(consumer)->audio.in.channels;
audioFormat.mFramesPerPacket = 1;
audioFormat.mBitsPerChannel = TMEDIA_CONSUMER(consumer)->audio.bits_per_sample;
audioFormat.mBytesPerPacket = audioFormat.mBitsPerChannel / 8 * audioFormat.mChannelsPerFrame;
audioFormat.mBytesPerFrame = audioFormat.mBytesPerPacket;
audioFormat.mReserved = 0;
status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(consumer->audioUnitHandle),
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
kOutputBus,
&audioFormat,
sizeof(audioFormat));
if(status) {
TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioUnitProperty_StreamFormat) failed with status=%ld", (signed long)status);
return -5;
}
else {
// configure
if(tdav_audiounit_handle_configure(consumer->audioUnitHandle, tsk_true, TMEDIA_CONSUMER(consumer)->audio.ptime, &audioFormat)) {
TSK_DEBUG_ERROR("tdav_audiounit_handle_set_rate(%d) failed", TMEDIA_CONSUMER(consumer)->audio.out.rate);
return -4;
}
// set callback function
AURenderCallbackStruct callback;
callback.inputProc = __handle_output_buffer;
callback.inputProcRefCon = consumer;
status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(consumer->audioUnitHandle),
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input,
kOutputBus,
&callback,
sizeof(callback));
if(status) {
TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioOutputUnitProperty_SetInputCallback) failed with status=%ld", (signed long)status);
return -6;
}
}
}
// allocate the chunck buffer and create the ring
consumer->ring.chunck.size = (TMEDIA_CONSUMER(consumer)->audio.ptime * audioFormat.mSampleRate * audioFormat.mBytesPerFrame) / 1000;
consumer->ring.size = kRingPacketCount * consumer->ring.chunck.size;
if(!(consumer->ring.chunck.buffer = tsk_realloc(consumer->ring.chunck.buffer, consumer->ring.chunck.size))) {
TSK_DEBUG_ERROR("Failed to allocate new buffer");
return -7;
}
if(!consumer->ring.buffer) {
consumer->ring.buffer = speex_buffer_init((int)consumer->ring.size);
}
else {
int ret;
if((ret = (int)speex_buffer_resize(consumer->ring.buffer, (int)consumer->ring.size)) < 0) {
TSK_DEBUG_ERROR("speex_buffer_resize(%d) failed with error code=%d", (int)consumer->ring.size, ret);
return ret;
}
}
if(!consumer->ring.buffer) {
TSK_DEBUG_ERROR("Failed to create a new ring buffer with size = %d", (int)consumer->ring.size);
return -8;
}
if(!consumer->ring.mutex && !(consumer->ring.mutex = tsk_mutex_create_2(tsk_false))) {
TSK_DEBUG_ERROR("Failed to create mutex");
return -9;
}
// set maximum frames per slice as buffer size
//UInt32 numFrames = (UInt32)consumer->ring.chunck.size;
//status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(consumer->audioUnitHandle),
// kAudioUnitProperty_MaximumFramesPerSlice,
// kAudioUnitScope_Global,
// 0,
// &numFrames,
// sizeof(numFrames));
//if(status){
// TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioUnitProperty_MaximumFramesPerSlice, %u) failed with status=%d", (unsigned)numFrames, (int32_t)status);
// return -6;
//}
if (tdav_audiounit_handle_signal_consumer_ready(consumer->audioUnitHandle)) {
TSK_DEBUG_ERROR("tdav_audiounit_handle_signal_consumer_ready failed");
return -10;
}
consumer->ready = tsk_true;
TSK_DEBUG_INFO("AudioUnit consumer initialized and ready");
return 0;
}
int tdav_consumer_audiounit_deinit(tmedia_consumer_t* self)
{
tdav_consumer_audiounit_t* consumer = (tdav_consumer_audiounit_t*)self;
if(!consumer) {
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
if(!consumer->started) {
TSK_DEBUG_INFO("Not started");
return 0;
}
else {
// Stop
if (consumer->started) {
int ret = tdav_audiounit_handle_stop(consumer->audioUnitHandle);
if(ret) {
if (ret) {
TSK_DEBUG_ERROR("tdav_audiounit_handle_stop failed with error code=%d", ret);
return ret;
}
consumer->started = tsk_false;
}
// Destroy handle (will be re-created by the next start)
#if TARGET_OS_IPHONE
//https://devforums.apple.com/thread/118595
if(consumer->audioUnitHandle) {
if (consumer->audioUnitHandle) {
tdav_audiounit_handle_destroy(&consumer->audioUnitHandle);
}
#endif
consumer->started = tsk_false;
TSK_DEBUG_INFO("AudioUnit consumer stoppped");
consumer->ready = tsk_false;
consumer->paused = tsk_false;
TSK_DEBUG_INFO("AudioUnit consumer deinitialized");
return 0;
}
//
@ -432,14 +480,7 @@ 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);
}
tdav_consumer_audiounit_deinit(TMEDIA_CONSUMER(self));
TSK_FREE(consumer->ring.chunck.buffer);
if(consumer->ring.buffer) {
speex_buffer_destroy(consumer->ring.buffer);

View File

@ -37,6 +37,8 @@
static int tdav_producer_audiounit_pause(tmedia_producer_t* self);
static int tdav_producer_audiounit_resume(tmedia_producer_t* self);
static int tdav_producer_audiounit_init(tmedia_producer_t* self);
static int tdav_producer_audiounit_deinit(tmedia_producer_t* self);
static OSStatus __handle_input_buffer(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
@ -104,28 +106,146 @@ int tdav_producer_audiounit_set(tmedia_producer_t* self, const tmedia_param_t* p
}
static int tdav_producer_audiounit_prepare(tmedia_producer_t* self, const tmedia_codec_t* codec)
{
tdav_producer_audiounit_t* producer = (tdav_producer_audiounit_t*)self;
if (!producer || !codec || !codec->plugin) {
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
TMEDIA_PRODUCER(producer)->audio.channels = TMEDIA_CODEC_CHANNELS_AUDIO_ENCODING(codec);
TMEDIA_PRODUCER(producer)->audio.rate = TMEDIA_CODEC_RATE_ENCODING(codec);
TMEDIA_PRODUCER(producer)->audio.ptime = TMEDIA_CODEC_PTIME_AUDIO_ENCODING(codec);
TSK_DEBUG_INFO("AudioUnit producer prepared(channels=%d, rate=%d, ptime=%d)",
(int)TMEDIA_PRODUCER(producer)->audio.channels,
(int)TMEDIA_PRODUCER(producer)->audio.rate,
(int)TMEDIA_PRODUCER(producer)->audio.ptime);
return 0;
}
static int tdav_producer_audiounit_start(tmedia_producer_t* self)
{
tdav_producer_audiounit_t* producer = (tdav_producer_audiounit_t*)self;
if (!producer) {
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
if (producer->paused) {
producer->paused = tsk_false;
return tsk_false;
}
int ret;
if (producer->started) {
TSK_DEBUG_WARN("Already started");
return 0;
}
else {
// Initialize the consumer if not already done
if (!producer->ready) {
ret = tdav_producer_audiounit_init(self);
if (ret) {
tdav_producer_audiounit_deinit(self);
TSK_DEBUG_ERROR("tdav_producer_audiounit_init failed with error code=%d", ret);
return ret;
}
}
// Start handle
ret = tdav_audiounit_handle_start(producer->audioUnitHandle);
if(ret) {
TSK_DEBUG_ERROR("tdav_audiounit_handle_start failed with error code=%d", ret);
return ret;
}
}
producer->started = tsk_true;
// apply parameters (because could be lost when the producer is restarted -handle recreated-)
ret = tdav_audiounit_handle_mute(producer->audioUnitHandle, producer->muted);
TSK_DEBUG_INFO("AudioUnit producer started");
return 0;
}
static int tdav_producer_audiounit_pause(tmedia_producer_t* self)
{
tdav_producer_audiounit_t* producer = (tdav_producer_audiounit_t*)self;
if (!producer) {
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
if (!producer->paused) {
tdav_producer_audiounit_deinit(self);
producer->paused = tsk_true;
}
TSK_DEBUG_INFO("AudioUnit producer paused");
return 0;
}
static int tdav_producer_audiounit_resume(tmedia_producer_t* self)
{
tdav_producer_audiounit_t* producer = (tdav_producer_audiounit_t*)self;
if (!producer) {
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
if (producer->paused) {
producer->paused = tsk_false; // *must* be before start()
if (!producer->started) {
int ret = tdav_producer_audiounit_start(self);
if (ret) {
TSK_DEBUG_ERROR("Failed to stop the consumer");
return ret;
}
}
}
TSK_DEBUG_INFO("AudioUnit producer resumed");
return 0;
}
static int tdav_producer_audiounit_stop(tmedia_producer_t* self)
{
int ret = tdav_producer_audiounit_deinit(self);
if (ret) {
TSK_DEBUG_ERROR("Failed to stop the consumer");
return ret;
}
TSK_DEBUG_INFO("AudioUnit producer stoppped");
return 0;
}
static int tdav_producer_audiounit_init(tmedia_producer_t* self)
{
static UInt32 flagOne = 1;
UInt32 param;
// static UInt32 flagZero = 0;
#define kInputBus 1
tdav_producer_audiounit_t* producer = (tdav_producer_audiounit_t*)self;
OSStatus status = noErr;
AudioStreamBasicDescription audioFormat;
AudioStreamBasicDescription deviceFormat;
if(!producer || !codec || !codec->plugin) {
if (!producer) {
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
if(!producer->audioUnitHandle) {
if (producer->ready) {
TSK_DEBUG_INFO("AudioUnit consumer already initialized");
return 0;
}
if (!producer->audioUnitHandle) {
if(!(producer->audioUnitHandle = tdav_audiounit_handle_create(TMEDIA_PRODUCER(producer)->session_id))) {
TSK_DEBUG_ERROR("Failed to get audio unit instance for session with id=%lld", TMEDIA_PRODUCER(producer)->session_id);
return -3;
}
}
// enable
status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(producer->audioUnitHandle),
kAudioOutputUnitProperty_EnableIO,
@ -133,7 +253,7 @@ static int tdav_producer_audiounit_prepare(tmedia_producer_t* self, const tmedia
kInputBus,
&flagOne,
sizeof(flagOne));
if(status != noErr) {
if (status != noErr) {
TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioOutputUnitProperty_EnableIO) failed with status=%ld", (signed long)status);
return -4;
}
@ -151,7 +271,7 @@ static int tdav_producer_audiounit_prepare(tmedia_producer_t* self, const tmedia
TSK_DEBUG_ERROR("AudioUnitSetProperty(kAudioOutputUnitProperty_EnableIO) failed with status=%ld", (signed long)status);
return -4;
}
// set default audio device
param = sizeof(AudioDeviceID);
AudioDeviceID inputDeviceID;
@ -160,7 +280,7 @@ static int tdav_producer_audiounit_prepare(tmedia_producer_t* self, const tmedia
TSK_DEBUG_ERROR("AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice) failed with status=%ld", (signed long)status);
return -4;
}
// set the current device to the default input unit
status = AudioUnitSetProperty(tdav_audiounit_handle_get_instance(producer->audioUnitHandle),
kAudioOutputUnitProperty_CurrentDevice,
@ -173,17 +293,12 @@ static int tdav_producer_audiounit_prepare(tmedia_producer_t* self, const tmedia
return -4;
}
#endif /* TARGET_OS_MAC */
/* codec should have ptime */
TMEDIA_PRODUCER(producer)->audio.channels = TMEDIA_CODEC_CHANNELS_AUDIO_ENCODING(codec);
TMEDIA_PRODUCER(producer)->audio.rate = TMEDIA_CODEC_RATE_ENCODING(codec);
TMEDIA_PRODUCER(producer)->audio.ptime = TMEDIA_CODEC_PTIME_AUDIO_ENCODING(codec);
TSK_DEBUG_INFO("AudioUnit producer: channels=%d, rate=%d, ptime=%d",
TMEDIA_PRODUCER(producer)->audio.channels,
TMEDIA_PRODUCER(producer)->audio.rate,
TMEDIA_PRODUCER(producer)->audio.ptime);
// get device format
param = sizeof(AudioStreamBasicDescription);
status = AudioUnitGetProperty(tdav_audiounit_handle_get_instance(producer->audioUnitHandle),
@ -199,7 +314,7 @@ static int tdav_producer_audiounit_prepare(tmedia_producer_t* self, const tmedia
TMEDIA_PRODUCER(producer)->audio.rate = deviceFormat.mSampleRate;
#endif
}
// set format
audioFormat.mSampleRate = TMEDIA_PRODUCER(producer)->audio.rate;
audioFormat.mFormatID = kAudioFormatLinearPCM;
@ -224,13 +339,13 @@ static int tdav_producer_audiounit_prepare(tmedia_producer_t* self, const tmedia
return -5;
}
else {
// configure
if(tdav_audiounit_handle_configure(producer->audioUnitHandle, tsk_false, TMEDIA_PRODUCER(producer)->audio.ptime, &audioFormat)) {
if (tdav_audiounit_handle_configure(producer->audioUnitHandle, tsk_false, TMEDIA_PRODUCER(producer)->audio.ptime, &audioFormat)) {
TSK_DEBUG_ERROR("tdav_audiounit_handle_set_rate(%d) failed", TMEDIA_PRODUCER(producer)->audio.rate);
return -4;
}
// set callback function
AURenderCallbackStruct callback;
callback.inputProc = __handle_input_buffer;
@ -253,7 +368,7 @@ static int tdav_producer_audiounit_prepare(tmedia_producer_t* self, const tmedia
// kInputBus,
// &flagZero,
// sizeof(flagZero));
producer->ring.chunck.size = (TMEDIA_PRODUCER(producer)->audio.ptime * audioFormat.mSampleRate * audioFormat.mBytesPerFrame) / 1000;
// allocate our chunck buffer
if(!(producer->ring.chunck.buffer = tsk_realloc(producer->ring.chunck.buffer, producer->ring.chunck.size))) {
@ -267,7 +382,7 @@ static int tdav_producer_audiounit_prepare(tmedia_producer_t* self, const tmedia
}
else {
int ret;
if((ret = speex_buffer_resize(producer->ring.buffer, producer->ring.size)) < 0) {
if((ret = speex_buffer_resize(producer->ring.buffer, (int)producer->ring.size)) < 0) {
TSK_DEBUG_ERROR("speex_buffer_resize(%d) failed with error code=%d", (int)producer->ring.size, ret);
return ret;
}
@ -277,119 +392,48 @@ static int tdav_producer_audiounit_prepare(tmedia_producer_t* self, const tmedia
return -9;
}
}
}
}
TSK_DEBUG_INFO("AudioUnit producer prepared");
return tdav_audiounit_handle_signal_producer_prepared(producer->audioUnitHandle);;
}
static int tdav_producer_audiounit_start(tmedia_producer_t* self)
{
tdav_producer_audiounit_t* producer = (tdav_producer_audiounit_t*)self;
if(!producer) {
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
if (tdav_audiounit_handle_signal_producer_ready(producer->audioUnitHandle)) {
TSK_DEBUG_ERROR("tdav_audiounit_handle_signal_producer_ready failed");
return -10;
}
if(producer->paused) {
producer->paused = tsk_false;
return tsk_false;
}
int ret;
if(producer->started) {
TSK_DEBUG_WARN("Already started");
return 0;
}
else {
ret = tdav_audiounit_handle_start(producer->audioUnitHandle);
if(ret) {
TSK_DEBUG_ERROR("tdav_audiounit_handle_start failed with error code=%d", ret);
return ret;
}
}
producer->started = tsk_true;
// apply parameters (because could be lost when the producer is restarted -handle recreated-)
ret = tdav_audiounit_handle_mute(producer->audioUnitHandle, producer->muted);
TSK_DEBUG_INFO("AudioUnit producer started");
producer->ready = tsk_true;
TSK_DEBUG_INFO("AudioUnit producer initialized");
return 0;
}
static int tdav_producer_audiounit_pause(tmedia_producer_t* self)
static int tdav_producer_audiounit_deinit(tmedia_producer_t* self)
{
tdav_producer_audiounit_t* producer = (tdav_producer_audiounit_t*)self;
if(!producer) {
if (!producer) {
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
if (!producer->paused) {
producer->paused = tsk_true;
if (producer->started) {
int ret = tdav_audiounit_handle_stop(producer->audioUnitHandle);
if(ret) {
TSK_DEBUG_ERROR("tdav_audiounit_handle_stop failed with error code=%d", ret);
// do not return even if failed => we MUST stop the thread!
}
producer->started = false;
}
}
TSK_DEBUG_INFO("AudioUnit producer paused");
return 0;
}
static int tdav_producer_audiounit_resume(tmedia_producer_t* self)
{
tdav_producer_audiounit_t* producer = (tdav_producer_audiounit_t*)self;
if(!producer) {
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
if (producer->paused) {
if (!producer->started) {
int ret = tdav_audiounit_handle_start(producer->audioUnitHandle);
if(ret) {
TSK_DEBUG_ERROR("tdav_audiounit_handle_start failed with error code=%d", ret);
// do not return even if failed => we MUST stop the thread!
}
}
producer->paused = false;
producer->started = true;
}
TSK_DEBUG_INFO("AudioUnit producer resumed");
return 0;
}
static int tdav_producer_audiounit_stop(tmedia_producer_t* self)
{
tdav_producer_audiounit_t* producer = (tdav_producer_audiounit_t*)self;
if(!producer) {
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
if(!producer->started) {
TSK_DEBUG_INFO("Not started");
return 0;
}
else {
// Stop
if (producer->started) {
int ret = tdav_audiounit_handle_stop(producer->audioUnitHandle);
if(ret) {
if (ret) {
TSK_DEBUG_ERROR("tdav_audiounit_handle_stop failed with error code=%d", ret);
// do not return even if failed => we MUST stop the thread!
}
#if TARGET_OS_IPHONE
//https://devforums.apple.com/thread/118595
if(producer->audioUnitHandle) {
tdav_audiounit_handle_destroy(&producer->audioUnitHandle);
}
#endif
producer->started = tsk_false;
}
producer->started = tsk_false;
TSK_DEBUG_INFO("AudioUnit producer stoppped");
// Destroy handle (will be re-created by the next start)
#if TARGET_OS_IPHONE
//https://devforums.apple.com/thread/118595
if (producer->audioUnitHandle) {
tdav_audiounit_handle_destroy(&producer->audioUnitHandle);
}
#endif
producer->ready = tsk_false;
producer->paused = tsk_false;
TSK_DEBUG_INFO("AudioUnit producer deinitialized");
return 0;
}
@ -413,15 +457,7 @@ static tsk_object_t* tdav_producer_audiounit_dtor(tsk_object_t * self)
{
tdav_producer_audiounit_t *producer = self;
if(producer) {
// Stop the producer if not done
if(producer->started) {
tdav_producer_audiounit_stop(self);
}
// Free all buffers and dispose the queue
if (producer->audioUnitHandle) {
tdav_audiounit_handle_destroy(&producer->audioUnitHandle);
}
tdav_producer_audiounit_deinit(TMEDIA_PRODUCER(self));
TSK_FREE(producer->ring.chunck.buffer);
if(producer->ring.buffer) {
speex_buffer_destroy(producer->ring.buffer);