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) {
|
||||
|
@ -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 {
|
||||
|
|
|
@ -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, ¶m, 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, ¶m, &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, ¶m, 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, ¶m, &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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue