2 mediastreamer2 library - modular sound and video processing and streaming
3 Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org)
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 /* this file is specifically distributed under a BSD license */
23 * Copyright (C) 2008 Hiroki Mori (himori@users.sourceforge.net)
24 * All rights reserved.
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions are met:
28 * * Redistributions of source code must retain the above copyright
29 * notice, this list of conditions and the following disclaimer.
30 * * Redistributions in binary form must reproduce the above copyright
31 * notice, this list of conditions and the following disclaimer in the
32 * documentation and/or other materials provided with the distribution.
33 * * Neither the name of the <organization> nor the
34 * names of its contributors may be used to endorse or promote products
35 * derived from this software without specific prior written permission.
37 * THIS SOFTWARE IS PROVIDED BY <copyright holder> ``AS IS'' AND ANY
38 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
39 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40 * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
41 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
42 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
43 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
45 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
46 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
50 This is MacOS X Audio Queue Service support code for mediastreamer2.
51 Audio Queue Support MacOS X 10.5 or later.
52 http://developer.apple.com/documentation/MusicAudio/Conceptual/AudioQueueProgrammingGuide/
55 #include <AudioToolbox/AudioToolbox.h>
56 #if (!defined(__AudioHardware_h__) & !defined(__IPHONE_3_0))
57 #include "AudioHardware.h"
60 #include "mediastreamer2/mssndcard.h"
61 #include "mediastreamer2/msfilter.h"
63 MSFilter *ms_aq_read_new(MSSndCard * card);
64 MSFilter *ms_aq_write_new(MSSndCard * card);
66 #define kSecondsPerBuffer 0.02 /*0.04 */
67 #define kNumberAudioOutDataBuffers 4
68 #define kNumberAudioInDataBuffers 4
70 float gain_volume_in=1.0;
71 float gain_volume_out=1.0;
72 bool gain_changed_in = true;
73 bool gain_changed_out = true;
75 typedef struct AQData {
77 AudioStreamBasicDescription devicereadFormat;
78 AudioStreamBasicDescription devicewriteFormat;
89 AudioConverterRef readAudioConverter;
90 AudioQueueRef readQueue;
91 AudioStreamBasicDescription readAudioFormat;
92 UInt32 readBufferByteSize;
94 AudioConverterRef writeAudioConverter;
95 AudioQueueRef writeQueue;
96 AudioStreamBasicDescription writeAudioFormat;
97 UInt32 writeBufferByteSize;
98 AudioQueueBufferRef writeBuffers[kNumberAudioOutDataBuffers];
100 MSBufferizer *bufferizer;
106 mediastreamer2 function
109 typedef struct AqSndDsCard {
111 AudioStreamBasicDescription devicereadFormat;
112 AudioStreamBasicDescription devicewriteFormat;
116 static void aqcard_set_level(MSSndCard * card, MSSndCardMixerElem e,
120 case MS_SND_CARD_PLAYBACK:
121 case MS_SND_CARD_MASTER:
122 gain_volume_out =((float)percent)/100.0f;
123 gain_changed_out = true;
125 case MS_SND_CARD_CAPTURE:
126 gain_volume_in =((float)percent)/100.0f;
127 gain_changed_in = true;
130 ms_warning("aqcard_set_level: unsupported command.");
134 static int aqcard_get_level(MSSndCard * card, MSSndCardMixerElem e)
137 case MS_SND_CARD_PLAYBACK:
138 case MS_SND_CARD_MASTER:
141 return (int)(gain_volume_out*100.0f);
142 case MS_SND_CARD_CAPTURE:
143 return (int)(gain_volume_in*100.0f);
145 ms_warning("aqcard_get_level: unsupported command.");
150 static void aqcard_set_source(MSSndCard * card, MSSndCardCapture source)
154 static void aqcard_init(MSSndCard * card)
156 AqSndDsCard *c = (AqSndDsCard *) ms_new(AqSndDsCard, 1);
161 static void aqcard_uninit(MSSndCard * card)
163 AqSndDsCard *d = (AqSndDsCard *) card->data;
164 if (d->uidname != NULL)
165 CFRelease(d->uidname);
169 static void aqcard_detect(MSSndCardManager * m);
170 static MSSndCard *aqcard_duplicate(MSSndCard * obj);
172 MSSndCardDesc aq_card_desc = {
174 .detect = aqcard_detect,
176 .set_level = aqcard_set_level,
177 .get_level = aqcard_get_level,
178 .set_capture = aqcard_set_source,
181 .create_reader = ms_aq_read_new,
182 .create_writer = ms_aq_write_new,
183 .uninit = aqcard_uninit,
184 .duplicate = aqcard_duplicate
187 static MSSndCard *aqcard_duplicate(MSSndCard * obj)
189 MSSndCard *card = ms_snd_card_new(&aq_card_desc);
190 card->name = ms_strdup(obj->name);
191 card->data = ms_new(AqSndDsCard, 1);
192 memcpy(card->data, obj->data, sizeof(AqSndDsCard));
196 static MSSndCard *aq_card_new(const char *name, CFStringRef uidname,
197 AudioStreamBasicDescription *
199 AudioStreamBasicDescription *
200 devicewriteFormat, unsigned cap)
202 MSSndCard *card = ms_snd_card_new(&aq_card_desc);
203 AqSndDsCard *d = (AqSndDsCard *) card->data;
204 d->uidname = uidname;
205 memcpy(&d->devicereadFormat, devicereadFormat,
206 sizeof(AudioStreamBasicDescription));
207 memcpy(&d->devicewriteFormat, devicewriteFormat,
208 sizeof(AudioStreamBasicDescription));
209 card->name = ms_strdup(name);
210 card->capabilities = cap;
214 static void show_format(char *name,
215 AudioStreamBasicDescription * deviceFormat)
217 ms_debug("Format for %s", name);
218 ms_debug("mSampleRate = %g", deviceFormat->mSampleRate);
219 char *the4CCString = (char *) &deviceFormat->mFormatID;
221 outName[0] = the4CCString[0];
222 outName[1] = the4CCString[1];
223 outName[2] = the4CCString[2];
224 outName[3] = the4CCString[3];
226 ms_debug("mFormatID = %s", outName);
227 ms_debug("mFormatFlags = %08lX", deviceFormat->mFormatFlags);
228 ms_debug("mBytesPerPacket = %ld", deviceFormat->mBytesPerPacket);
229 ms_debug("mFramesPerPacket = %ld", deviceFormat->mFramesPerPacket);
230 ms_debug("mChannelsPerFrame = %ld", deviceFormat->mChannelsPerFrame);
231 ms_debug("mBytesPerFrame = %ld", deviceFormat->mBytesPerFrame);
232 ms_debug("mBitsPerChannel = %ld", deviceFormat->mBitsPerChannel);
235 static void aqcard_detect(MSSndCardManager * m)
245 AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &slen,
247 if (err != kAudioHardwareNoError) {
248 ms_error("get kAudioHardwarePropertyDevices error %ld", err);
251 AudioDeviceID V[slen / sizeof(AudioDeviceID)];
253 AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &slen, V);
254 if (err != kAudioHardwareNoError) {
255 ms_error("get kAudioHardwarePropertyDevices error %ld", err);
258 count = slen / sizeof(AudioDeviceID);
259 for (i = 0; i < count; i++) {
265 AudioDeviceGetProperty(V[i], 0, FALSE,
266 kAudioDevicePropertyDeviceName, &slen,
268 if (err != kAudioHardwareNoError) {
269 ms_error("get kAudioDevicePropertyDeviceName error %ld", err);
272 slen = strlen(devname);
273 /* trim whitespace */
274 while ((slen > 0) && (devname[slen - 1] == ' ')) {
277 devname[slen] = '\0';
280 AudioDeviceGetPropertyInfo(V[i], 0, FALSE,
281 kAudioDevicePropertyStreamConfiguration,
283 if (err != kAudioHardwareNoError) {
284 ms_error("get kAudioDevicePropertyDeviceName error %ld", err);
287 AudioBufferList *buflist = ms_new(slen, 1);
288 if (buflist == NULL) {
289 ms_error("alloc AudioBufferList %ld", err);
294 AudioDeviceGetProperty(V[i], 0, FALSE,
295 kAudioDevicePropertyStreamConfiguration,
297 if (err != kAudioHardwareNoError) {
298 ms_error("get kAudioDevicePropertyDeviceName error %ld", err);
304 for (j = 0; j < buflist->mNumberBuffers; j++) {
305 if (buflist->mBuffers[j].mNumberChannels > 0) {
306 cap = MS_SND_CARD_CAP_PLAYBACK;
314 AudioDeviceGetPropertyInfo(V[i], 0, TRUE,
315 kAudioDevicePropertyStreamConfiguration,
317 if (err != kAudioHardwareNoError) {
318 ms_error("get kAudioDevicePropertyDeviceName error %ld", err);
321 buflist = ms_new(slen, 1);
322 if (buflist == NULL) {
323 ms_error("alloc error %ld", err);
328 AudioDeviceGetProperty(V[i], 0, TRUE,
329 kAudioDevicePropertyStreamConfiguration,
331 if (err != kAudioHardwareNoError) {
332 ms_error("get kAudioDevicePropertyDeviceName error %ld", err);
337 for (j = 0; j < buflist->mNumberBuffers; j++) {
338 if (buflist->mBuffers[j].mNumberChannels > 0) {
339 cap |= MS_SND_CARD_CAP_CAPTURE;
348 slen = sizeof(CFStringRef);
350 AudioDeviceGetProperty(V[i], 0, false,
351 kAudioDevicePropertyDeviceUID, &slen,
353 if (err != kAudioHardwareNoError) {
354 ms_error("get kAudioHardwarePropertyDevices error %ld", err);
357 CFStringGetCString(dUID, uidname, 256,
358 CFStringGetSystemEncoding());
359 ms_message("AQ: devname:%s uidname:%s", devname, uidname);
361 AudioStreamBasicDescription devicereadFormat;
362 AudioStreamBasicDescription devicewriteFormat;
363 slen = sizeof(devicewriteFormat);
364 err = AudioDeviceGetProperty(V[i], 0, false,
365 kAudioDevicePropertyStreamFormat,
366 &slen, &devicewriteFormat);
367 if (err == kAudioHardwareNoError) {
368 show_format("output device", &devicewriteFormat);
370 slen = sizeof(devicereadFormat);
371 err = AudioDeviceGetProperty(V[i], 0, true,
372 kAudioDevicePropertyStreamFormat,
373 &slen, &devicereadFormat);
374 if (err == kAudioHardwareNoError) {
375 show_format("input device", &devicereadFormat);
378 MSSndCard *card = aq_card_new(devname, dUID, &devicereadFormat,
379 &devicewriteFormat, cap);
380 ms_snd_card_manager_add_card(m, card);
386 Audio Queue recode callback
389 static void readCallback(void *aqData,
391 AudioQueueBufferRef inBuffer,
392 const AudioTimeStamp * inStartTime,
394 const AudioStreamPacketDescription * inPacketDesc)
396 AQData *d = (AQData *) aqData;
401 (inBuffer->mAudioDataByteSize * d->readAudioFormat.mSampleRate /
402 1) / d->devicereadFormat.mSampleRate /
403 d->devicereadFormat.mChannelsPerFrame;
405 ms_mutex_lock(&d->mutex);
406 if (d->read_started == FALSE) {
407 ms_mutex_unlock(&d->mutex);
413 err = AudioConverterConvertBuffer(d->readAudioConverter,
414 inBuffer->mAudioDataByteSize,
415 inBuffer->mAudioData,
418 ms_error("readCallback: AudioConverterConvertBuffer %d", err);
419 ms_warning("readCallback: inBuffer->mAudioDataByteSize = %d",
420 inBuffer->mAudioDataByteSize);
421 ms_warning("readCallback: outlen = %d", len);
422 ms_warning("readCallback: origlen = %i",
423 (inBuffer->mAudioDataByteSize *
424 d->readAudioFormat.mSampleRate / 1) /
425 d->devicereadFormat.mSampleRate /
426 d->devicereadFormat.mChannelsPerFrame);
431 if (gain_volume_in != 1.0f)
433 int16_t *ptr=(int16_t *)rm->b_rptr;
434 for (;ptr<(int16_t *)rm->b_wptr;ptr++)
436 *ptr=(int16_t)(((float)(*ptr))*gain_volume_in);
442 err = AudioQueueEnqueueBuffer(d->readQueue, inBuffer, 0, NULL);
444 ms_error("readCallback:AudioQueueEnqueueBuffer %d", err);
446 ms_mutex_unlock(&d->mutex);
450 Audio Queue play callback
453 static void writeCallback(void *aqData,
454 AudioQueueRef inAQ, AudioQueueBufferRef inBuffer)
456 AQData *d = (AQData *) aqData;
460 (d->writeBufferByteSize * d->writeAudioFormat.mSampleRate / 1) /
461 d->devicewriteFormat.mSampleRate /
462 d->devicewriteFormat.mChannelsPerFrame;
464 ms_mutex_lock(&d->mutex);
465 if (d->write_started == FALSE) {
466 ms_mutex_unlock(&d->mutex);
469 if (d->bufferizer->size >= len) {
470 UInt32 bsize = d->writeBufferByteSize;
471 uint8_t *pData = ms_malloc(len);
473 ms_bufferizer_read(d->bufferizer, pData, len);
474 err = AudioConverterConvertBuffer(d->writeAudioConverter,
477 &bsize, inBuffer->mAudioData);
479 ms_error("writeCallback: AudioConverterConvertBuffer %d", err);
483 if (bsize != d->writeBufferByteSize)
484 ms_warning("d->writeBufferByteSize = %i len = %i bsize = %i",
485 d->writeBufferByteSize, len, bsize);
487 memset(inBuffer->mAudioData, 0, d->writeBufferByteSize);
489 inBuffer->mAudioDataByteSize = d->writeBufferByteSize;
491 if (gain_changed_out == true)
493 AudioQueueSetParameter (d->writeQueue,
494 kAudioQueueParam_Volume,
496 gain_changed_out = false;
499 err = AudioQueueEnqueueBuffer(d->writeQueue, inBuffer, 0, NULL);
501 ms_error("AudioQueueEnqueueBuffer %d", err);
503 ms_mutex_unlock(&d->mutex);
506 void putWriteAQ(void *aqData, int queuenum)
508 AQData *d = (AQData *) aqData;
510 err = AudioQueueEnqueueBuffer(d->writeQueue,
511 d->writeBuffers[queuenum], 0, NULL);
513 ms_error("AudioQueueEnqueueBuffer %d", err);
518 play buffer setup function
521 void setupWrite(MSFilter * f)
523 AQData *d = (AQData *) f->data;
528 for (bufferIndex = 0; bufferIndex < kNumberAudioOutDataBuffers;
531 err = AudioQueueAllocateBuffer(d->writeQueue,
532 d->writeBufferByteSize,
533 &d->writeBuffers[bufferIndex]
536 ms_error("setupWrite:AudioQueueAllocateBuffer %d", err);
542 recode buffer setup function
545 void setupRead(MSFilter * f)
547 AQData *d = (AQData *) f->data;
550 // allocate and enqueue buffers
553 for (bufferIndex = 0; bufferIndex < kNumberAudioInDataBuffers;
556 AudioQueueBufferRef buffer;
558 err = AudioQueueAllocateBuffer(d->readQueue,
559 d->readBufferByteSize, &buffer);
561 ms_error("setupRead:AudioQueueAllocateBuffer %d", err);
564 err = AudioQueueEnqueueBuffer(d->readQueue, buffer, 0, NULL);
566 ms_error("AudioQueueEnqueueBuffer %d", err);
572 static void aq_start_r(MSFilter * f)
574 AQData *d = (AQData *) f->data;
575 if (d->read_started == FALSE) {
578 d->readAudioFormat.mSampleRate = d->rate;
579 d->readAudioFormat.mFormatID = kAudioFormatLinearPCM;
580 d->readAudioFormat.mFormatFlags =
581 kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
582 d->readAudioFormat.mFramesPerPacket = 1;
583 d->readAudioFormat.mChannelsPerFrame = 1;
584 d->readAudioFormat.mBitsPerChannel = d->bits;
585 d->readAudioFormat.mBytesPerPacket = d->bits / 8;
586 d->readAudioFormat.mBytesPerFrame = d->bits / 8;
588 //show_format("input device", &d->devicereadFormat);
589 //show_format("data from input filter", &d->readAudioFormat);
591 memcpy(&d->devicereadFormat, &d->readAudioFormat,
592 sizeof(d->readAudioFormat));
593 d->readBufferByteSize =
594 kSecondsPerBuffer * d->devicereadFormat.mSampleRate *
595 (d->devicereadFormat.mBitsPerChannel / 8) *
596 d->devicereadFormat.mChannelsPerFrame;
598 aqresult = AudioConverterNew(&d->devicereadFormat,
600 &d->readAudioConverter);
601 if (aqresult != noErr) {
602 ms_error("d->readAudioConverter = %d", aqresult);
603 d->readAudioConverter = NULL;
606 aqresult = AudioQueueNewInput(&d->devicereadFormat, readCallback, d, // userData
608 NULL, // run loop mode
611 if (aqresult != noErr) {
612 ms_error("AudioQueueNewInput = %d", aqresult);
616 CFStringGetCString(d->uidname, uidname, 256,
617 CFStringGetSystemEncoding());
618 ms_message("AQ: using uidname:%s", uidname);
620 AudioQueueSetProperty(d->readQueue,
621 kAudioQueueProperty_CurrentDevice,
622 &d->uidname, sizeof(CFStringRef));
623 if (aqresult != noErr) {
625 ("AudioQueueSetProperty on kAudioQueueProperty_CurrentDevice %d",
630 AudioQueueStart(d->readQueue, NULL // start time. NULL means ASAP.
632 if (aqresult != noErr) {
633 ms_error("AudioQueueStart %d", aqresult);
635 d->read_started = TRUE;
639 static void aq_stop_r(MSFilter * f)
641 AQData *d = (AQData *) f->data;
643 if (d->read_started == TRUE) {
644 ms_mutex_lock(&d->mutex);
645 d->read_started = FALSE; /* avoid a deadlock related to buffer conversion in callback */
646 ms_mutex_unlock(&d->mutex);
647 AudioConverterDispose(d->readAudioConverter);
648 AudioQueueStop(d->readQueue, true);
649 AudioQueueDispose(d->readQueue, true);
653 static void aq_start_w(MSFilter * f)
655 AQData *d = (AQData *) f->data;
656 if (d->write_started == FALSE) {
659 d->writeAudioFormat.mSampleRate = d->rate;
660 d->writeAudioFormat.mFormatID = kAudioFormatLinearPCM;
661 d->writeAudioFormat.mFormatFlags =
662 kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
663 d->writeAudioFormat.mFramesPerPacket = 1;
664 d->writeAudioFormat.mChannelsPerFrame = 1;
665 d->writeAudioFormat.mBitsPerChannel = d->bits;
666 d->writeAudioFormat.mBytesPerPacket = d->bits / 8;
667 d->writeAudioFormat.mBytesPerFrame = d->bits / 8;
669 //show_format("data provided to output filter", &d->writeAudioFormat);
670 //show_format("output device", &d->devicewriteFormat);
672 memcpy(&d->devicewriteFormat, &d->writeAudioFormat,
673 sizeof(d->writeAudioFormat));
674 d->writeBufferByteSize =
675 kSecondsPerBuffer * d->devicewriteFormat.mSampleRate *
676 (d->devicewriteFormat.mBitsPerChannel / 8) *
677 d->devicewriteFormat.mChannelsPerFrame;
679 aqresult = AudioConverterNew(&d->writeAudioFormat,
680 &d->devicewriteFormat,
681 &d->writeAudioConverter);
682 if (aqresult != noErr) {
683 ms_error("d->writeAudioConverter = %d", aqresult);
684 d->writeAudioConverter = NULL;
686 // create the playback audio queue object
687 aqresult = AudioQueueNewOutput(&d->devicewriteFormat, writeCallback, d, NULL, /*CFRunLoopGetCurrent () */
688 NULL, /*kCFRunLoopCommonModes */
691 if (aqresult != noErr) {
692 ms_error("AudioQueueNewOutput = %d", aqresult);
695 AudioQueueSetParameter (d->writeQueue,
696 kAudioQueueParam_Volume,
700 CFStringGetCString(d->uidname, uidname, 256,
701 CFStringGetSystemEncoding());
702 ms_message("AQ: using uidname:%s", uidname);
704 AudioQueueSetProperty(d->writeQueue,
705 kAudioQueueProperty_CurrentDevice,
706 &d->uidname, sizeof(CFStringRef));
707 if (aqresult != noErr) {
709 ("AudioQueueSetProperty on kAudioQueueProperty_CurrentDevice %d",
713 d->curWriteBuffer = 0;
717 static void aq_stop_w(MSFilter * f)
719 AQData *d = (AQData *) f->data;
720 if (d->write_started == TRUE) {
721 ms_mutex_lock(&d->mutex);
722 d->write_started = FALSE; /* avoid a deadlock related to buffer conversion in callback */
723 ms_mutex_unlock(&d->mutex);
724 AudioConverterDispose(d->writeAudioConverter);
725 AudioQueueStop(d->writeQueue, true);
727 AudioQueueDispose(d->writeQueue, true);
731 static mblk_t *aq_get(MSFilter * f)
733 AQData *d = (AQData *) f->data;
735 ms_mutex_lock(&d->mutex);
737 ms_mutex_unlock(&d->mutex);
741 static void aq_put(MSFilter * f, mblk_t * m)
743 AQData *d = (AQData *) f->data;
744 ms_mutex_lock(&d->mutex);
745 ms_bufferizer_put(d->bufferizer, m);
746 ms_mutex_unlock(&d->mutex);
749 (d->writeBufferByteSize * d->writeAudioFormat.mSampleRate / 1) /
750 d->devicewriteFormat.mSampleRate /
751 d->devicewriteFormat.mChannelsPerFrame;
752 if (d->write_started == FALSE && d->bufferizer->size >= len) {
753 AudioQueueBufferRef curbuf = d->writeBuffers[d->curWriteBuffer];
755 UInt32 bsize = d->writeBufferByteSize;
756 uint8_t *pData = ms_malloc(len);
758 ms_bufferizer_read(d->bufferizer, pData, len);
759 err = AudioConverterConvertBuffer(d->writeAudioConverter,
762 &bsize, curbuf->mAudioData);
764 ms_error("writeCallback: AudioConverterConvertBuffer %d", err);
768 if (bsize != d->writeBufferByteSize)
769 ms_warning("d->writeBufferByteSize = %i len = %i bsize = %i",
770 d->writeBufferByteSize, len, bsize);
772 curbuf->mAudioDataByteSize = d->writeBufferByteSize;
773 putWriteAQ(d, d->curWriteBuffer);
776 if (d->write_started == FALSE
777 && d->curWriteBuffer == kNumberAudioOutDataBuffers - 1) {
779 err = AudioQueueStart(d->writeQueue, NULL // start time. NULL means ASAP.
782 ms_error("AudioQueueStart %d", err);
784 d->write_started = TRUE;
788 static void aq_init(MSFilter * f)
790 AQData *d = ms_new(AQData, 1);
795 d->read_started = FALSE;
796 d->write_started = FALSE;
798 d->bufferizer = ms_bufferizer_new();
799 ms_mutex_init(&d->mutex, NULL);
803 static void aq_uninit(MSFilter * f)
805 AQData *d = (AQData *) f->data;
807 ms_bufferizer_destroy(d->bufferizer);
808 ms_mutex_destroy(&d->mutex);
809 if (d->uidname != NULL)
810 CFRelease(d->uidname);
814 static void aq_read_preprocess(MSFilter * f)
819 static void aq_read_postprocess(MSFilter * f)
824 static void aq_read_process(MSFilter * f)
827 while ((m = aq_get(f)) != NULL) {
828 ms_queue_put(f->outputs[0], m);
832 static void aq_write_preprocess(MSFilter * f)
837 static void aq_write_postprocess(MSFilter * f)
842 static void aq_write_process(MSFilter * f)
845 while ((m = ms_queue_get(f->inputs[0])) != NULL) {
850 static int set_rate(MSFilter * f, void *arg)
852 AQData *d = (AQData *) f->data;
853 d->rate = *((int *) arg);
857 static int read_get_rate(MSFilter * f, void *arg)
859 AQData *d = (AQData *) f->data;
860 *((int *) arg) = d->rate;
864 static int write_get_rate(MSFilter * f, void *arg)
866 AQData *d = (AQData *) f->data;
867 *((int *) arg) = d->rate;
872 static int set_nchannels(MSFilter *f, void *arg){
873 AQData *d=(AQData*)f->data;
874 d->stereo=(*((int*)arg)==2);
879 static MSFilterMethod aq_read_methods[] = {
880 {MS_FILTER_SET_SAMPLE_RATE, set_rate},
881 {MS_FILTER_GET_SAMPLE_RATE, read_get_rate},
883 { MS_FILTER_SET_NCHANNELS , set_nchannels },
888 MSFilterDesc aq_read_desc = {
891 .text = N_("Sound capture filter for MacOS X Audio Queue Service"),
892 .category = MS_FILTER_OTHER,
896 .preprocess = aq_read_preprocess,
897 .process = aq_read_process,
898 .postprocess = aq_read_postprocess,
900 .methods = aq_read_methods
903 static MSFilterMethod aq_write_methods[] = {
904 {MS_FILTER_SET_SAMPLE_RATE, set_rate},
905 {MS_FILTER_GET_SAMPLE_RATE, write_get_rate},
907 { MS_FILTER_SET_NCHANNELS , set_nchannels },
912 MSFilterDesc aq_write_desc = {
913 .id = MS_AQ_WRITE_ID,
915 .text = N_("Sound playback filter for MacOS X Audio Queue Service"),
916 .category = MS_FILTER_OTHER,
920 .preprocess = aq_write_preprocess,
921 .process = aq_write_process,
922 .postprocess = aq_write_postprocess,
924 .methods = aq_write_methods
927 MSFilter *ms_aq_read_new(MSSndCard * card)
929 MSFilter *f = ms_filter_new_from_desc(&aq_read_desc);
930 AqSndDsCard *wc = (AqSndDsCard *) card->data;
931 AQData *d = (AQData *) f->data;
932 d->uidname = CFStringCreateCopy(NULL, wc->uidname);
933 memcpy(&d->devicereadFormat, &wc->devicereadFormat,
934 sizeof(AudioStreamBasicDescription));
935 memcpy(&d->devicewriteFormat, &wc->devicewriteFormat,
936 sizeof(AudioStreamBasicDescription));
941 MSFilter *ms_aq_write_new(MSSndCard * card)
943 MSFilter *f = ms_filter_new_from_desc(&aq_write_desc);
944 AqSndDsCard *wc = (AqSndDsCard *) card->data;
945 AQData *d = (AQData *) f->data;
946 d->uidname = CFStringCreateCopy(NULL, wc->uidname);
947 memcpy(&d->devicereadFormat, &wc->devicereadFormat,
948 sizeof(AudioStreamBasicDescription));
949 memcpy(&d->devicewriteFormat, &wc->devicewriteFormat,
950 sizeof(AudioStreamBasicDescription));
954 MS_FILTER_DESC_EXPORT(aq_read_desc)
955 MS_FILTER_DESC_EXPORT(aq_write_desc)