Destroy audioUnit instance when call is put on hold to allow multiple audio sessions
This commit is contained in:
parent
a4973c7fe3
commit
6b9f5f831a
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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) {
|
||||
|
@ -86,17 +86,17 @@ static int _tdav_audiounit_handle_signal_xxx_prepared(tdav_audiounit_handle_t* s
|
|||
tsk_safeobj_lock(inst);
|
||||
|
||||
if (consumer) {
|
||||
inst->prepared.consumer = tsk_true;
|
||||
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,6 +204,7 @@ int tdav_audiounit_handle_start(tdav_audiounit_handle_t* self)
|
|||
}
|
||||
|
||||
tsk_safeobj_lock(inst);
|
||||
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))) {
|
||||
|
@ -217,6 +218,10 @@ int tdav_audiounit_handle_start(tdav_audiounit_handle_t* self)
|
|||
if (inst->started) {
|
||||
inst->interrupted = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
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;
|
||||
}
|
||||
|
@ -359,6 +364,8 @@ int tdav_audiounit_handle_stop(tdav_audiounit_handle_t* self)
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
@ -121,6 +123,139 @@ 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)
|
||||
{
|
||||
tdav_consumer_audiounit_t* consumer = (tdav_consumer_audiounit_t*)self;
|
||||
|
||||
if (!consumer || !codec || !codec->plugin) {
|
||||
TSK_DEBUG_ERROR("Invalid parameter");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
tdav_consumer_audiounit_t* consumer = (tdav_consumer_audiounit_t*)self;
|
||||
|
||||
if(!consumer) {
|
||||
TSK_DEBUG_ERROR("Invalid parameter");
|
||||
return -1;
|
||||
}
|
||||
if (consumer->paused) {
|
||||
consumer->paused = tsk_false;
|
||||
}
|
||||
if (consumer->started) {
|
||||
TSK_DEBUG_WARN("Already started");
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
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;
|
||||
}
|
||||
}
|
||||
consumer->started = tsk_true;
|
||||
TSK_DEBUG_INFO("AudioUnit consumer started");
|
||||
return 0;
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
static int tdav_consumer_audiounit_pause(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->paused) {
|
||||
tdav_consumer_audiounit_deinit(self);
|
||||
consumer->paused = tsk_true;
|
||||
}
|
||||
|
||||
TSK_DEBUG_INFO("AudioUnit consumer paused");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tdav_consumer_audiounit_resume(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->paused) {
|
||||
consumer->paused = tsk_false; // *must* be before start()
|
||||
if (!consumer->started) {
|
||||
int ret = tdav_consumer_audiounit_start(self);
|
||||
if (ret) {
|
||||
TSK_DEBUG_ERROR("Failed to stop the consumer");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TSK_DEBUG_INFO("AudioUnit consumer resumed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tdav_consumer_audiounit_stop(tmedia_consumer_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;
|
||||
|
@ -129,14 +264,21 @@ static int tdav_consumer_audiounit_prepare(tmedia_consumer_t* self, const tmedia
|
|||
tdav_consumer_audiounit_t* consumer = (tdav_consumer_audiounit_t*)self;
|
||||
OSStatus status = noErr;
|
||||
|
||||
if(!consumer || !codec || !codec->plugin) {
|
||||
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 -3;
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -187,10 +329,6 @@ static int tdav_consumer_audiounit_prepare(tmedia_consumer_t* self, const tmedia
|
|||
|
||||
#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,
|
||||
|
@ -281,135 +419,45 @@ static int tdav_consumer_audiounit_prepare(tmedia_consumer_t* self, const tmedia
|
|||
// return -6;
|
||||
//}
|
||||
|
||||
TSK_DEBUG_INFO("AudioUnit consumer prepared");
|
||||
return tdav_audiounit_handle_signal_consumer_prepared(consumer->audioUnitHandle);
|
||||
if (tdav_audiounit_handle_signal_consumer_ready(consumer->audioUnitHandle)) {
|
||||
TSK_DEBUG_ERROR("tdav_audiounit_handle_signal_consumer_ready failed");
|
||||
return -10;
|
||||
}
|
||||
|
||||
static int tdav_consumer_audiounit_start(tmedia_consumer_t* self)
|
||||
{
|
||||
tdav_consumer_audiounit_t* consumer = (tdav_consumer_audiounit_t*)self;
|
||||
consumer->ready = tsk_true;
|
||||
|
||||
if(!consumer) {
|
||||
TSK_DEBUG_ERROR("Invalid parameter");
|
||||
return -1;
|
||||
}
|
||||
if(consumer->paused) {
|
||||
consumer->paused = tsk_false;
|
||||
}
|
||||
if(consumer->started) {
|
||||
TSK_DEBUG_WARN("Already started");
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
int ret = tdav_audiounit_handle_start(consumer->audioUnitHandle);
|
||||
if(ret) {
|
||||
TSK_DEBUG_ERROR("tdav_audiounit_handle_start failed with error code=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
consumer->started = tsk_true;
|
||||
TSK_DEBUG_INFO("AudioUnit consumer started");
|
||||
TSK_DEBUG_INFO("AudioUnit consumer initialized and ready");
|
||||
return 0;
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
static int tdav_consumer_audiounit_pause(tmedia_consumer_t* self)
|
||||
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->paused) {
|
||||
consumer->paused = tsk_true;
|
||||
// Stop
|
||||
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");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tdav_consumer_audiounit_resume(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->paused) {
|
||||
consumer->paused = tsk_false;
|
||||
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);
|
||||
}
|
||||
consumer->started = true;
|
||||
}
|
||||
}
|
||||
|
||||
TSK_DEBUG_INFO("AudioUnit consumer resumed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tdav_consumer_audiounit_stop(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 {
|
||||
int ret = tdav_audiounit_handle_stop(consumer->audioUnitHandle);
|
||||
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) {
|
||||
tdav_audiounit_handle_destroy(&consumer->audioUnitHandle);
|
||||
}
|
||||
#endif
|
||||
consumer->ready = tsk_false;
|
||||
consumer->paused = tsk_false;
|
||||
|
||||
TSK_DEBUG_INFO("AudioUnit consumer deinitialized");
|
||||
|
||||
consumer->started = tsk_false;
|
||||
TSK_DEBUG_INFO("AudioUnit consumer stoppped");
|
||||
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);
|
||||
|
|
|
@ -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,6 +106,118 @@ 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;
|
||||
|
@ -115,10 +229,16 @@ static int tdav_producer_audiounit_prepare(tmedia_producer_t* self, const tmedia
|
|||
AudioStreamBasicDescription audioFormat;
|
||||
AudioStreamBasicDescription deviceFormat;
|
||||
|
||||
if(!producer || !codec || !codec->plugin) {
|
||||
if (!producer) {
|
||||
TSK_DEBUG_ERROR("Invalid parameter");
|
||||
return -1;
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -174,11 +294,6 @@ static int tdav_producer_audiounit_prepare(tmedia_producer_t* self, const tmedia
|
|||
}
|
||||
#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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -281,115 +396,44 @@ static int tdav_producer_audiounit_prepare(tmedia_producer_t* self, const tmedia
|
|||
}
|
||||
}
|
||||
|
||||
TSK_DEBUG_INFO("AudioUnit producer prepared");
|
||||
return tdav_audiounit_handle_signal_producer_prepared(producer->audioUnitHandle);;
|
||||
if (tdav_audiounit_handle_signal_producer_ready(producer->audioUnitHandle)) {
|
||||
TSK_DEBUG_ERROR("tdav_audiounit_handle_signal_producer_ready failed");
|
||||
return -10;
|
||||
}
|
||||
|
||||
static int tdav_producer_audiounit_start(tmedia_producer_t* self)
|
||||
{
|
||||
tdav_producer_audiounit_t* producer = (tdav_producer_audiounit_t*)self;
|
||||
producer->ready = tsk_true;
|
||||
|
||||
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 {
|
||||
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");
|
||||
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) {
|
||||
TSK_DEBUG_ERROR("Invalid parameter");
|
||||
return -1;
|
||||
}
|
||||
if (!producer->paused) {
|
||||
producer->paused = tsk_true;
|
||||
// Stop
|
||||
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 {
|
||||
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 = tsk_false;
|
||||
}
|
||||
// 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->started = tsk_false;
|
||||
TSK_DEBUG_INFO("AudioUnit producer stoppped");
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue