aqsnd.c 31 KB
Newer Older
smorlat's avatar
smorlat committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2006  Simon MORLAT (simon.morlat@linphone.org)

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

/* this file is specifically distributed under a BSD license */

/**
* Copyright (C) 2008  Hiroki Mori (himori@users.sourceforge.net)
* All rights reserved.
* 
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in the
*       documentation and/or other materials provided with the distribution.
*     * Neither the name of the <organization> nor the
*       names of its contributors may be used to endorse or promote products
*       derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY <copyright holder> ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**/

/*
 This is MacOS X Audio Queue Service support code for mediastreamer2.
 Audio Queue Support MacOS X 10.5 or later.
 http://developer.apple.com/documentation/MusicAudio/Conceptual/AudioQueueProgrammingGuide/
 */

55 56 57 58
#ifdef __APPLE__
#include "TargetConditionals.h"
#endif

smorlat's avatar
smorlat committed
59
#include <AudioToolbox/AudioToolbox.h>
jehan's avatar
jehan committed
60
#if !TARGET_OS_IPHONE
61
#include <CoreAudio/AudioHardware.h>
smorlat's avatar
smorlat committed
62 63 64 65 66
#endif

#include "mediastreamer2/mssndcard.h"
#include "mediastreamer2/msfilter.h"

aymeric's avatar
aymeric committed
67 68 69 70 71 72 73
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

74 75 76 77
static float gain_volume_in=1.0;
static float gain_volume_out=1.0;
static bool gain_changed_in = true;
static bool gain_changed_out = true;
78

jehan's avatar
jehan committed
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105

const char* aq_format_error(OSStatus status) {
	switch (status) {
		case kAudioQueueErr_InvalidBuffer: return "kAudioQueueErr_InvalidBuffer";
		case kAudioQueueErr_BufferEmpty: return"kAudioQueueErr_BufferEmpty";
		case kAudioQueueErr_DisposalPending: return"kAudioQueueErr_DisposalPending";
		case kAudioQueueErr_InvalidProperty: return"kAudioQueueErr_InvalidProperty";
		case kAudioQueueErr_InvalidPropertySize: return"kAudioQueueErr_InvalidPropertySize";
		case kAudioQueueErr_InvalidParameter: return"kAudioQueueErr_InvalidParameter";
		case kAudioQueueErr_CannotStart: return"kAudioQueueErr_CannotStart";
		case kAudioQueueErr_InvalidDevice: return"kAudioQueueErr_InvalidDevice";
		case kAudioQueueErr_BufferInQueue: return"kAudioQueueErr_BufferInQueue";
		case kAudioQueueErr_InvalidRunState: return"kAudioQueueErr_InvalidRunState";
		case kAudioQueueErr_InvalidQueueType: return"kAudioQueueErr_InvalidQueueType";
		case kAudioQueueErr_Permissions: return"kAudioQueueErr_Permissions";
		case kAudioQueueErr_InvalidPropertyValue: return"kAudioQueueErr_InvalidPropertyValue";
		case kAudioQueueErr_PrimeTimedOut: return"kAudioQueueErr_PrimeTimedOut";
		case kAudioQueueErr_CodecNotFound: return"kAudioQueueErr_CodecNotFound";
		case kAudioQueueErr_InvalidCodecAccess: return"kAudioQueueErr_InvalidCodecAccess";
		case kAudioQueueErr_QueueInvalidated: return"kAudioQueueErr_QueueInvalidated";
		case kAudioQueueErr_RecordUnderrun: return"kAudioQueueErr_RecordUnderrun";
		case kAudioQueueErr_EnqueueDuringReset: return"kAudioQueueErr_EnqueueDuringReset";
		case kAudioQueueErr_InvalidOfflineMode: return"kAudioQueueErr_InvalidOfflineMode";
		default:
			return "unkown error code";
	}
}
Simon Morlat's avatar
Simon Morlat committed
106
#ifdef __ios
107 108 109 110
#define CFStringRef void *
#define CFRelease(A) {}
#define CFStringGetCString(A, B, LEN, encoding)  {}
#define CFStringCreateCopy(A, B) NULL
111
#define check_aqresult(aq,method) \
jehan's avatar
jehan committed
112
if (aq!=0) ms_error("AudioQueue error for %s: ret=%s",method,aq_format_error(aq))
113 114
#endif

aymeric's avatar
aymeric committed
115 116 117 118 119 120 121 122 123 124 125 126 127
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;
128
#if 0
aymeric's avatar
aymeric committed
129
	AudioConverterRef readAudioConverter;
130
#endif
aymeric's avatar
aymeric committed
131 132 133 134
	AudioQueueRef readQueue;
	AudioStreamBasicDescription readAudioFormat;
	UInt32 readBufferByteSize;

135
#if 0
aymeric's avatar
aymeric committed
136
	AudioConverterRef writeAudioConverter;
137
#endif
aymeric's avatar
aymeric committed
138 139 140 141 142 143
	AudioQueueRef writeQueue;
	AudioStreamBasicDescription writeAudioFormat;
	UInt32 writeBufferByteSize;
	AudioQueueBufferRef writeBuffers[kNumberAudioOutDataBuffers];
	int curWriteBuffer;
	MSBufferizer *bufferizer;
smorlat's avatar
smorlat committed
144 145
} AQData;

aymeric's avatar
aymeric committed
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161


/*
 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)
{
162 163 164 165 166 167 168 169 170 171 172 173 174
	switch(e){
		case MS_SND_CARD_PLAYBACK:
		case MS_SND_CARD_MASTER:
			gain_volume_out =((float)percent)/100.0f;
			gain_changed_out = true;
			return;
		case MS_SND_CARD_CAPTURE:
			gain_volume_in =((float)percent)/100.0f;
			gain_changed_in = true;
			return;
		default:
			ms_warning("aqcard_set_level: unsupported command.");
	}
aymeric's avatar
aymeric committed
175 176 177 178
}

static int aqcard_get_level(MSSndCard * card, MSSndCardMixerElem e)
{
179 180 181 182 183 184 185 186 187 188
	switch(e){
		case MS_SND_CARD_PLAYBACK:
		case MS_SND_CARD_MASTER:
		  return (int)(gain_volume_out*100.0f);
		case MS_SND_CARD_CAPTURE:
		  return (int)(gain_volume_in*100.0f);
		default:
			ms_warning("aqcard_get_level: unsupported command.");
	}
	return -1;
aymeric's avatar
aymeric committed
189 190 191 192 193 194 195 196
}

static void aqcard_set_source(MSSndCard * card, MSSndCardCapture source)
{
}

static void aqcard_init(MSSndCard * card)
{
197
	AqSndDsCard *c = (AqSndDsCard *) ms_new0(AqSndDsCard, 1);
aymeric's avatar
aymeric committed
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
	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)
{
230 231
	AqSndDsCard *ca;
	AqSndDsCard *cadup;
aymeric's avatar
aymeric committed
232 233
	MSSndCard *card = ms_snd_card_new(&aq_card_desc);
	card->name = ms_strdup(obj->name);
234
	card->data = ms_new0(AqSndDsCard, 1);
aymeric's avatar
aymeric committed
235
	memcpy(card->data, obj->data, sizeof(AqSndDsCard));
236 237 238
	ca = obj->data;
	cadup = card->data;
	cadup->uidname = CFStringCreateCopy(NULL, ca->uidname);
aymeric's avatar
aymeric committed
239 240 241 242 243 244 245 246 247 248 249 250
	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;
251 252 253 254 255 256
	if (devicereadFormat!=NULL)
	  memcpy(&d->devicereadFormat, devicereadFormat,
		 sizeof(AudioStreamBasicDescription));
	if (devicewriteFormat!=NULL)
	  memcpy(&d->devicewriteFormat, devicewriteFormat,
		 sizeof(AudioStreamBasicDescription));
aymeric's avatar
aymeric committed
257 258 259 260 261 262 263 264
	card->name = ms_strdup(name);
	card->capabilities = cap;
	return card;
}

static void show_format(char *name,
						AudioStreamBasicDescription * deviceFormat)
{
265 266
	ms_message("Format for %s", name);
	ms_message("mSampleRate = %g", deviceFormat->mSampleRate);
aymeric's avatar
aymeric committed
267 268 269 270 271 272 273
	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;
274 275 276 277 278 279 280
	ms_message("mFormatID = %s", outName);
	ms_message("mFormatFlags = %08lX", deviceFormat->mFormatFlags);
	ms_message("mBytesPerPacket = %ld", deviceFormat->mBytesPerPacket);
	ms_message("mFramesPerPacket = %ld", deviceFormat->mFramesPerPacket);
	ms_message("mChannelsPerFrame = %ld", deviceFormat->mChannelsPerFrame);
	ms_message("mBytesPerFrame = %ld", deviceFormat->mBytesPerFrame);
	ms_message("mBitsPerChannel = %ld", deviceFormat->mBitsPerChannel);
aymeric's avatar
aymeric committed
281 282 283 284
}

static void aqcard_detect(MSSndCardManager * m)
{
Simon Morlat's avatar
Simon Morlat committed
285
#ifdef __ios
jehan's avatar
jehan committed
286 287 288 289
	AudioStreamBasicDescription deviceFormat;
	memset(&deviceFormat, 0, sizeof(AudioStreamBasicDescription));
	
	MSSndCard *card = aq_card_new("Audio Queue Device", NULL, &deviceFormat,
290
								  &deviceFormat, MS_SND_CARD_CAP_PLAYBACK/*|MS_SND_CARD_CAP_CAPTURE*/);
jehan's avatar
jehan committed
291 292
	ms_snd_card_manager_add_card(m, card);
#else
aymeric's avatar
aymeric committed
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
	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++) {
316 317 318 319
		char devname_in[256];
		char uidname_in[256];
		char devname_out[256];
		char uidname_out[256];
aymeric's avatar
aymeric committed
320
		int cap = 0;
321 322

		/* OUTPUT CARDS */
aymeric's avatar
aymeric committed
323 324 325 326
		slen = 256;
		err =
			AudioDeviceGetProperty(V[i], 0, FALSE,
								   kAudioDevicePropertyDeviceName, &slen,
327
								   devname_out);
aymeric's avatar
aymeric committed
328 329 330 331
		if (err != kAudioHardwareNoError) {
			ms_error("get kAudioDevicePropertyDeviceName error %ld", err);
			continue;
		}
332
		slen = strlen(devname_out);
aymeric's avatar
aymeric committed
333
		/* trim whitespace */
334
		while ((slen > 0) && (devname_out[slen - 1] == ' ')) {
aymeric's avatar
aymeric committed
335 336
			slen--;
		}
337
		devname_out[slen] = '\0';
aymeric's avatar
aymeric committed
338 339 340 341 342 343 344 345 346

		err =
			AudioDeviceGetPropertyInfo(V[i], 0, FALSE,
									   kAudioDevicePropertyStreamConfiguration,
									   &slen, &writable);
		if (err != kAudioHardwareNoError) {
			ms_error("get kAudioDevicePropertyDeviceName error %ld", err);
			continue;
		}
347

Aymeric Moizard's avatar
Aymeric Moizard committed
348
		AudioBufferList *buflist = ms_malloc(slen);
aymeric's avatar
aymeric committed
349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
		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);

374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400
		/* INPUT CARDS */
		slen = 256;
		err =
			AudioDeviceGetProperty(V[i], 0, TRUE,
								   kAudioDevicePropertyDeviceName, &slen,
								   devname_in);
		if (err != kAudioHardwareNoError) {
			ms_error("get kAudioDevicePropertyDeviceName error %ld", err);
			continue;
		}
		slen = strlen(devname_in);
		/* trim whitespace */
		while ((slen > 0) && (devname_in[slen - 1] == ' ')) {
			slen--;
		}
		devname_in[slen] = '\0';

		err =
			AudioDeviceGetPropertyInfo(V[i], 0, TRUE,
									   kAudioDevicePropertyStreamConfiguration,
									   &slen, &writable);
		if (err != kAudioHardwareNoError) {
			ms_error("get kAudioDevicePropertyDeviceName error %ld", err);
			continue;
		}


aymeric's avatar
aymeric committed
401 402 403 404 405 406 407 408
		err =
			AudioDeviceGetPropertyInfo(V[i], 0, TRUE,
									   kAudioDevicePropertyStreamConfiguration,
									   &slen, &writable);
		if (err != kAudioHardwareNoError) {
			ms_error("get kAudioDevicePropertyDeviceName error %ld", err);
			continue;
		}
Aymeric Moizard's avatar
Aymeric Moizard committed
409
		buflist = ms_malloc(slen);
aymeric's avatar
aymeric committed
410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
		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);

434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460
		if (cap & MS_SND_CARD_CAP_PLAYBACK) {
		  CFStringRef dUID_out;
		  dUID_out = NULL;
		  slen = sizeof(CFStringRef);
		  err =
		    AudioDeviceGetProperty(V[i], 0, false,
					   kAudioDevicePropertyDeviceUID, &slen,
					   &dUID_out);
		  if (err != kAudioHardwareNoError) {
		    ms_error("get kAudioHardwarePropertyDevices error %ld", err);
		    continue;
		  }
		  CFStringGetCString(dUID_out, uidname_out, 256,
				     CFStringGetSystemEncoding());
		  ms_message("AQ: devname_out:%s uidname_out:%s", devname_out, uidname_out);

		  AudioStreamBasicDescription devicewriteFormat;
		  slen = sizeof(devicewriteFormat);
		  err = AudioDeviceGetProperty(V[i], 0, false,
					       kAudioDevicePropertyStreamFormat,
					       &slen, &devicewriteFormat);
		  if (err == kAudioHardwareNoError) {
		    show_format("output device", &devicewriteFormat);
		  }
		  MSSndCard *card = aq_card_new(devname_out, dUID_out, NULL,
						&devicewriteFormat, MS_SND_CARD_CAP_PLAYBACK);
		  ms_snd_card_manager_add_card(m, card);
aymeric's avatar
aymeric committed
461 462
		}

463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490
		if (cap & MS_SND_CARD_CAP_CAPTURE) {
		  CFStringRef dUID_in;
		  dUID_in = NULL;
		  slen = sizeof(CFStringRef);
		  err =
		    AudioDeviceGetProperty(V[i], 0, true,
					   kAudioDevicePropertyDeviceUID, &slen,
					   &dUID_in);
		  if (err != kAudioHardwareNoError) {
		    ms_error("get kAudioHardwarePropertyDevices error %ld", err);
		    continue;
		  }
		  CFStringGetCString(dUID_in, uidname_in, 256,
				     CFStringGetSystemEncoding());
		  ms_message("AQ: devname_in:%s uidname_in:%s", devname_in, uidname_in);
		  
		  AudioStreamBasicDescription devicereadFormat;
		  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_in, dUID_in, &devicereadFormat,
						NULL, MS_SND_CARD_CAP_CAPTURE);
		  ms_snd_card_manager_add_card(m, card);
		}
aymeric's avatar
aymeric committed
491
	}
492
#endif
aymeric's avatar
aymeric committed
493 494 495
}


smorlat's avatar
smorlat committed
496 497 498 499
/*
 Audio Queue recode callback
 */

aymeric's avatar
aymeric committed
500 501 502 503 504 505 506 507
static void readCallback(void *aqData,
						 AudioQueueRef inAQ,
						 AudioQueueBufferRef inBuffer,
						 const AudioTimeStamp * inStartTime,
						 UInt32 inNumPackets,
						 const AudioStreamPacketDescription * inPacketDesc)
{
	AQData *d = (AQData *) aqData;
smorlat's avatar
smorlat committed
508
	OSStatus err;
aymeric's avatar
aymeric committed
509 510 511 512 513 514
	mblk_t *rm = NULL;

	UInt32 len =
		(inBuffer->mAudioDataByteSize * d->readAudioFormat.mSampleRate /
		 1) / d->devicereadFormat.mSampleRate /
		d->devicereadFormat.mChannelsPerFrame;
smorlat's avatar
smorlat committed
515 516

	ms_mutex_lock(&d->mutex);
aymeric's avatar
aymeric committed
517 518 519 520 521 522 523
	if (d->read_started == FALSE) {
		ms_mutex_unlock(&d->mutex);
		return;
	}

	rm = allocb(len, 0);

524
#if 0
aymeric's avatar
aymeric committed
525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540
	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 {
541 542 543 544 545 546 547 548 549 550 551

	  rm->b_wptr += len;
	  if (gain_volume_in != 1.0f)
	    {
	      int16_t *ptr=(int16_t *)rm->b_rptr;
	      for (;ptr<(int16_t *)rm->b_wptr;ptr++)
		{
		  *ptr=(int16_t)(((float)(*ptr))*gain_volume_in);
		}
	    }
	  putq(&d->rq, rm);
aymeric's avatar
aymeric committed
552
	}
553 554 555 556 557 558 559 560 561 562 563 564 565 566
#else
	memcpy(rm->b_wptr, inBuffer->mAudioData, len);
	rm->b_wptr += len;
	if (gain_volume_in != 1.0f)
	{
		int16_t *ptr=(int16_t *)rm->b_rptr;
		for (;ptr<(int16_t *)rm->b_wptr;ptr++)
		{
			*ptr=(int16_t)(((float)(*ptr))*gain_volume_in);
		}
	}
	putq(&d->rq, rm);	
#endif
	
aymeric's avatar
aymeric committed
567 568
	err = AudioQueueEnqueueBuffer(d->readQueue, inBuffer, 0, NULL);
	if (err != noErr) {
jehan's avatar
jehan committed
569
		ms_error("readCallback:AudioQueueEnqueueBuffer %ld", err);
smorlat's avatar
smorlat committed
570
	}
aymeric's avatar
aymeric committed
571
	ms_mutex_unlock(&d->mutex);
smorlat's avatar
smorlat committed
572 573 574 575 576 577
}

/*
 Audio Queue play callback
 */

aymeric's avatar
aymeric committed
578 579 580 581
static void writeCallback(void *aqData,
						  AudioQueueRef inAQ, AudioQueueBufferRef inBuffer)
{
	AQData *d = (AQData *) aqData;
smorlat's avatar
smorlat committed
582
	OSStatus err;
aymeric's avatar
aymeric committed
583 584

	int len =
585
		(d->writeBufferByteSize * d->writeAudioFormat.mSampleRate / 1) /
aymeric's avatar
aymeric committed
586 587 588 589 590
		d->devicewriteFormat.mSampleRate /
		d->devicewriteFormat.mChannelsPerFrame;

	ms_mutex_lock(&d->mutex);
	if (d->write_started == FALSE) {
smorlat's avatar
smorlat committed
591
		ms_mutex_unlock(&d->mutex);
aymeric's avatar
aymeric committed
592 593 594
		return;
	}
	if (d->bufferizer->size >= len) {
595
#if 0
aymeric's avatar
aymeric committed
596 597 598 599 600 601 602 603 604 605 606 607
		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);
smorlat's avatar
smorlat committed
608

aymeric's avatar
aymeric committed
609 610 611
		if (bsize != d->writeBufferByteSize)
			ms_warning("d->writeBufferByteSize = %i len = %i bsize = %i",
					   d->writeBufferByteSize, len, bsize);
612 613 614
#else
		ms_bufferizer_read(d->bufferizer, inBuffer->mAudioData, len);
#endif
smorlat's avatar
smorlat committed
615 616 617 618
	} else {
		memset(inBuffer->mAudioData, 0, d->writeBufferByteSize);
	}
	inBuffer->mAudioDataByteSize = d->writeBufferByteSize;
619 620 621 622 623 624 625 626 627

	if (gain_changed_out == true)
	  {
	    AudioQueueSetParameter (d->writeQueue,
				    kAudioQueueParam_Volume,
				    gain_volume_out);
	    gain_changed_out = false;
	  }

aymeric's avatar
aymeric committed
628 629
	err = AudioQueueEnqueueBuffer(d->writeQueue, inBuffer, 0, NULL);
	if (err != noErr) {
jehan's avatar
jehan committed
630
		ms_error("AudioQueueEnqueueBuffer %ld", err);
smorlat's avatar
smorlat committed
631
	}
aymeric's avatar
aymeric committed
632
	ms_mutex_unlock(&d->mutex);
smorlat's avatar
smorlat committed
633 634
}

aymeric's avatar
aymeric committed
635
void putWriteAQ(void *aqData, int queuenum)
smorlat's avatar
smorlat committed
636
{
aymeric's avatar
aymeric committed
637
	AQData *d = (AQData *) aqData;
smorlat's avatar
smorlat committed
638
	OSStatus err;
aymeric's avatar
aymeric committed
639 640 641
	err = AudioQueueEnqueueBuffer(d->writeQueue,
								  d->writeBuffers[queuenum], 0, NULL);
	if (err != noErr) {
jehan's avatar
jehan committed
642
		ms_error("AudioQueueEnqueueBuffer %ld", err);
smorlat's avatar
smorlat committed
643 644 645 646 647 648 649
	}
}

/*
 play buffer setup function
 */

