aqsnd.c 29.1 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"

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

79
#ifdef __ios
80 81 82 83
#define CFStringRef void *
#define CFRelease(A) {}
#define CFStringGetCString(A, B, LEN, encoding)  {}
#define CFStringCreateCopy(A, B) NULL
84 85
#define check_aqresult(aq,method) \
if (aq!=0) ms_error("AudioQueue error for %s: ret=%li",method,aq)
86 87
#endif

88 89 90 91 92 93 94 95 96 97 98 99 100
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;
101
#if 0
102
	AudioConverterRef readAudioConverter;
103
#endif
104 105 106 107
	AudioQueueRef readQueue;
	AudioStreamBasicDescription readAudioFormat;
	UInt32 readBufferByteSize;

108
#if 0
109
	AudioConverterRef writeAudioConverter;
110
#endif
111 112 113 114 115 116
	AudioQueueRef writeQueue;
	AudioStreamBasicDescription writeAudioFormat;
	UInt32 writeBufferByteSize;
	AudioQueueBufferRef writeBuffers[kNumberAudioOutDataBuffers];
	int curWriteBuffer;
	MSBufferizer *bufferizer;
smorlat's avatar
smorlat committed
117 118
} AQData;

119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134


/*
 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)
{
135 136 137 138 139 140 141 142 143 144 145 146 147
	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.");
	}
148 149 150 151
}

static int aqcard_get_level(MSSndCard * card, MSSndCardMixerElem e)
{
152 153 154 155 156 157 158 159 160 161
	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;
162 163 164 165 166 167 168 169
}

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

static void aqcard_init(MSSndCard * card)
{
170
	AqSndDsCard *c = (AqSndDsCard *) ms_new0(AqSndDsCard, 1);
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
	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)
{
203 204
	AqSndDsCard *ca;
	AqSndDsCard *cadup;
205 206
	MSSndCard *card = ms_snd_card_new(&aq_card_desc);
	card->name = ms_strdup(obj->name);
207
	card->data = ms_new0(AqSndDsCard, 1);
208
	memcpy(card->data, obj->data, sizeof(AqSndDsCard));
209 210 211
	ca = obj->data;
	cadup = card->data;
	cadup->uidname = CFStringCreateCopy(NULL, ca->uidname);
212 213 214 215 216 217 218 219 220 221 222 223
	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;
224 225 226 227 228 229
	if (devicereadFormat!=NULL)
	  memcpy(&d->devicereadFormat, devicereadFormat,
		 sizeof(AudioStreamBasicDescription));
	if (devicewriteFormat!=NULL)
	  memcpy(&d->devicewriteFormat, devicewriteFormat,
		 sizeof(AudioStreamBasicDescription));
230 231 232 233 234 235 236 237
	card->name = ms_strdup(name);
	card->capabilities = cap;
	return card;
}

static void show_format(char *name,
						AudioStreamBasicDescription * deviceFormat)
{
238 239
	ms_message("Format for %s", name);
	ms_message("mSampleRate = %g", deviceFormat->mSampleRate);
240 241 242 243 244 245 246
	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;
247 248 249 250 251 252 253
	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);
254 255 256 257
}

static void aqcard_detect(MSSndCardManager * m)
{
258
#ifdef __ios
259 260 261 262
	AudioStreamBasicDescription deviceFormat;
	memset(&deviceFormat, 0, sizeof(AudioStreamBasicDescription));
	
	MSSndCard *card = aq_card_new("Audio Queue Device", NULL, &deviceFormat,
263
								  &deviceFormat, MS_SND_CARD_CAP_PLAYBACK/*|MS_SND_CARD_CAP_CAPTURE*/);
264 265
	ms_snd_card_manager_add_card(m, card);
#else
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
	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++) {
289 290 291 292
		char devname_in[256];
		char uidname_in[256];
		char devname_out[256];
		char uidname_out[256];
293
		int cap = 0;
294 295

		/* OUTPUT CARDS */
296 297 298 299
		slen = 256;
		err =
			AudioDeviceGetProperty(V[i], 0, FALSE,
								   kAudioDevicePropertyDeviceName, &slen,
300
								   devname_out);
301 302 303 304
		if (err != kAudioHardwareNoError) {
			ms_error("get kAudioDevicePropertyDeviceName error %ld", err);
			continue;
		}
305
		slen = strlen(devname_out);
306
		/* trim whitespace */
307
		while ((slen > 0) && (devname_out[slen - 1] == ' ')) {
308 309
			slen--;
		}
310
		devname_out[slen] = '\0';
311 312 313 314 315 316 317 318 319

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

Aymeric Moizard's avatar
Aymeric Moizard committed
321
		AudioBufferList *buflist = ms_malloc(slen);
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346
		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);

347 348 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
		/* 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;
		}


374 375 376 377 378 379 380 381
		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
382
		buflist = ms_malloc(slen);
383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
		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);

407 408 409 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 (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);
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 461 462 463
		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);
		}
464
	}
465
#endif
466 467 468
}


smorlat's avatar
smorlat committed
469 470 471 472
/*
 Audio Queue recode callback
 */

473 474 475 476 477 478 479 480
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
481
	OSStatus err;
482 483 484 485 486 487
	mblk_t *rm = NULL;

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

	ms_mutex_lock(&d->mutex);
490 491 492 493 494 495 496
	if (d->read_started == FALSE) {
		ms_mutex_unlock(&d->mutex);
		return;
	}

	rm = allocb(len, 0);

497
#if 0
498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513
	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 {
514 515 516 517 518 519 520 521 522 523 524

	  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);
525
	}
526 527 528 529 530 531 532 533 534 535 536 537 538 539
#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
	
540 541
	err = AudioQueueEnqueueBuffer(d->readQueue, inBuffer, 0, NULL);
	if (err != noErr) {
smorlat's avatar
smorlat committed
542 543
		ms_error("readCallback:AudioQueueEnqueueBuffer %d", err);
	}
544
	ms_mutex_unlock(&d->mutex);
smorlat's avatar
smorlat committed
545 546 547 548 549 550
}

/*
 Audio Queue play callback
 */

551 552 553 554
static void writeCallback(void *aqData,
						  AudioQueueRef inAQ, AudioQueueBufferRef inBuffer)
{
	AQData *d = (AQData *) aqData;
smorlat's avatar
smorlat committed
555
	OSStatus err;
556 557

	int len =
558
		(d->writeBufferByteSize * d->writeAudioFormat.mSampleRate / 1) /
559 560 561 562 563
		d->devicewriteFormat.mSampleRate /
		d->devicewriteFormat.mChannelsPerFrame;

	ms_mutex_lock(&d->mutex);
	if (d->write_started == FALSE) {
smorlat's avatar
smorlat committed
564
		ms_mutex_unlock(&d->mutex);
565 566 567
		return;
	}
	if (d->bufferizer->size >= len) {
568
#if 0
569 570 571 572 573 574 575 576 577 578 579 580
		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
581

582 583 584
		if (bsize != d->writeBufferByteSize)
			ms_warning("d->writeBufferByteSize = %i len = %i bsize = %i",
					   d->writeBufferByteSize, len, bsize);
585 586 587
#else
		ms_bufferizer_read(d->bufferizer, inBuffer->mAudioData, len);
#endif
smorlat's avatar
smorlat committed
588 589 590 591
	} else {
		memset(inBuffer->mAudioData, 0, d->writeBufferByteSize);
	}
	inBuffer->mAudioDataByteSize = d->writeBufferByteSize;
592 593 594 595 596 597 598 599 600

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

601 602
	err = AudioQueueEnqueueBuffer(d->writeQueue, inBuffer, 0, NULL);
	if (err != noErr) {
smorlat's avatar
smorlat committed
603 604
		ms_error("AudioQueueEnqueueBuffer %d", err);
	}
605
	ms_mutex_unlock(&d->mutex);
smorlat's avatar
smorlat committed
606 607
}

608
void putWriteAQ(void *aqData, int queuenum)
smorlat's avatar
smorlat committed
609
{
610
	AQData *d = (AQData *) aqData;
smorlat's avatar
smorlat committed
611
	OSStatus err;
612 613 614
	err = AudioQueueEnqueueBuffer(d->writeQueue,
								  d->writeBuffers[queuenum], 0, NULL);
	if (err != noErr) {
smorlat's avatar
smorlat committed
615 616 617 618 619 620 621 622
		ms_error("AudioQueueEnqueueBuffer %d", err);
	}
}

/*
 play buffer setup function
 */

623 624 625
void setupWrite(MSFilter * f)
{
	AQData *d = (AQData *) f->data;
smorlat's avatar
smorlat committed
626 627 628
	OSStatus err;

	int bufferIndex;
629 630 631 632 633 634 635 636 637

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

		err = AudioQueueAllocateBuffer(d->writeQueue,
									   d->writeBufferByteSize,
									   &d->writeBuffers[bufferIndex]
			);
		if (err != noErr) {
smorlat's avatar
smorlat committed
638 639 640 641 642 643 644 645 646
			ms_error("setupWrite:AudioQueueAllocateBuffer %d", err);
		}
	}
}

/*
 recode buffer setup function
 */

647 648 649
void setupRead(MSFilter * f)
{
	AQData *d = (AQData *) f->data;
smorlat's avatar
smorlat committed
650 651 652 653 654
	OSStatus err;

	// allocate and enqueue buffers
	int bufferIndex;

655 656 657
	for (bufferIndex = 0; bufferIndex < kNumberAudioInDataBuffers;
		 ++bufferIndex) {

smorlat's avatar
smorlat committed
658
		AudioQueueBufferRef buffer;
659 660 661 662

		err = AudioQueueAllocateBuffer(d->readQueue,
									   d->readBufferByteSize, &buffer);
		if (err != noErr) {
smorlat's avatar
smorlat committed
663 664
			ms_error("setupRead:AudioQueueAllocateBuffer %d", err);
		}
665 666 667

		err = AudioQueueEnqueueBuffer(d->readQueue, buffer, 0, NULL);
		if (err != noErr) {
smorlat's avatar
smorlat committed
668 669 670 671 672 673
			ms_error("AudioQueueEnqueueBuffer %d", err);
		}
	}
}


674
static void aq_start_r(MSFilter * f)
smorlat's avatar
smorlat committed
675
{
676 677 678
	AQData *d = (AQData *) f->data;
	if (d->read_started == FALSE) {
		OSStatus aqresult;
smorlat's avatar
smorlat committed
679

680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699
		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;

700
#if 0
701 702 703 704 705 706 707
		aqresult = AudioConverterNew(&d->devicereadFormat,
									 &d->readAudioFormat,
									 &d->readAudioConverter);
		if (aqresult != noErr) {
			ms_error("d->readAudioConverter = %d", aqresult);
			d->readAudioConverter = NULL;
		}
708 709
#endif
		
710 711 712 713 714 715 716 717
		aqresult = AudioQueueNewInput(&d->devicereadFormat, readCallback, d,	// userData
									  NULL,	// run loop
									  NULL,	// run loop mode
									  0,	// flags
									  &d->readQueue);
		if (aqresult != noErr) {
			ms_error("AudioQueueNewInput = %d", aqresult);
		}
smorlat's avatar
smorlat committed
718

719 720 721 722 723 724 725
		if (d->uidname!=NULL){
			char uidname[256];
			CFStringGetCString(d->uidname, uidname, 256,
							   CFStringGetSystemEncoding());
			ms_message("AQ: using uidname:%s", uidname);
			aqresult =
				AudioQueueSetProperty(d->readQueue,
726 727
								  kAudioQueueProperty_CurrentDevice,
								  &d->uidname, sizeof(CFStringRef));
728 729 730 731 732
			if (aqresult != noErr) {
				ms_error
					("AudioQueueSetProperty on kAudioQueueProperty_CurrentDevice %d",
					 aqresult);
			}
733
		}
smorlat's avatar
smorlat committed
734

735
		setupRead(f);
Aymeric Moizard's avatar
Aymeric Moizard committed
736
		aqresult = AudioQueueStart(d->readQueue, NULL);	// start time. NULL means ASAP.
737
		if (aqresult != noErr) {
738
			ms_error("AudioQueueStart -read- %d", aqresult);
739
		}
smorlat's avatar
smorlat committed
740 741 742 743
		d->read_started = TRUE;
	}
}

744 745 746
static void aq_stop_r(MSFilter * f)
{
	AQData *d = (AQData *) f->data;
smorlat's avatar
smorlat committed
747

748 749 750 751
	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);
752
#if 0
753
		AudioConverterDispose(d->readAudioConverter);
754
#endif
755 756
		AudioQueueStop(d->readQueue, true);
		AudioQueueDispose(d->readQueue, true);
smorlat's avatar
smorlat committed
757 758 759
	}
}

760 761 762 763
static void aq_start_w(MSFilter * f)
{
	AQData *d = (AQData *) f->data;
	if (d->write_started == FALSE) {
smorlat's avatar
smorlat committed
764
		OSStatus aqresult;
765 766 767 768 769 770 771 772 773 774 775
#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
776 777 778 779 780 781 782 783 784 785
		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;

786 787
		//show_format("data provided to output filter",	&d->writeAudioFormat);
		//show_format("output device", &d->devicewriteFormat);
788 789 790 791 792 793 794 795

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

796
#if 0
797 798 799 800 801 802 803
		aqresult = AudioConverterNew(&d->writeAudioFormat,
									 &d->devicewriteFormat,
									 &d->writeAudioConverter);
		if (aqresult != noErr) {
			ms_error("d->writeAudioConverter = %d", aqresult);
			d->writeAudioConverter = NULL;
		}
804 805
#endif
		
smorlat's avatar
smorlat committed
806
		// create the playback audio queue object
807 808 809 810 811 812 813 814
		aqresult = AudioQueueNewOutput(&d->devicewriteFormat, writeCallback, d, NULL,	/*CFRunLoopGetCurrent () */
									   NULL,	/*kCFRunLoopCommonModes */
									   0,	// run loop flags
									   &d->writeQueue);
		if (aqresult != noErr) {
			ms_error("AudioQueueNewOutput = %d", aqresult);
		}

815 816 817 818
		AudioQueueSetParameter (d->writeQueue,
					kAudioQueueParam_Volume,
					gain_volume_out);

819 820 821 822 823 824 825 826 827 828 829 830 831 832
		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
					("AudioQueueSetProperty on kAudioQueueProperty_CurrentDevice %d",
					 aqresult);
			}
833
		}
Aymeric Moizard's avatar
Aymeric Moizard committed
834

835
		setupWrite(f);
smorlat's avatar
smorlat committed
836 837 838 839
		d->curWriteBuffer = 0;
	}
}

840 841 842 843 844 845 846
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);
847
#if 0
848
		AudioConverterDispose(d->writeAudioConverter);
849
#endif
850 851 852
		AudioQueueStop(d->writeQueue, true);

		AudioQueueDispose(d->writeQueue, true);
smorlat's avatar
smorlat committed
853 854 855
	}
}

856 857 858
static mblk_t *aq_get(MSFilter * f)
{
	AQData *d = (AQData *) f->data;
smorlat's avatar
smorlat committed
859 860
	mblk_t *m;
	ms_mutex_lock(&d->mutex);
861
	m = getq(&d->rq);
smorlat's avatar
smorlat committed
862 863 864 865
	ms_mutex_unlock(&d->mutex);
	return m;
}

866 867 868
static void aq_put(MSFilter * f, mblk_t * m)
{
	AQData *d = (AQData *) f->data;
smorlat's avatar
smorlat committed
869
	ms_mutex_lock(&d->mutex);
870
	ms_bufferizer_put(d->bufferizer, m);
smorlat's avatar
smorlat committed
871 872
	ms_mutex_unlock(&d->mutex);

873 874 875 876 877
	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
878
		AudioQueueBufferRef curbuf = d->writeBuffers[d->curWriteBuffer];
879
#if 0
880 881 882 883 884 885 886 887 888 889 890
		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
891
		}
892 893 894 895 896
		ms_free(pData);

		if (bsize != d->writeBufferByteSize)
			ms_warning("d->writeBufferByteSize = %i len = %i bsize = %i",
					   d->writeBufferByteSize, len, bsize);
897 898 899
#else
		ms_bufferizer_read(d->bufferizer, curbuf->mAudioData, len);
