Files
ANSCORE/MediaClient/media/audio_capture_avf.mm

1092 lines
28 KiB
Plaintext
Raw Permalink Normal View History

2026-03-28 16:54:11 +11:00
/***************************************************************************************
*
* IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
*
* By downloading, copying, installing or using the software you agree to this license.
* If you do not agree to this license, do not download, install,
* copy or use the software.
*
* Copyright (C) 2014-2024, Happytimesoft Corporation, all rights reserved.
*
* Redistribution and use in binary forms, with or without modification, are permitted.
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*
****************************************************************************************/
#include "sys_inc.h"
#include "audio_capture_avf.h"
#include <CoreAudio/CoreAudio.h>
#include <AudioToolbox/AudioToolbox.h>
#include <AudioUnit/AudioUnit.h>
/***************************************************************************************/
typedef struct
{
BOOL capture_flag;
pthread_t capture_thread;
AudioQueueRef audio_queue;
int num_audio_buffers;
AudioQueueBufferRef * audio_buffer;
void * buffer;
uint32 buffer_offset;
uint32 buffer_size;
AudioStreamBasicDescription strdesc;
AudioDeviceID device_id;
int device_index;
int samplerate;
uint16 channels;
uint16 samples;
int samplefmt;
avf_audio_callback callback;
void * userdata;
void * mutex_cb;
} AVFAudioContext;
static const AudioObjectPropertyAddress devlist_address =
{
kAudioHardwarePropertyDevices,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMain
};
/***************************************************************************************/
int avf_audio_device_nums()
{
int count = 0;
OSStatus result = noErr;
uint32 size = 0;
AudioDeviceID *devs = NULL;
uint32 i = 0;
uint32 max = 0;
result = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject,
&devlist_address, 0, NULL, &size);
if (result != kAudioHardwareNoError)
{
return 0;
}
devs = (AudioDeviceID *) alloca(size);
if (devs == NULL)
{
return 0;
}
result = AudioObjectGetPropertyData(kAudioObjectSystemObject,
&devlist_address, 0, NULL, &size, devs);
if (result != kAudioHardwareNoError)
{
return 0;
}
max = size / sizeof (AudioDeviceID);
for (i = 0; i < max; i++)
{
CFStringRef cfstr = NULL;
char *ptr = NULL;
AudioDeviceID dev = devs[i];
AudioBufferList *buflist = NULL;
int usable = 0;
CFIndex len = 0;
const AudioObjectPropertyAddress addr = {
kAudioDevicePropertyStreamConfiguration,
kAudioDevicePropertyScopeInput,
kAudioObjectPropertyElementMain
};
const AudioObjectPropertyAddress nameaddr = {
kAudioObjectPropertyName,
kAudioDevicePropertyScopeInput,
kAudioObjectPropertyElementMain
};
result = AudioObjectGetPropertyDataSize(dev, &addr, 0, NULL, &size);
if (result != noErr)
{
continue;
}
buflist = (AudioBufferList *) malloc(size);
if (buflist == NULL)
{
continue;
}
result = AudioObjectGetPropertyData(dev, &addr, 0, NULL, &size, buflist);
if (result == noErr)
{
uint32 j;
for (j = 0; j < buflist->mNumberBuffers; j++)
{
if (buflist->mBuffers[j].mNumberChannels > 0)
{
usable = 1;
break;
}
}
}
free(buflist);
if (!usable)
{
continue;
}
size = sizeof (CFStringRef);
result = AudioObjectGetPropertyData(dev, &nameaddr, 0, NULL, &size, &cfstr);
if (result != kAudioHardwareNoError)
{
continue;
}
len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfstr),
kCFStringEncodingUTF8);
ptr = (char *) malloc(len + 1);
usable = ((ptr != NULL) &&
(CFStringGetCString
(cfstr, ptr, len + 1, kCFStringEncodingUTF8)));
CFRelease(cfstr);
if (usable)
{
len = strlen(ptr);
/* Some devices have whitespace at the end...trim it. */
while ((len > 0) && (ptr[len - 1] == ' '))
{
len--;
}
usable = (len > 0);
}
if (usable)
{
count++;
}
free(ptr);
}
return count;
}
void avf_audio_device_list()
{
int count = 0;
OSStatus result = noErr;
uint32 size = 0;
AudioDeviceID *devs = NULL;
uint32 i = 0;
uint32 max = 0;
result = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject,
&devlist_address, 0, NULL, &size);
if (result != kAudioHardwareNoError)
{
return;
}
devs = (AudioDeviceID *) alloca(size);
if (devs == NULL)
{
return;
}
result = AudioObjectGetPropertyData(kAudioObjectSystemObject,
&devlist_address, 0, NULL, &size, devs);
if (result != kAudioHardwareNoError)
{
return;
}
printf("\r\nAvailable audio capture device : \r\n\r\n");
max = size / sizeof (AudioDeviceID);
for (i = 0; i < max; i++)
{
CFStringRef cfstr = NULL;
char *ptr = NULL;
AudioDeviceID dev = devs[i];
AudioBufferList *buflist = NULL;
int usable = 0;
CFIndex len = 0;
const AudioObjectPropertyAddress addr = {
kAudioDevicePropertyStreamConfiguration,
kAudioDevicePropertyScopeInput,
kAudioObjectPropertyElementMain
};
const AudioObjectPropertyAddress nameaddr = {
kAudioObjectPropertyName,
kAudioDevicePropertyScopeInput,
kAudioObjectPropertyElementMain
};
result = AudioObjectGetPropertyDataSize(dev, &addr, 0, NULL, &size);
if (result != noErr)
{
continue;
}
buflist = (AudioBufferList *) malloc(size);
if (buflist == NULL)
{
continue;
}
result = AudioObjectGetPropertyData(dev, &addr, 0, NULL, &size, buflist);
if (result == noErr)
{
uint32 j;
for (j = 0; j < buflist->mNumberBuffers; j++)
{
if (buflist->mBuffers[j].mNumberChannels > 0)
{
usable = 1;
break;
}
}
}
free(buflist);
if (!usable)
{
continue;
}
size = sizeof (CFStringRef);
result = AudioObjectGetPropertyData(dev, &nameaddr, 0, NULL, &size, &cfstr);
if (result != kAudioHardwareNoError)
{
continue;
}
len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfstr),
kCFStringEncodingUTF8);
ptr = (char *) malloc(len + 1);
usable = ((ptr != NULL) &&
(CFStringGetCString
(cfstr, ptr, len + 1, kCFStringEncodingUTF8)));
CFRelease(cfstr);
if (usable)
{
len = strlen(ptr);
/* Some devices have whitespace at the end...trim it. */
while ((len > 0) && (ptr[len - 1] == ' '))
{
len--;
}
usable = (len > 0);
}
if (usable)
{
ptr[len] = '\0';
printf("index : %d, name : %s\r\n", count++, ptr);
}
free(ptr);
}
}
int avf_audio_device_get_index(const char * name)
{
int count = 0;
OSStatus result = noErr;
uint32 size = 0;
AudioDeviceID *devs = NULL;
uint32 i = 0;
uint32 max = 0;
result = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject,
&devlist_address, 0, NULL, &size);
if (result != kAudioHardwareNoError)
{
return 0;
}
devs = (AudioDeviceID *) alloca(size);
if (devs == NULL)
{
return 0;
}
result = AudioObjectGetPropertyData(kAudioObjectSystemObject,
&devlist_address, 0, NULL, &size, devs);
if (result != kAudioHardwareNoError)
{
return 0;
}
max = size / sizeof (AudioDeviceID);
for (i = 0; i < max; i++)
{
CFStringRef cfstr = NULL;
char *ptr = NULL;
AudioDeviceID dev = devs[i];
AudioBufferList *buflist = NULL;
int usable = 0;
CFIndex len = 0;
const AudioObjectPropertyAddress addr = {
kAudioDevicePropertyStreamConfiguration,
kAudioDevicePropertyScopeInput,
kAudioObjectPropertyElementMain
};
const AudioObjectPropertyAddress nameaddr = {
kAudioObjectPropertyName,
kAudioDevicePropertyScopeInput,
kAudioObjectPropertyElementMain
};
result = AudioObjectGetPropertyDataSize(dev, &addr, 0, NULL, &size);
if (result != noErr)
{
continue;
}
buflist = (AudioBufferList *) malloc(size);
if (buflist == NULL)
{
continue;
}
result = AudioObjectGetPropertyData(dev, &addr, 0, NULL, &size, buflist);
if (result == noErr)
{
uint32 j;
for (j = 0; j < buflist->mNumberBuffers; j++)
{
if (buflist->mBuffers[j].mNumberChannels > 0)
{
usable = 1;
break;
}
}
}
free(buflist);
if (!usable)
{
continue;
}
size = sizeof (CFStringRef);
result = AudioObjectGetPropertyData(dev, &nameaddr, 0, NULL, &size, &cfstr);
if (result != kAudioHardwareNoError)
{
continue;
}
len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfstr),
kCFStringEncodingUTF8);
ptr = (char *) malloc(len + 1);
usable = ((ptr != NULL) &&
(CFStringGetCString
(cfstr, ptr, len + 1, kCFStringEncodingUTF8)));
CFRelease(cfstr);
if (usable)
{
len = strlen(ptr);
/* Some devices have whitespace at the end...trim it. */
while ((len > 0) && (ptr[len - 1] == ' '))
{
len--;
}
usable = (len > 0);
}
if (usable)
{
ptr[len] = '\0';
if (strcasecmp(ptr, name) == 0)
{
free(ptr);
break;
}
count++;
}
free(ptr);
}
return count;
}
BOOL avf_audio_device_get_name(int index, char * name, int namesize)
{
BOOL ret = FALSE;
OSStatus result = noErr;
uint32 size = 0;
AudioDeviceID *devs = NULL;
uint32 max = 0;
result = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject,
&devlist_address, 0, NULL, &size);
if (result != kAudioHardwareNoError)
{
return FALSE;
}
devs = (AudioDeviceID *) alloca(size);
if (devs == NULL)
{
return FALSE;
}
result = AudioObjectGetPropertyData(kAudioObjectSystemObject,
&devlist_address, 0, NULL, &size, devs);
if (result != kAudioHardwareNoError)
{
return FALSE;
}
max = size / sizeof (AudioDeviceID);
if (index < 0 || index >= max)
{
return FALSE;
}
{
CFStringRef cfstr = NULL;
char *ptr = NULL;
AudioDeviceID dev = devs[index];
AudioBufferList *buflist = NULL;
int usable = 0;
CFIndex len = 0;
const AudioObjectPropertyAddress addr = {
kAudioDevicePropertyStreamConfiguration,
kAudioDevicePropertyScopeInput,
kAudioObjectPropertyElementMain
};
const AudioObjectPropertyAddress nameaddr = {
kAudioObjectPropertyName,
kAudioDevicePropertyScopeInput,
kAudioObjectPropertyElementMain
};
result = AudioObjectGetPropertyDataSize(dev, &addr, 0, NULL, &size);
if (result != noErr)
{
return FALSE;
}
buflist = (AudioBufferList *) malloc(size);
if (buflist == NULL)
{
return FALSE;
}
result = AudioObjectGetPropertyData(dev, &addr, 0, NULL, &size, buflist);
if (result == noErr)
{
uint32 j;
for (j = 0; j < buflist->mNumberBuffers; j++)
{
if (buflist->mBuffers[j].mNumberChannels > 0)
{
usable = 1;
break;
}
}
}
free(buflist);
if (!usable)
{
return FALSE;
}
size = sizeof (CFStringRef);
result = AudioObjectGetPropertyData(dev, &nameaddr, 0, NULL, &size, &cfstr);
if (result != kAudioHardwareNoError)
{
return FALSE;
}
len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfstr),
kCFStringEncodingUTF8);
ptr = (char *) malloc(len + 1);
usable = ((ptr != NULL) &&
(CFStringGetCString
(cfstr, ptr, len + 1, kCFStringEncodingUTF8)));
CFRelease(cfstr);
if (usable)
{
len = strlen(ptr);
/* Some devices have whitespace at the end...trim it. */
while ((len > 0) && (ptr[len - 1] == ' '))
{
len--;
}
usable = (len > 0);
}
if (usable)
{
ptr[len] = '\0';
ret = TRUE;
strncpy(name, ptr, namesize);
}
free(ptr);
}
return ret;
}
AudioDeviceID avf_audio_get_deviceid(int index)
{
int count = 0;
OSStatus result = noErr;
uint32 size = 0;
AudioDeviceID *devs = NULL;
uint32 i = 0;
uint32 max = 0;
result = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject,
&devlist_address, 0, NULL, &size);
if (result != kAudioHardwareNoError)
{
return 0;
}
devs = (AudioDeviceID *) alloca(size);
if (devs == NULL)
{
return 0;
}
result = AudioObjectGetPropertyData(kAudioObjectSystemObject,
&devlist_address, 0, NULL, &size, devs);
if (result != kAudioHardwareNoError)
{
return 0;
}
max = size / sizeof (AudioDeviceID);
for (i = 0; i < max; i++)
{
CFStringRef cfstr = NULL;
char *ptr = NULL;
AudioDeviceID dev = devs[i];
AudioBufferList *buflist = NULL;
int usable = 0;
CFIndex len = 0;
const AudioObjectPropertyAddress addr = {
kAudioDevicePropertyStreamConfiguration,
kAudioDevicePropertyScopeInput,
kAudioObjectPropertyElementMain
};
const AudioObjectPropertyAddress nameaddr = {
kAudioObjectPropertyName,
kAudioDevicePropertyScopeInput,
kAudioObjectPropertyElementMain
};
result = AudioObjectGetPropertyDataSize(dev, &addr, 0, NULL, &size);
if (result != noErr)
{
continue;
}
buflist = (AudioBufferList *) malloc(size);
if (buflist == NULL)
{
continue;
}
result = AudioObjectGetPropertyData(dev, &addr, 0, NULL, &size, buflist);
if (result == noErr)
{
uint32 j;
for (j = 0; j < buflist->mNumberBuffers; j++)
{
if (buflist->mBuffers[j].mNumberChannels > 0)
{
usable = 1;
break;
}
}
}
free(buflist);
if (!usable)
{
continue;
}
size = sizeof (CFStringRef);
result = AudioObjectGetPropertyData(dev, &nameaddr, 0, NULL, &size, &cfstr);
if (result != kAudioHardwareNoError)
{
continue;
}
len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(cfstr),
kCFStringEncodingUTF8);
ptr = (char *) malloc(len + 1);
usable = ((ptr != NULL) &&
(CFStringGetCString
(cfstr, ptr, len + 1, kCFStringEncodingUTF8)));
CFRelease(cfstr);
if (usable)
{
len = strlen(ptr);
/* Some devices have whitespace at the end...trim it. */
while ((len > 0) && (ptr[len - 1] == ' '))
{
len--;
}
usable = (len > 0);
}
if (usable)
{
ptr[len] = '\0';
if (count == index)
{
free(ptr);
return dev;
}
count++;
}
free(ptr);
}
return 0;
}
BOOL avf_audio_prepare_device(AVFAudioContext * context)
{
AudioDeviceID devid = (AudioDeviceID) avf_audio_get_deviceid(context->device_index);
OSStatus result = noErr;
uint32 size = 0;
uint32 alive = 0;
pid_t pid = 0;
AudioObjectPropertyAddress addr = {
0,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMain
};
addr.mSelector = kAudioDevicePropertyDeviceIsAlive;
addr.mScope = kAudioDevicePropertyScopeInput;
size = sizeof (alive);
result = AudioObjectGetPropertyData(devid, &addr, 0, NULL, &size, &alive);
if (result != noErr)
{
log_print(HT_LOG_ERR, "%s, AudioObjectGetPropertyData failed\r\n", __FUNCTION__);
return FALSE;
}
if (!alive)
{
log_print(HT_LOG_ERR, "%s, requested device exists, but isn't alive\r\n", __FUNCTION__);
return FALSE;
}
addr.mSelector = kAudioDevicePropertyHogMode;
size = sizeof (pid);
result = AudioObjectGetPropertyData(devid, &addr, 0, NULL, &size, &pid);
/* some devices don't support this property, so errors are fine here. */
if ((result == noErr) && (pid != -1))
{
log_print(HT_LOG_ERR, "%s, requested device is being hogged\r\n", __FUNCTION__);
return FALSE;
}
context->device_id = devid;
return TRUE;
}
int avf_audio_assign_device(AVFAudioContext * context)
{
const AudioObjectPropertyAddress prop = {
kAudioDevicePropertyDeviceUID,
kAudioDevicePropertyScopeInput,
kAudioObjectPropertyElementMain
};
OSStatus result;
CFStringRef devuid;
uint32 devuidsize = sizeof (devuid);
result = AudioObjectGetPropertyData(context->device_id, &prop, 0, NULL, &devuidsize, &devuid);
if (result != noErr)
{
log_print(HT_LOG_ERR, "%s, AudioObjectGetPropertyData failed\r\n", __FUNCTION__);
return 0;
}
result = AudioQueueSetProperty(context->audio_queue, kAudioQueueProperty_CurrentDevice, &devuid, devuidsize);
if (result != noErr)
{
log_print(HT_LOG_ERR, "%s, AudioQueueSetProperty failed\r\n", __FUNCTION__);
return 0;
}
return 1;
}
void avf_audio_input_cb(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer,
const AudioTimeStamp *inStartTime, uint32 inNumberPacketDescriptions,
const AudioStreamPacketDescription *inPacketDescs)
{
AVFAudioContext * context = (AVFAudioContext *) inUserData;
const uint8 * ptr = (const uint8 *) inBuffer->mAudioData;
uint32 remaining = inBuffer->mAudioDataByteSize;
while (remaining > 0)
{
uint32 len = context->buffer_size - context->buffer_offset;
if (len > remaining)
{
len = remaining;
}
memcpy((char *)context->buffer + context->buffer_offset, ptr, len);
ptr += len;
remaining -= len;
context->buffer_offset += len;
if (context->buffer_offset >= context->buffer_size)
{
if (context->callback)
{
avf_audio_data data;
memset(&data, 0, sizeof(data));
data.data[0] = (uint8 *)context->buffer;
data.linesize[0] = context->buffer_size;
data.samplerate = context->samplerate;
data.channels = context->channels;
data.samples = context->samples;
data.format = context->samplefmt;
context->callback(&data, context->userdata);
}
context->buffer_offset = 0;
}
}
AudioQueueEnqueueBuffer(context->audio_queue, inBuffer, 0, NULL);
}
int avf_audio_prepare_queue(AVFAudioContext * context)
{
int i;
OSStatus result;
const AudioStreamBasicDescription *strdesc = &context->strdesc;
result = AudioQueueNewInput(strdesc, avf_audio_input_cb, context, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &context->audio_queue);
if (result != noErr)
{
log_print(HT_LOG_ERR, "%s, AudioQueueNewInput failed\r\n", __FUNCTION__);
return 0;
}
if (!avf_audio_assign_device(context))
{
log_print(HT_LOG_ERR, "%s, avf_audio_assign_device failed\r\n", __FUNCTION__);
return 0;
}
AudioChannelLayout layout;
memset(&layout, 0, sizeof(layout));
layout.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo;
result = AudioQueueSetProperty(context->audio_queue, kAudioQueueProperty_ChannelLayout, &layout, sizeof(layout));
if (result != noErr)
{
log_print(HT_LOG_ERR, "%s, AudioQueueSetProperty failed\r\n", __FUNCTION__);
return 0;
}
uint32 size = strdesc->mBitsPerChannel / 8;
size *= context->channels;
size *= context->samples;
/* Allocate a sample buffer */
context->buffer_size = size;
context->buffer_offset = 0;
context->buffer = malloc(context->buffer_size);
if (context->buffer == NULL)
{
log_print(HT_LOG_ERR, "%s, malloc failed\r\n", __FUNCTION__);
return 0;
}
/* Make sure we can feed the device a minimum amount of time */
double MINIMUM_AUDIO_BUFFER_TIME_MS = 15.0;
const double msecs = (context->samples / ((double) context->samplerate)) * 1000.0;
int num_audio_buffers = 2;
if (msecs < MINIMUM_AUDIO_BUFFER_TIME_MS)
{
/* use more buffers if we have a VERY small sample set. */
num_audio_buffers = ((int)ceil(MINIMUM_AUDIO_BUFFER_TIME_MS / msecs) * 2);
}
context->num_audio_buffers = num_audio_buffers;
context->audio_buffer = (AudioQueueBufferRef *) calloc(1, sizeof(AudioQueueBufferRef) * num_audio_buffers);
if (context->audio_buffer == NULL)
{
log_print(HT_LOG_ERR, "%s, calloc failed\r\n", __FUNCTION__);
return 0;
}
for (i = 0; i < num_audio_buffers; i++)
{
result = AudioQueueAllocateBuffer(context->audio_queue, size, &context->audio_buffer[i]);
if (result != noErr)
{
log_print(HT_LOG_ERR, "%s, AudioQueueAllocateBuffer failed\r\n", __FUNCTION__);
return 0;
}
memset(context->audio_buffer[i]->mAudioData, 0, context->audio_buffer[i]->mAudioDataBytesCapacity);
context->audio_buffer[i]->mAudioDataByteSize = context->audio_buffer[i]->mAudioDataBytesCapacity;
result = AudioQueueEnqueueBuffer(context->audio_queue, context->audio_buffer[i], 0, NULL);
if (result != noErr)
{
log_print(HT_LOG_ERR, "%s, AudioQueueEnqueueBuffer failed\r\n", __FUNCTION__);
return 0;
}
}
result = AudioQueueStart(context->audio_queue, NULL);
if (result != noErr)
{
log_print(HT_LOG_ERR, "%s, AudioQueueStart failed\r\n", __FUNCTION__);
return 0;
}
/* We're running! */
return 1;
}
void * avf_audio_thread(void * argv)
{
AVFAudioContext * context = (AVFAudioContext *) argv;
const int rc = avf_audio_prepare_queue(context);
if (!rc)
{
log_print(HT_LOG_ERR, "%s, avf_audio_prepare_queue failed\r\n", __FUNCTION__);
return NULL;
}
while (context->capture_flag)
{
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.10, 1);
}
context->capture_thread = 0;
return NULL;
}
void * avf_audio_init(int device_index, int samplerate, int channels)
{
AVFAudioContext * context = (AVFAudioContext *)malloc(sizeof(AVFAudioContext));
if (NULL == context)
{
return NULL;
}
memset(context, 0, sizeof(AVFAudioContext));
context->device_index = device_index;
context->samplerate = samplerate;
context->channels = channels;
context->samples = 1024;
context->samplefmt = 1; // AV_SAMPLE_FMT_S16
AudioStreamBasicDescription *strdesc = &context->strdesc;
memset(strdesc, 0, sizeof(AudioStreamBasicDescription));
strdesc->mFormatID = kAudioFormatLinearPCM;
strdesc->mFormatFlags = kLinearPCMFormatFlagIsPacked;
strdesc->mChannelsPerFrame = channels;
strdesc->mSampleRate = samplerate;
strdesc->mFramesPerPacket = 1;
strdesc->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
strdesc->mBitsPerChannel = 16;
strdesc->mBytesPerFrame = strdesc->mChannelsPerFrame * strdesc->mBitsPerChannel / 8;
strdesc->mBytesPerPacket = strdesc->mBytesPerFrame * strdesc->mFramesPerPacket;
if (!avf_audio_prepare_device(context))
{
log_print(HT_LOG_ERR, "%s, avf_prepare_device failed!\r\n", __FUNCTION__);
goto fail;
}
context->capture_flag = TRUE;
context->capture_thread = sys_os_create_thread((void *)avf_audio_thread, (void *)context);
if (!context->capture_thread)
{
goto fail;
}
context->mutex_cb = sys_os_create_mutex();
return context;
fail:
avf_audio_uninit((void *)context);
return NULL;
}
void avf_audio_uninit(void * ctx)
{
if (NULL == ctx)
{
return;
}
AVFAudioContext * context = (AVFAudioContext *)ctx;
if (context->audio_queue)
{
AudioQueueDispose(context->audio_queue, 1);
}
context->capture_flag = FALSE;
while (context->capture_thread)
{
usleep(200*1000);
}
free(context->audio_buffer);
free(context->buffer);
sys_os_destroy_sig_mutex(context->mutex_cb);
free(context);
}
void avf_audio_set_callback(void * ctx, avf_audio_callback cb, void * userdata)
{
if (NULL == ctx)
{
return;
}
AVFAudioContext * context = (AVFAudioContext *)ctx;
sys_os_mutex_enter(context->mutex_cb);
context->callback = cb;
context->userdata = userdata;
sys_os_mutex_leave(context->mutex_cb);
}
int avf_audio_get_samplerate(void * ctx)
{
if (NULL == ctx)
{
return 0;
}
AVFAudioContext * context = (AVFAudioContext *)ctx;
return context->samplerate;
}
int avf_audio_get_channels(void * ctx)
{
if (NULL == ctx)
{
return 0;
}
AVFAudioContext * context = (AVFAudioContext *)ctx;
return context->channels;
}
int avf_audio_get_samplefmt(void * ctx)
{
if (NULL == ctx)
{
return 0;
}
AVFAudioContext * context = (AVFAudioContext *)ctx;
return context->samplefmt;
}
BOOL avf_audio_read(void * ctx, int * samples)
{
return FALSE;
}