aymeric's avatar
aymeric committed
650 651 652
void setupWrite(MSFilter * f)
{
	AQData *d = (AQData *) f->data;
smorlat's avatar
smorlat committed
653 654 655
	OSStatus err;

	int bufferIndex;
aymeric's avatar
aymeric committed
656 657 658 659 660 661 662 663 664

	for (bufferIndex = 0; bufferIndex < kNumberAudioOutDataBuffers;
		 ++bufferIndex) {

		err = AudioQueueAllocateBuffer(d->writeQueue,
									   d->writeBufferByteSize,
									   &d->writeBuffers[bufferIndex]
			);
		if (err != noErr) {
jehan's avatar
jehan committed
665
			ms_error("setupWrite:AudioQueueAllocateBuffer %ld", err);
smorlat's avatar
smorlat committed
666 667 668 669 670 671 672 673
		}
	}
}

/*
 recode buffer setup function
 */

aymeric's avatar
aymeric committed
674 675 676
void setupRead(MSFilter * f)
{
	AQData *d = (AQData *) f->data;
smorlat's avatar
smorlat committed
677 678 679 680 681
	OSStatus err;

	// allocate and enqueue buffers
	int bufferIndex;

aymeric's avatar
aymeric committed
682 683 684
	for (bufferIndex = 0; bufferIndex < kNumberAudioInDataBuffers;
		 ++bufferIndex) {

smorlat's avatar
smorlat committed
685
		AudioQueueBufferRef buffer;
aymeric's avatar
aymeric committed
686 687 688 689

		err = AudioQueueAllocateBuffer(d->readQueue,
									   d->readBufferByteSize, &buffer);
		if (err != noErr) {
jehan's avatar
jehan committed
690
			ms_error("setupRead:AudioQueueAllocateBuffer %ld", err);
smorlat's avatar
smorlat committed
691
		}
aymeric's avatar
aymeric committed
692 693 694

		err = AudioQueueEnqueueBuffer(d->readQueue, buffer, 0, NULL);
		if (err != noErr) {
jehan's avatar
jehan committed
695
			ms_error("AudioQueueEnqueueBuffer %ld", err);
smorlat's avatar
smorlat committed
696 697 698 699 700
		}
	}
}


aymeric's avatar
aymeric committed
701
static void aq_start_r(MSFilter * f)
smorlat's avatar
smorlat committed
702
{
aymeric's avatar
aymeric committed
703 704 705
	AQData *d = (AQData *) f->data;
	if (d->read_started == FALSE) {
		OSStatus aqresult;
smorlat's avatar
smorlat committed
706

aymeric's avatar
aymeric committed
707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726
		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;

727
#if 0
aymeric's avatar
aymeric committed
728 729 730 731 732 733 734
		aqresult = AudioConverterNew(&d->devicereadFormat,
									 &d->readAudioFormat,
									 &d->readAudioConverter);
		if (aqresult != noErr) {
			ms_error("d->readAudioConverter = %d", aqresult);
			d->readAudioConverter = NULL;
		}
735 736
#endif
		
aymeric's avatar
aymeric committed
737 738 739 740 741 742
		aqresult = AudioQueueNewInput(&d->devicereadFormat, readCallback, d,	// userData
									  NULL,	// run loop
									  NULL,	// run loop mode
									  0,	// flags
									  &d->readQueue);
		if (aqresult != noErr) {
jehan's avatar
jehan committed
743
			ms_error("AudioQueueNewInput = %ld", aqresult);
aymeric's avatar
aymeric committed
744
		}
smorlat's avatar
smorlat committed
745

746 747 748 749 750 751 752
		if (d->uidname!=NULL){
			char uidname[256];
			CFStringGetCString(d->uidname, uidname, 256,
							   CFStringGetSystemEncoding());
			ms_message("AQ: using uidname:%s", uidname);
			aqresult =
				AudioQueueSetProperty(d->readQueue,
aymeric's avatar
aymeric committed
753 754
								  kAudioQueueProperty_CurrentDevice,
								  &d->uidname, sizeof(CFStringRef));
755 756
			if (aqresult != noErr) {
				ms_error
jehan's avatar
jehan committed
757
					("AudioQueueSetProperty on kAudioQueueProperty_CurrentDevice %ld",
758 759
					 aqresult);
			}
aymeric's avatar
aymeric committed
760
		}
smorlat's avatar
smorlat committed
761

aymeric's avatar
aymeric committed
762
		setupRead(f);
Aymeric Moizard's avatar
Aymeric Moizard committed
763
		aqresult = AudioQueueStart(d->readQueue, NULL);	// start time. NULL means ASAP.
jehan's avatar
jehan committed
764 765 766
		check_aqresult(aqresult,"AudioQueueStart - read");
		if (aqresult == noErr) {
			d->read_started = TRUE;
aymeric's avatar
aymeric committed
767
		}
jehan's avatar
jehan committed
768
		
smorlat's avatar
smorlat committed
769 770 771
	}
}

aymeric's avatar
aymeric committed
772 773 774
static void aq_stop_r(MSFilter * f)
{
	AQData *d = (AQData *) f->data;
smorlat's avatar
smorlat committed
775

aymeric's avatar
aymeric committed
776 777 778 779
	if (d->read_started == TRUE) {
		ms_mutex_lock(&d->mutex);
		d->read_started = FALSE;	/* avoid a deadlock related to buffer conversion in callback  */
		ms_mutex_unlock(&d->mutex);
780
#if 0
aymeric's avatar
aymeric committed
781
		AudioConverterDispose(d->readAudioConverter);
782
#endif
aymeric's avatar
aymeric committed
783 784
		AudioQueueStop(d->readQueue, true);
		AudioQueueDispose(d->readQueue, true);
785 786 787 788

#if TARGET_OS_IPHONE
		check_aqresult(AudioSessionSetActive(false),"AudioSessionSetActive(false)");
#endif
smorlat's avatar
smorlat committed
789 790 791
	}
}

aymeric's avatar
aymeric committed
792 793 794 795
static void aq_start_w(MSFilter * f)
{
	AQData *d = (AQData *) f->data;
	if (d->write_started == FALSE) {
smorlat's avatar
smorlat committed
796
		OSStatus aqresult;
797 798 799 800 801 802 803 804 805 806 807
#if TARGET_OS_IPHONE
		aqresult = AudioSessionSetActive(true);
		check_aqresult(aqresult,"AudioSessionSetActive");
		
		UInt32 audioCategory;
		
		audioCategory= kAudioSessionCategory_AmbientSound;
		ms_message("Configuring audio session for play back");
		aqresult =AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(audioCategory), &audioCategory);
		check_aqresult(aqresult,"Configuring audio session ");
#endif
aymeric's avatar
aymeric committed
808 809 810 811 812 813 814 815 816 817
		d->writeAudioFormat.mSampleRate = d->rate;
		d->writeAudioFormat.mFormatID = kAudioFormatLinearPCM;
		d->writeAudioFormat.mFormatFlags =
			kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
		d->writeAudioFormat.mFramesPerPacket = 1;
		d->writeAudioFormat.mChannelsPerFrame = 1;
		d->writeAudioFormat.mBitsPerChannel = d->bits;
		d->writeAudioFormat.mBytesPerPacket = d->bits / 8;
		d->writeAudioFormat.mBytesPerFrame = d->bits / 8;

818 819
		//show_format("data provided to output filter",	&d->writeAudioFormat);
		//show_format("output device", &d->devicewriteFormat);
aymeric's avatar
aymeric committed
820 821 822 823 824 825 826 827

		memcpy(&d->devicewriteFormat, &d->writeAudioFormat,
			   sizeof(d->writeAudioFormat));
		d->writeBufferByteSize =
			kSecondsPerBuffer * d->devicewriteFormat.mSampleRate *
			(d->devicewriteFormat.mBitsPerChannel / 8) *
			d->devicewriteFormat.mChannelsPerFrame;

828
#if 0
aymeric's avatar
aymeric committed
829 830 831 832 833 834 835
		aqresult = AudioConverterNew(&d->writeAudioFormat,
									 &d->devicewriteFormat,
									 &d->writeAudioConverter);
		if (aqresult != noErr) {
			ms_error("d->writeAudioConverter = %d", aqresult);
			d->writeAudioConverter = NULL;
		}
836 837
#endif
		
smorlat's avatar
smorlat committed
838
		// create the playback audio queue object
aymeric's avatar
aymeric committed
839 840 841 842 843
		aqresult = AudioQueueNewOutput(&d->devicewriteFormat, writeCallback, d, NULL,	/*CFRunLoopGetCurrent () */
									   NULL,	/*kCFRunLoopCommonModes */
									   0,	// run loop flags
									   &d->writeQueue);
		if (aqresult != noErr) {
jehan's avatar
jehan committed
844
			ms_error("AudioQueueNewOutput = %ld", aqresult);
aymeric's avatar
aymeric committed
845 846
		}

847 848 849 850
		AudioQueueSetParameter (d->writeQueue,
					kAudioQueueParam_Volume,
					gain_volume_out);

851 852 853 854 855 856 857 858 859 860 861
		if (d->uidname!=NULL){
			char uidname[256];
			CFStringGetCString(d->uidname, uidname, 256,
							   CFStringGetSystemEncoding());
			ms_message("AQ: using uidname:%s", uidname);
			aqresult =
				AudioQueueSetProperty(d->writeQueue,
									  kAudioQueueProperty_CurrentDevice,
									  &d->uidname, sizeof(CFStringRef));
			if (aqresult != noErr) {
				ms_error
jehan's avatar
jehan committed
862
					("AudioQueueSetProperty on kAudioQueueProperty_CurrentDevice %ld",
863 864
					 aqresult);
			}
aymeric's avatar
aymeric committed
865
		}
Aymeric Moizard's avatar
Aymeric Moizard committed
866

aymeric's avatar
aymeric committed
867
		setupWrite(f);
smorlat's avatar
smorlat committed
868 869 870 871
		d->curWriteBuffer = 0;
	}
}

aymeric's avatar
aymeric committed
872 873 874 875 876 877 878
static void aq_stop_w(MSFilter * f)
{
	AQData *d = (AQData *) f->data;
	if (d->write_started == TRUE) {
		ms_mutex_lock(&d->mutex);
		d->write_started = FALSE;	/* avoid a deadlock related to buffer conversion in callback */
		ms_mutex_unlock(&d->mutex);
879
#if 0
aymeric's avatar
aymeric committed
880
		AudioConverterDispose(d->writeAudioConverter);
881
#endif
aymeric's avatar
aymeric committed
882 883 884
		AudioQueueStop(d->writeQueue, true);

		AudioQueueDispose(d->writeQueue, true);
885 886 887 888

#if TARGET_OS_IPHONE
		check_aqresult(AudioSessionSetActive(false),"AudioSessionSetActive(false)");
#endif
smorlat's avatar
smorlat committed
889 890 891
	}
}