#endif
900 901 902
		curbuf->mAudioDataByteSize = d->writeBufferByteSize;
		putWriteAQ(d, d->curWriteBuffer);
		++d->curWriteBuffer;
smorlat's avatar
smorlat committed
903
	}
904 905
	if (d->write_started == FALSE
		&& d->curWriteBuffer == kNumberAudioOutDataBuffers - 1) {
smorlat's avatar
smorlat committed
906
		OSStatus err;
907 908 909
		err = AudioQueueStart(d->writeQueue, NULL	// start time. NULL means ASAP.
			);
		if (err != noErr) {
910
			ms_error("AudioQueueStart -write- %d", err);
911
		}
smorlat's avatar
smorlat committed
912
		d->write_started = TRUE;
Aymeric Moizard's avatar
Aymeric Moizard committed
913

smorlat's avatar
smorlat committed
914 915 916
	}
}

917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945
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
946 947
}

948 949 950
static void aq_read_postprocess(MSFilter * f)
{
	aq_stop_r(f);
smorlat's avatar
smorlat committed
951 952
}

953 954
static void aq_read_process(MSFilter * f)
{
smorlat's avatar
smorlat committed
955
	mblk_t *m;
956 957
	while ((m = aq_get(f)) != NULL) {
		ms_queue_put(f->outputs[0], m);
smorlat's avatar
smorlat committed
958 959 960
	}
}

961 962 963
static void aq_write_preprocess(MSFilter * f)
{
	aq_start_w(f);
smorlat's avatar
smorlat committed
964 965
}

966 967 968
static void aq_write_postprocess(MSFilter * f)
{
	aq_stop_w(f);
smorlat's avatar
smorlat committed
969 970
}

971 972
static void aq_write_process(MSFilter * f)
{
smorlat's avatar
smorlat committed
973
	mblk_t *m;
974 975
	while ((m = ms_queue_get(f->inputs[0])) != NULL) {
		aq_put(f, m);
smorlat's avatar
smorlat committed
976 977 978
	}
}

979 980 981 982 983 984 985 986 987 988 989
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
990 991
	return 0;
}
992 993 994 995 996 997 998 999

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

1000
/*
smorlat's avatar
smorlat committed
1001
static int set_nchannels(MSFilter *f, void *arg){
1002
	AQData *d=(AQData*)f->data;
smorlat's avatar
smorlat committed
1003 1004 1005
	d->stereo=(*((int*)arg)==2);
	return 0;
}
1006
*/
1007 1008 1009 1010

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
1011 1012 1013
/* not support yet
	{	MS_FILTER_SET_NCHANNELS		, set_nchannels	},
*/
1014
	{0, NULL}
smorlat's avatar
smorlat committed
1015 1016
};

1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029
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
1030 1031
};

1032 1033 1034 1035 1036 1037 1038 1039
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
1040

1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053
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
1054 1055
};

1056 1057 1058 1059 1060
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;
1061 1062 1063
	d->uidname = NULL;
	if (wc->uidname != NULL)
		d->uidname = CFStringCreateCopy(NULL, wc->uidname);
1064 1065 1066 1067
	memcpy(&d->devicereadFormat, &wc->devicereadFormat,
		   sizeof(AudioStreamBasicDescription));
	memcpy(&d->devicewriteFormat, &wc->devicewriteFormat,
		   sizeof(AudioStreamBasicDescription));
smorlat's avatar
smorlat committed
1068 1069 1070 1071
	return f;
}


1072 1073 1074 1075 1076
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;
1077 1078 1079
	d->uidname = NULL;
	if (wc->uidname != NULL)
		d->uidname = CFStringCreateCopy(NULL, wc->uidname);
1080 1081 1082 1083
	memcpy(&d->devicereadFormat, &wc->devicereadFormat,
		   sizeof(AudioStreamBasicDescription));
	memcpy(&d->devicewriteFormat, &wc->devicewriteFormat,
		   sizeof(AudioStreamBasicDescription));
smorlat's avatar
smorlat committed
1084 1085 1086 1087 1088
	return f;
}

MS_FILTER_DESC_EXPORT(aq_read_desc)
MS_FILTER_DESC_EXPORT(aq_write_desc)