Commit a5537a84 authored by aymeric's avatar aymeric

add support for several outputs

git-svn-id: svn+ssh://svn.savannah.nongnu.org/linphone/trunk@709 3f6dc0c8-ddfe-455d-9043-3cd528dc4637
parent e794d1ea
......@@ -60,115 +60,409 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "mediastreamer2/mssndcard.h"
#include "mediastreamer2/msfilter.h"
MSFilter *ms_aq_read_new(MSSndCard *card);
MSFilter *ms_aq_write_new(MSSndCard *card);
#define kSecondsPerBuffer 0.02
#define kNumberAudioDataBuffers 4
typedef struct AQData{
int rate;
int bits;
bool_t stereo;
ms_mutex_t mutex;
queue_t rq;
bool_t read_started;
bool_t write_started;
AudioQueueRef readQueue;
AudioStreamBasicDescription readAudioFormat;
UInt32 readBufferByteSize;
AudioQueueRef writeQueue;
AudioStreamBasicDescription writeAudioFormat;
UInt32 writeBufferByteSize;
AudioQueueBufferRef writeBuffers[kNumberAudioDataBuffers];
int curWriteBuffer;
MSBufferizer *bufferizer;
MSFilter *ms_aq_read_new(MSSndCard * card);
MSFilter *ms_aq_write_new(MSSndCard * card);
#define kSecondsPerBuffer 0.02 /*0.04 */
#define kNumberAudioOutDataBuffers 4
#define kNumberAudioInDataBuffers 4
typedef struct AQData {
CFStringRef uidname;
AudioStreamBasicDescription devicereadFormat;
AudioStreamBasicDescription devicewriteFormat;
int rate;
int bits;
bool_t stereo;
ms_mutex_t mutex;
queue_t rq;
bool_t read_started;
bool_t write_started;
AudioConverterRef readAudioConverter;
AudioQueueRef readQueue;
AudioStreamBasicDescription readAudioFormat;
UInt32 readBufferByteSize;
AudioConverterRef writeAudioConverter;
AudioQueueRef writeQueue;
AudioStreamBasicDescription writeAudioFormat;
UInt32 writeBufferByteSize;
AudioQueueBufferRef writeBuffers[kNumberAudioOutDataBuffers];
int curWriteBuffer;
MSBufferizer *bufferizer;
} AQData;
/*
mediastreamer2 function
*/
typedef struct AqSndDsCard {
CFStringRef uidname;
AudioStreamBasicDescription devicereadFormat;
AudioStreamBasicDescription devicewriteFormat;
int removed;
} AqSndDsCard;
static void aqcard_set_level(MSSndCard * card, MSSndCardMixerElem e,
int percent)
{
}
static int aqcard_get_level(MSSndCard * card, MSSndCardMixerElem e)
{
return 0;
}
static void aqcard_set_source(MSSndCard * card, MSSndCardCapture source)
{
}
static void aqcard_init(MSSndCard * card)
{
AqSndDsCard *c = (AqSndDsCard *) ms_new(AqSndDsCard, 1);
c->removed = 0;
card->data = c;
}
static void aqcard_uninit(MSSndCard * card)
{
AqSndDsCard *d = (AqSndDsCard *) card->data;
if (d->uidname != NULL)
CFRelease(d->uidname);
ms_free(d);
}
static void aqcard_detect(MSSndCardManager * m);
static MSSndCard *aqcard_duplicate(MSSndCard * obj);
MSSndCardDesc aq_card_desc = {
.driver_type = "AQ",
.detect = aqcard_detect,
.init = aqcard_init,
.set_level = aqcard_set_level,
.get_level = aqcard_get_level,
.set_capture = aqcard_set_source,
.set_control = NULL,
.get_control = NULL,
.create_reader = ms_aq_read_new,
.create_writer = ms_aq_write_new,
.uninit = aqcard_uninit,
.duplicate = aqcard_duplicate
};
static MSSndCard *aqcard_duplicate(MSSndCard * obj)
{
MSSndCard *card = ms_snd_card_new(&aq_card_desc);
card->name = ms_strdup(obj->name);
card->data = ms_new(AqSndDsCard, 1);
memcpy(card->data, obj->data, sizeof(AqSndDsCard));
return card;
}
static MSSndCard *aq_card_new(const char *name, CFStringRef uidname,
AudioStreamBasicDescription *
devicereadFormat,
AudioStreamBasicDescription *
devicewriteFormat, unsigned cap)
{
MSSndCard *card = ms_snd_card_new(&aq_card_desc);
AqSndDsCard *d = (AqSndDsCard *) card->data;
d->uidname = uidname;
memcpy(&d->devicereadFormat, devicereadFormat,
sizeof(AudioStreamBasicDescription));
memcpy(&d->devicewriteFormat, devicewriteFormat,
sizeof(AudioStreamBasicDescription));
card->name = ms_strdup(name);
card->capabilities = cap;
return card;
}
static void show_format(char *name,
AudioStreamBasicDescription * deviceFormat)
{
ms_debug("Format for %s", name);
ms_debug("mSampleRate = %g", deviceFormat->mSampleRate);
char *the4CCString = (char *) &deviceFormat->mFormatID;
char outName[5];
outName[0] = the4CCString[0];
outName[1] = the4CCString[1];
outName[2] = the4CCString[2];
outName[3] = the4CCString[3];
outName[4] = 0;
ms_debug("mFormatID = %s", outName);
ms_debug("mFormatFlags = %08lX", deviceFormat->mFormatFlags);
ms_debug("mBytesPerPacket = %ld", deviceFormat->mBytesPerPacket);
ms_debug("mFramesPerPacket = %ld", deviceFormat->mFramesPerPacket);
ms_debug("mChannelsPerFrame = %ld", deviceFormat->mChannelsPerFrame);
ms_debug("mBytesPerFrame = %ld", deviceFormat->mBytesPerFrame);
ms_debug("mBitsPerChannel = %ld", deviceFormat->mBitsPerChannel);
}
static void aqcard_detect(MSSndCardManager * m)
{
OSStatus err;
UInt32 slen;
int count;
Boolean writable;
int i;
writable = 0;
slen = 0;
err =
AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &slen,
&writable);
if (err != kAudioHardwareNoError) {
ms_error("get kAudioHardwarePropertyDevices error %ld", err);
return;
}
AudioDeviceID V[slen / sizeof(AudioDeviceID)];
err =
AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &slen, V);
if (err != kAudioHardwareNoError) {
ms_error("get kAudioHardwarePropertyDevices error %ld", err);
return;
}
count = slen / sizeof(AudioDeviceID);
for (i = 0; i < count; i++) {
char devname[256];
char uidname[256];
int cap = 0;
slen = 256;
err =
AudioDeviceGetProperty(V[i], 0, FALSE,
kAudioDevicePropertyDeviceName, &slen,
devname);
if (err != kAudioHardwareNoError) {
ms_error("get kAudioDevicePropertyDeviceName error %ld", err);
continue;
}
slen = strlen(devname);
/* trim whitespace */
while ((slen > 0) && (devname[slen - 1] == ' ')) {
slen--;
}
devname[slen] = '\0';
err =
AudioDeviceGetPropertyInfo(V[i], 0, FALSE,
kAudioDevicePropertyStreamConfiguration,
&slen, &writable);
if (err != kAudioHardwareNoError) {
ms_error("get kAudioDevicePropertyDeviceName error %ld", err);
continue;
}
AudioBufferList *buflist = ms_new(slen, 1);
if (buflist == NULL) {
ms_error("alloc AudioBufferList %ld", err);
continue;
}
err =
AudioDeviceGetProperty(V[i], 0, FALSE,
kAudioDevicePropertyStreamConfiguration,
&slen, buflist);
if (err != kAudioHardwareNoError) {
ms_error("get kAudioDevicePropertyDeviceName error %ld", err);
ms_free(buflist);
continue;
}
UInt32 j;
for (j = 0; j < buflist->mNumberBuffers; j++) {
if (buflist->mBuffers[j].mNumberChannels > 0) {
cap = MS_SND_CARD_CAP_PLAYBACK;
break;
}
}
ms_free(buflist);
err =
AudioDeviceGetPropertyInfo(V[i], 0, TRUE,
kAudioDevicePropertyStreamConfiguration,
&slen, &writable);
if (err != kAudioHardwareNoError) {
ms_error("get kAudioDevicePropertyDeviceName error %ld", err);
continue;
}
buflist = ms_new(slen, 1);
if (buflist == NULL) {
ms_error("alloc error %ld", err);
continue;
}
err =
AudioDeviceGetProperty(V[i], 0, TRUE,
kAudioDevicePropertyStreamConfiguration,
&slen, buflist);
if (err != kAudioHardwareNoError) {
ms_error("get kAudioDevicePropertyDeviceName error %ld", err);
ms_free(buflist);
continue;
}
for (j = 0; j < buflist->mNumberBuffers; j++) {
if (buflist->mBuffers[j].mNumberChannels > 0) {
cap |= MS_SND_CARD_CAP_CAPTURE;
break;
}
}
ms_free(buflist);
CFStringRef dUID;
dUID = NULL;
slen = sizeof(CFStringRef);
err =
AudioDeviceGetProperty(V[i], 0, false,
kAudioDevicePropertyDeviceUID, &slen,
&dUID);
if (err != kAudioHardwareNoError) {
ms_error("get kAudioHardwarePropertyDevices error %ld", err);
continue;
}
CFStringGetCString(dUID, uidname, 256,
CFStringGetSystemEncoding());
ms_message("AQ: devname:%s uidname:%s", devname, uidname);
AudioStreamBasicDescription devicereadFormat;
AudioStreamBasicDescription devicewriteFormat;
slen = sizeof(devicewriteFormat);
err = AudioDeviceGetProperty(V[i], 0, false,
kAudioDevicePropertyStreamFormat,
&slen, &devicewriteFormat);
if (err == kAudioHardwareNoError) {
show_format("output device", &devicewriteFormat);
}
slen = sizeof(devicereadFormat);
err = AudioDeviceGetProperty(V[i], 0, true,
kAudioDevicePropertyStreamFormat,
&slen, &devicereadFormat);
if (err == kAudioHardwareNoError) {
show_format("input device", &devicereadFormat);
}
MSSndCard *card = aq_card_new(devname, dUID, &devicereadFormat,
&devicewriteFormat, cap);
ms_snd_card_manager_add_card(m, card);
}
}
/*
Audio Queue recode callback
*/
static void readCallback (
void *aqData,
AudioQueueRef inAQ,
AudioQueueBufferRef inBuffer,
const AudioTimeStamp *inStartTime,
UInt32 inNumPackets,
const AudioStreamPacketDescription *inPacketDesc
) {
ms_debug("readCallback");
AQData *d=(AQData*)aqData;
static void readCallback(void *aqData,
AudioQueueRef inAQ,
AudioQueueBufferRef inBuffer,
const AudioTimeStamp * inStartTime,
UInt32 inNumPackets,
const AudioStreamPacketDescription * inPacketDesc)
{
AQData *d = (AQData *) aqData;
OSStatus err;
mblk_t *rm = NULL;
UInt32 len =
(inBuffer->mAudioDataByteSize * d->readAudioFormat.mSampleRate /
1) / d->devicereadFormat.mSampleRate /
d->devicereadFormat.mChannelsPerFrame;
// ms_debug("readCallback inNumPackets %d %d", inNumPackets, inBuffer->mAudioDataByteSize);
mblk_t *rm=NULL;
rm=allocb(inNumPackets*2,0);
memcpy(rm->b_wptr, inBuffer->mAudioData, inNumPackets*2);
rm->b_wptr += inNumPackets*2;
ms_mutex_lock(&d->mutex);
putq(&d->rq,rm);
ms_mutex_unlock(&d->mutex);
rm=NULL;
err = AudioQueueEnqueueBuffer (
d->readQueue,
inBuffer,
0,
NULL
);
if(err != noErr) {
if (d->read_started == FALSE) {
ms_mutex_unlock(&d->mutex);
return;
}
rm = allocb(len, 0);
err = AudioConverterConvertBuffer(d->readAudioConverter,
inBuffer->mAudioDataByteSize,
inBuffer->mAudioData,
&len, rm->b_wptr);
if (err != noErr) {
ms_error("readCallback: AudioConverterConvertBuffer %d", err);
ms_warning("readCallback: inBuffer->mAudioDataByteSize = %d",
inBuffer->mAudioDataByteSize);
ms_warning("readCallback: outlen = %d", len);
ms_warning("readCallback: origlen = %i",
(inBuffer->mAudioDataByteSize *
d->readAudioFormat.mSampleRate / 1) /
d->devicereadFormat.mSampleRate /
d->devicereadFormat.mChannelsPerFrame);
freeb(rm);
} else {
rm->b_wptr += len;
putq(&d->rq, rm);
}
err = AudioQueueEnqueueBuffer(d->readQueue, inBuffer, 0, NULL);
if (err != noErr) {
ms_error("readCallback:AudioQueueEnqueueBuffer %d", err);
}
ms_mutex_unlock(&d->mutex);
}
/*
Audio Queue play callback
*/
static void writeCallback (
void *aqData,
AudioQueueRef inAQ,
AudioQueueBufferRef inBuffer
) {
ms_debug("writeCallback");
AQData *d=(AQData*)aqData;
static void writeCallback(void *aqData,
AudioQueueRef inAQ, AudioQueueBufferRef inBuffer)
{
AQData *d = (AQData *) aqData;
OSStatus err;
if(d->bufferizer->size >= d->writeBufferByteSize) {
ms_mutex_lock(&d->mutex);
ms_bufferizer_read(d->bufferizer, inBuffer->mAudioData, d->writeBufferByteSize);
int len =
(d->writeBufferByteSize * d->writeAudioFormat.mSampleRate / 2) /
d->devicewriteFormat.mSampleRate /
d->devicewriteFormat.mChannelsPerFrame;
ms_mutex_lock(&d->mutex);
if (d->write_started == FALSE) {
ms_mutex_unlock(&d->mutex);
return;
}
if (d->bufferizer->size >= len) {
UInt32 bsize = d->writeBufferByteSize;
uint8_t *pData = ms_malloc(len);
ms_bufferizer_read(d->bufferizer, pData, len);
err = AudioConverterConvertBuffer(d->writeAudioConverter,
len,
pData,
&bsize, inBuffer->mAudioData);
if (err != noErr) {
ms_error("writeCallback: AudioConverterConvertBuffer %d", err);
}
ms_free(pData);
if (bsize != d->writeBufferByteSize)
ms_warning("d->writeBufferByteSize = %i len = %i bsize = %i",
d->writeBufferByteSize, len, bsize);
} else {
memset(inBuffer->mAudioData, 0, d->writeBufferByteSize);
}
inBuffer->mAudioDataByteSize = d->writeBufferByteSize;
err = AudioQueueEnqueueBuffer (
d->writeQueue,
inBuffer,
0,
NULL
);
if(err != noErr) {
err = AudioQueueEnqueueBuffer(d->writeQueue, inBuffer, 0, NULL);
if (err != noErr) {
ms_error("AudioQueueEnqueueBuffer %d", err);
}
ms_mutex_unlock(&d->mutex);
}
void putWriteAQ(void *aqData,
int queuenum)
void putWriteAQ(void *aqData, int queuenum)
{
ms_debug("putWriteAQ");
AQData *d=(AQData*)aqData;
AQData *d = (AQData *) aqData;
OSStatus err;
err = AudioQueueEnqueueBuffer (
d->writeQueue,
d->writeBuffers[queuenum],
0,
NULL
);
if(err != noErr) {
err = AudioQueueEnqueueBuffer(d->writeQueue,
d->writeBuffers[queuenum], 0, NULL);
if (err != noErr) {
ms_error("AudioQueueEnqueueBuffer %d", err);
}
}
......@@ -177,21 +471,21 @@ void putWriteAQ(void *aqData,
play buffer setup function
*/
void setupWrite(MSSndCard *card) {
ms_debug("setupWrite");
AQData *d=(AQData*)card->data;
void setupWrite(MSFilter * f)
{
AQData *d = (AQData *) f->data;
OSStatus err;
int bufferIndex;
for (bufferIndex = 0; bufferIndex < kNumberAudioDataBuffers; ++bufferIndex) {
err = AudioQueueAllocateBuffer (
d->writeQueue,
d->writeBufferByteSize,
&d->writeBuffers[bufferIndex]
);
if(err != noErr) {
for (bufferIndex = 0; bufferIndex < kNumberAudioOutDataBuffers;
++bufferIndex) {
err = AudioQueueAllocateBuffer(d->writeQueue,
d->writeBufferByteSize,
&d->writeBuffers[bufferIndex]
);
if (err != noErr) {
ms_error("setupWrite:AudioQueueAllocateBuffer %d", err);
}
}
......@@ -201,437 +495,408 @@ void setupWrite(MSSndCard *card) {
recode buffer setup function
*/
void setupRead(MSSndCard *card) {
ms_debug("setupRead");
AQData *d=(AQData*)card->data;
void setupRead(MSFilter * f)
{
AQData *d = (AQData *) f->data;
OSStatus err;
// allocate and enqueue buffers
int bufferIndex;
for (bufferIndex = 0; bufferIndex < kNumberAudioDataBuffers; ++bufferIndex) {
for (bufferIndex = 0; bufferIndex < kNumberAudioInDataBuffers;
++bufferIndex) {
AudioQueueBufferRef buffer;
err = AudioQueueAllocateBuffer (
d->readQueue,
d->readBufferByteSize,
&buffer
);
if(err != noErr) {
err = AudioQueueAllocateBuffer(d->readQueue,
d->readBufferByteSize, &buffer);
if (err != noErr) {
ms_error("setupRead:AudioQueueAllocateBuffer %d", err);
}
err = AudioQueueEnqueueBuffer (
d->readQueue,
buffer,
0,
NULL
);
if(err != noErr) {
err = AudioQueueEnqueueBuffer(d->readQueue, buffer, 0, NULL);
if (err != noErr) {
ms_error("AudioQueueEnqueueBuffer %d", err);
}
}
}
/*
mediastreamer2 function
*/
static void aq_set_level(MSSndCard *card, MSSndCardMixerElem e, int percent)
{
}
static int aq_get_level(MSSndCard *card, MSSndCardMixerElem e)
{
return 0;
}
static void aq_set_source(MSSndCard *card, MSSndCardCapture source)
static void aq_start_r(MSFilter * f)
{
}
static void aq_init(MSSndCard *card){
ms_debug("aq_init");
AQData *d=ms_new(AQData,1);
d->bits=16;
d->rate=8000;
d->stereo=FALSE;
d->read_started=FALSE;
d->write_started=FALSE;
qinit(&d->rq);
d->bufferizer=ms_bufferizer_new();
ms_mutex_init(&d->mutex,NULL);
card->data=d;
}
static void aq_uninit(MSSndCard *card){
AQData *d=(AQData*)card->data;
flushq(&d->rq,0);
ms_bufferizer_destroy(d->bufferizer);
ms_mutex_destroy(&d->mutex);
ms_free(d);
}
static void aq_detect(MSSndCardManager *m);
static MSSndCard *aq_duplicate(MSSndCard *obj);
MSSndCardDesc aq_card_desc={
.driver_type="AQ",
.detect=aq_detect,
.init=aq_init,
.set_level=aq_set_level,
.get_level=aq_get_level,
.set_capture=aq_set_source,
.set_control=NULL,
.get_control=NULL,
.create_reader=ms_aq_read_new,
.create_writer=ms_aq_write_new,
.uninit=aq_uninit,
.duplicate=aq_duplicate
};
static MSSndCard *aq_duplicate(MSSndCard *obj){
MSSndCard *card=ms_snd_card_new(&aq_card_desc);
card->name=ms_strdup(obj->name);
return card;
}
static MSSndCard *aq_card_new(){
MSSndCard *card=ms_snd_card_new(&aq_card_desc);
card->name=ms_strdup("Audio Queue");
return card;
}
static void aq_detect(MSSndCardManager *m){
ms_debug("aq_detect");
AQData *d = (AQData *) f->data;
if (d->read_started == FALSE) {
OSStatus aqresult;
#if defined(__AudioHardware_h__)
OSStatus err;
UInt32 count;
AudioDeviceID inDevice, outDevice;
char name[255];
d->readAudioFormat.mSampleRate = d->rate;
d->readAudioFormat.mFormatID = kAudioFormatLinearPCM;
d->readAudioFormat.mFormatFlags =
kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
d->readAudioFormat.mFramesPerPacket = 1;
d->readAudioFormat.mChannelsPerFrame = 1;
d->readAudioFormat.mBitsPerChannel = d->bits;
d->readAudioFormat.mBytesPerPacket = d->bits / 8;
d->readAudioFormat.mBytesPerFrame = d->bits / 8;
//show_format("input device", &d->devicereadFormat);
//show_format("data from input filter", &d->readAudioFormat);
memcpy(&d->devicereadFormat, &d->readAudioFormat,
sizeof(d->readAudioFormat));
d->readBufferByteSize =
kSecondsPerBuffer * d->devicereadFormat.mSampleRate *
(d->devicereadFormat.mBitsPerChannel / 8) *
d->devicereadFormat.mChannelsPerFrame;
aqresult = AudioConverterNew(&d->devicereadFormat,
&d->readAudioFormat,
&d->readAudioConverter);
if (aqresult != noErr) {
ms_error("d->readAudioConverter = %d", aqresult);
d->readAudioConverter = NULL;
}
count = sizeof(inDevice);
err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice,
&count,
&inDevice);
if (err) {
ms_error("get kAudioHardwarePropertyDefaultInputDevice error %x", err);
return;
}
count = sizeof(char) * 255;
AudioDeviceGetProperty(inDevice, 0, false, kAudioDevicePropertyDeviceName, &count, &name);
ms_debug("InputDevice name = %s",name);
count = sizeof(outDevice);
err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice,
&count,
&outDevice);
if (err) {
ms_error("get kAudioHardwarePropertyDefaultOutputDevice error %d", err);
return;
}
count = sizeof(char) * 255;
AudioDeviceGetProperty(outDevice, 0, false, kAudioDevicePropertyDeviceName, &count, &name);
ms_debug("OutputDevice name = %s", name);
UInt32 deviceBufferSize;
AudioStreamBasicDescription deviceFormat;
count = sizeof(deviceBufferSize);
err = AudioDeviceGetProperty(outDevice,
0,
false,
kAudioDevicePropertyBufferSize,
&count,
&deviceBufferSize);
if (err != kAudioHardwareNoError) {
ms_error("get kAudioDevicePropertyBufferSize error %ld", err);