aymeric's avatar
aymeric committed
892 893 894
static mblk_t *aq_get(MSFilter * f)
{
	AQData *d = (AQData *) f->data;
smorlat's avatar
smorlat committed
895 896
	mblk_t *m;
	ms_mutex_lock(&d->mutex);
aymeric's avatar
aymeric committed
897
	m = getq(&d->rq);
smorlat's avatar
smorlat committed
898 899 900 901
	ms_mutex_unlock(&d->mutex);
	return m;
}

aymeric's avatar
aymeric committed
902 903 904
static void aq_put(MSFilter * f, mblk_t * m)
{
	AQData *d = (AQData *) f->data;
smorlat's avatar
smorlat committed
905
	ms_mutex_lock(&d->mutex);
aymeric's avatar
aymeric committed
906
	ms_bufferizer_put(d->bufferizer, m);
smorlat's avatar
smorlat committed
907 908
	ms_mutex_unlock(&d->mutex);

aymeric's avatar
aymeric committed
909 910 911 912 913
	int len =
		(d->writeBufferByteSize * d->writeAudioFormat.mSampleRate / 1) /
		d->devicewriteFormat.mSampleRate /
		d->devicewriteFormat.mChannelsPerFrame;
	if (d->write_started == FALSE && d->bufferizer->size >= len) {
smorlat's avatar
smorlat committed
914
		AudioQueueBufferRef curbuf = d->writeBuffers[d->curWriteBuffer];
915
#if 0
aymeric's avatar
aymeric committed
916 917 918 919 920 921 922 923 924 925 926
		OSStatus err;
		UInt32 bsize = d->writeBufferByteSize;
		uint8_t *pData = ms_malloc(len);

		ms_bufferizer_read(d->bufferizer, pData, len);
		err = AudioConverterConvertBuffer(d->writeAudioConverter,
										  len,
										  pData,
										  &bsize, curbuf->mAudioData);
		if (err != noErr) {
			ms_error("writeCallback: AudioConverterConvertBuffer %d", err);
smorlat's avatar
smorlat committed
927
		}
aymeric's avatar
aymeric committed
928 929 930 931 932
		ms_free(pData);

		if (bsize != d->writeBufferByteSize)
			ms_warning("d->writeBufferByteSize = %i len = %i bsize = %i",
					   d->writeBufferByteSize, len, bsize);
933 934 935
#else
		ms_bufferizer_read(d->bufferizer, curbuf->mAudioData, len);
#endif
aymeric's avatar
aymeric committed
936 937 938
		curbuf->mAudioDataByteSize = d->writeBufferByteSize;
		putWriteAQ(d, d->curWriteBuffer);
		++d->curWriteBuffer;
smorlat's avatar
smorlat committed
939
	}
aymeric's avatar
aymeric committed
940 941
	if (d->write_started == FALSE
		&& d->curWriteBuffer == kNumberAudioOutDataBuffers - 1) {
smorlat's avatar
smorlat committed
942
		OSStatus err;
aymeric's avatar
aymeric committed
943 944
		err = AudioQueueStart(d->writeQueue, NULL	// start time. NULL means ASAP.
			);
jehan's avatar
jehan committed
945 946 947 948 949
		check_aqresult(err, "AudioQueueStart -write-");
		if (err == noErr) {
			d->write_started = TRUE;		
		} 
		
Aymeric Moizard's avatar
Aymeric Moizard committed
950

smorlat's avatar
smorlat committed
951 952 953
	}
}

aymeric's avatar
aymeric committed
954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982
static void aq_init(MSFilter * f)
{
	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);
	f->data = d;
}

static void aq_uninit(MSFilter * f)
{
	AQData *d = (AQData *) f->data;
	flushq(&d->rq, 0);
	ms_bufferizer_destroy(d->bufferizer);
	ms_mutex_destroy(&d->mutex);
	if (d->uidname != NULL)
		CFRelease(d->uidname);
	ms_free(d);
}

static void aq_read_preprocess(MSFilter * f)
{
	aq_start_r(f);
smorlat's avatar
smorlat committed
983 984
}

aymeric's avatar
aymeric committed
985 986 987
static void aq_read_postprocess(MSFilter * f)
{
	aq_stop_r(f);
smorlat's avatar
smorlat committed
988 989
}

aymeric's avatar
aymeric committed
990 991
static void aq_read_process(MSFilter * f)
{
smorlat's avatar
smorlat committed
992
	mblk_t *m;
aymeric's avatar
aymeric committed
993 994
	while ((m = aq_get(f)) != NULL) {
		ms_queue_put(f->outputs[0], m);
smorlat's avatar
smorlat committed
995 996 997
	}
}

aymeric's avatar
aymeric committed
998 999 1000
static void aq_write_preprocess(MSFilter * f)
{
	aq_start_w(f);
smorlat's avatar
smorlat committed
1001 1002
}

aymeric's avatar
aymeric committed
1003 1004 1005
static void aq_write_postprocess(MSFilter * f)
{
	aq_stop_w(f);
smorlat's avatar
smorlat committed
1006 1007
}

aymeric's avatar
aymeric committed
1008 1009
static void aq_write_process(MSFilter * f)
{
smorlat's avatar
smorlat committed
1010
	mblk_t *m;
aymeric's avatar
aymeric committed
1011 1012
	while ((m = ms_queue_get(f->inputs[0])) != NULL) {
		aq_put(f, m);
smorlat's avatar
smorlat committed
1013 1014 1015
	}
}

aymeric's avatar
aymeric committed
1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026
static int set_rate(MSFilter * f, void *arg)
{
	AQData *d = (AQData *) f->data;
	d->rate = *((int *) arg);
	return 0;
}

static int read_get_rate(MSFilter * f, void *arg)
{
	AQData *d = (AQData *) f->data;
	*((int *) arg) = d->rate;
smorlat's avatar
smorlat committed
1027 1028
	return 0;
}
aymeric's avatar
aymeric committed
1029 1030 1031 1032 1033 1034 1035 1036

static int write_get_rate(MSFilter * f, void *arg)
{
	AQData *d = (AQData *) f->data;
	*((int *) arg) = d->rate;
	return 0;
}

smorlat's avatar
smorlat committed
1037
/*
smorlat's avatar
smorlat committed
1038
static int set_nchannels(MSFilter *f, void *arg){
aymeric's avatar
aymeric committed
1039
	AQData *d=(AQData*)f->data;
smorlat's avatar
smorlat committed
1040 1041 1042
	d->stereo=(*((int*)arg)==2);
	return 0;
}
smorlat's avatar
smorlat committed
1043
*/
aymeric's avatar
aymeric committed
1044 1045 1046 1047

static MSFilterMethod aq_read_methods[] = {
	{MS_FILTER_SET_SAMPLE_RATE, set_rate},
	{MS_FILTER_GET_SAMPLE_RATE, read_get_rate},
smorlat's avatar
smorlat committed
1048 1049 1050
/* not support yet
	{	MS_FILTER_SET_NCHANNELS		, set_nchannels	},
*/
aymeric's avatar
aymeric committed
1051
	{0, NULL}
smorlat's avatar
smorlat committed
1052 1053
};

aymeric's avatar
aymeric committed
1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066
MSFilterDesc aq_read_desc = {
	.id = MS_AQ_READ_ID,
	.name = "MSAQRead",
	.text = N_("Sound capture filter for MacOS X Audio Queue Service"),
	.category = MS_FILTER_OTHER,
	.ninputs = 0,
	.noutputs = 1,
	.init = aq_init,
	.preprocess = aq_read_preprocess,
	.process = aq_read_process,
	.postprocess = aq_read_postprocess,
	.uninit = aq_uninit,
	.methods = aq_read_methods
smorlat's avatar
smorlat committed
1067 1068
};

aymeric's avatar
aymeric committed
1069 1070 1071 1072 1073 1074 1075 1076
static MSFilterMethod aq_write_methods[] = {
	{MS_FILTER_SET_SAMPLE_RATE, set_rate},
	{MS_FILTER_GET_SAMPLE_RATE, write_get_rate},
/* not support yet
	{	MS_FILTER_SET_NCHANNELS		, set_nchannels	},
*/
	{0, NULL}
};
smorlat's avatar
smorlat committed
1077

aymeric's avatar
aymeric committed
1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090
MSFilterDesc aq_write_desc = {
	.id = MS_AQ_WRITE_ID,
	.name = "MSAQWrite",
	.text = N_("Sound playback filter for MacOS X Audio Queue Service"),
	.category = MS_FILTER_OTHER,
	.ninputs = 1,
	.noutputs = 0,
	.init = aq_init,
	.preprocess = aq_write_preprocess,
	.process = aq_write_process,
	.postprocess = aq_write_postprocess,
	.uninit = aq_uninit,
	.methods = aq_write_methods
smorlat's avatar
smorlat committed
1091 1092
};

aymeric's avatar
aymeric committed
1093 1094 1095 1096 1097
MSFilter *ms_aq_read_new(MSSndCard * card)
{
	MSFilter *f = ms_filter_new_from_desc(&aq_read_desc);
	AqSndDsCard *wc = (AqSndDsCard *) card->data;
	AQData *d = (AQData *) f->data;
1098 1099 1100
	d->uidname = NULL;
	if (wc->uidname != NULL)
		d->uidname = CFStringCreateCopy(NULL, wc->uidname);
aymeric's avatar
aymeric committed
1101 1102 1103 1104
	memcpy(&d->devicereadFormat, &wc->devicereadFormat,
		   sizeof(AudioStreamBasicDescription));
	memcpy(&d->devicewriteFormat, &wc->devicewriteFormat,
		   sizeof(AudioStreamBasicDescription));
smorlat's avatar
smorlat committed
1105 1106 1107 1108
	return f;
}


aymeric's avatar
aymeric committed
1109 1110 1111 1112 1113
MSFilter *ms_aq_write_new(MSSndCard * card)
{
	MSFilter *f = ms_filter_new_from_desc(&aq_write_desc);
	AqSndDsCard *wc = (AqSndDsCard *) card->data;
	AQData *d = (AQData *) f->data;
1114 1115 1116
	d->uidname = NULL;
	if (wc->uidname != NULL)
		d->uidname = CFStringCreateCopy(NULL, wc->uidname);
aymeric's avatar
aymeric committed
1117 1118 1119 1120
	memcpy(&d->devicereadFormat, &wc->devicereadFormat,
		   sizeof(AudioStreamBasicDescription));
	memcpy(&d->devicewriteFormat, &wc->devicewriteFormat,
		   sizeof(AudioStreamBasicDescription));
smorlat's avatar
smorlat committed
1121 1122 1123 1124 1125
	return f;
}

MS_FILTER_DESC_EXPORT(aq_read_desc)
MS_FILTER_DESC_EXPORT(aq_write_desc)