source: mediastreamer2/src/macsnd.c @ 947:d2ba2ac865ab

Last change on this file since 947:d2ba2ac865ab was 947:d2ba2ac865ab, checked in by Aymeric Moizard <jack@…>, 3 years ago

add support for volume control in AudioUnit?

File size: 31.1 KB
Line 
1/*
2mediastreamer2 library - modular sound and video processing and streaming
3Copyright (C) 2006  Simon MORLAT (simon.morlat@linphone.org)
4
5This program is free software; you can redistribute it and/or
6modify it under the terms of the GNU General Public License
7as published by the Free Software Foundation; either version 2
8of the License, or (at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18*/
19
20/* this file is specifically distributed under a BSD license */
21
22/**
23* Copyright (C) 2007  Hiroki Mori (himori@users.sourceforge.net)
24* All rights reserved.
25*
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.
36*
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.
47**/
48#include <CoreServices/CoreServices.h>
49#include <AudioUnit/AudioUnit.h>
50#include <AudioToolbox/AudioToolbox.h>
51
52#include "mediastreamer2/mssndcard.h"
53#include "mediastreamer2/msfilter.h"
54
55MSFilter *ms_ca_read_new(MSSndCard *card);
56MSFilter *ms_ca_write_new(MSSndCard *card);
57
58static float gain_volume_in=1.0;
59static float gain_volume_out=1.0;
60static bool gain_changed_in = true;
61static bool gain_changed_out = true;
62
63typedef struct CAData{
64        int dev;
65       
66        AudioUnit caOutAudioUnit;
67        AudioUnit caInAudioUnit;
68        AudioStreamBasicDescription caOutASBD;
69        AudioStreamBasicDescription caInASBD;
70        AURenderCallbackStruct caOutRenderCallback;
71        AURenderCallbackStruct caInRenderCallback;
72        AudioConverterRef caOutConverter;
73        AudioConverterRef caInConverter;
74        int rate;
75        int bits;
76        ms_mutex_t mutex;
77        queue_t rq;
78        MSBufferizer * bufferizer;
79        bool_t read_started;
80        bool_t write_started;
81        bool_t stereo;
82        void *caSourceBuffer;
83        AudioBufferList *fAudioBuffer, *fMSBuffer;
84} CAData;
85
86
87typedef struct CaSndDsCard {
88        CFStringRef uidname;
89        AudioDeviceID dev;
90        int removed;
91} CaSndDsCard;
92
93static void cacard_set_level(MSSndCard *card, MSSndCardMixerElem e, int percent)
94{
95        switch(e){
96                case MS_SND_CARD_PLAYBACK:
97                case MS_SND_CARD_MASTER:
98                        gain_volume_out =((float)percent)/100.0f;
99                        gain_changed_out = true;
100                        return;
101                case MS_SND_CARD_CAPTURE:
102                        gain_volume_in =((float)percent)/100.0f;
103                        gain_changed_in = true;
104                        return;
105                default:
106                        ms_warning("cacard_set_level: unsupported command.");
107        }
108}
109
110static int cacard_get_level(MSSndCard *card, MSSndCardMixerElem e)
111{
112        switch(e){
113                case MS_SND_CARD_PLAYBACK:
114                case MS_SND_CARD_MASTER:
115                        return (int)(gain_volume_out*100.0f);
116                case MS_SND_CARD_CAPTURE:
117                        return (int)(gain_volume_in*100.0f);
118                default:
119                        ms_warning("cacard_get_level: unsupported command.");
120        }
121        return -1;
122}
123
124static void cacard_set_source(MSSndCard *card, MSSndCardCapture source)
125{
126}
127
128static void cacard_init(MSSndCard * card)
129{
130        CaSndDsCard *c = (CaSndDsCard *) ms_new0(CaSndDsCard, 1);
131        c->removed = 0;
132        card->data = c;
133}
134
135static void cacard_uninit(MSSndCard * card)
136{
137        CaSndDsCard *d = (CaSndDsCard *) card->data;
138        if (d->uidname != NULL)
139                CFRelease(d->uidname);
140        ms_free(d);
141}
142
143static void cacard_detect(MSSndCardManager *m);
144static MSSndCard *cacard_duplicate(MSSndCard *obj);
145
146MSSndCardDesc ca_card_desc={
147        .driver_type="CA",
148        .detect=cacard_detect,
149        .init=cacard_init,
150        .set_level=cacard_set_level,
151        .get_level=cacard_get_level,
152        .set_capture=cacard_set_source,
153        .set_control=NULL,
154        .get_control=NULL,
155        .create_reader=ms_ca_read_new,
156        .create_writer=ms_ca_write_new,
157        .uninit=cacard_uninit,
158        .duplicate=cacard_duplicate
159};
160
161static MSSndCard *cacard_duplicate(MSSndCard * obj)
162{
163        CaSndDsCard *ca;
164        CaSndDsCard *cadup;
165        MSSndCard *card = ms_snd_card_new(&ca_card_desc);
166        card->name = ms_strdup(obj->name);
167        card->data = ms_new0(CaSndDsCard, 1);
168        memcpy(card->data, obj->data, sizeof(CaSndDsCard));
169        ca = obj->data;
170        cadup = card->data;
171        cadup->uidname = CFStringCreateCopy(NULL, ca->uidname);
172        return card;
173}
174
175static MSSndCard *ca_card_new(const char *name, CFStringRef uidname, AudioDeviceID dev, unsigned cap)
176{
177        MSSndCard *card = ms_snd_card_new(&ca_card_desc);
178        CaSndDsCard *d = (CaSndDsCard *) card->data;
179        d->uidname = uidname;
180        d->dev = dev;
181        card->name = ms_strdup(name);
182        card->capabilities = cap;
183        return card;
184}
185
186static void show_format(char *name,
187                                                AudioStreamBasicDescription * deviceFormat)
188{
189        ms_message("Format for %s", name);
190        ms_message("mSampleRate = %g", deviceFormat->mSampleRate);
191        char *the4CCString = (char *) &deviceFormat->mFormatID;
192        char outName[5];
193        outName[0] = the4CCString[0];
194        outName[1] = the4CCString[1];
195        outName[2] = the4CCString[2];
196        outName[3] = the4CCString[3];
197        outName[4] = 0;
198        ms_message("mFormatID = %s", outName);
199        ms_message("mFormatFlags = %08lX", deviceFormat->mFormatFlags);
200        ms_message("mBytesPerPacket = %ld", deviceFormat->mBytesPerPacket);
201        ms_message("mFramesPerPacket = %ld", deviceFormat->mFramesPerPacket);
202        ms_message("mChannelsPerFrame = %ld", deviceFormat->mChannelsPerFrame);
203        ms_message("mBytesPerFrame = %ld", deviceFormat->mBytesPerFrame);
204        ms_message("mBitsPerChannel = %ld", deviceFormat->mBitsPerChannel);
205}
206
207static void cacard_detect(MSSndCardManager * m)
208{
209#ifndef TARGET_OS_IPHONE
210        OSStatus err;
211        UInt32 slen;
212        int count;
213        Boolean writable;
214        int i;
215        writable = 0;
216        slen = 0;
217        err =
218        AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &slen,
219                                                                 &writable);
220        if (err != kAudioHardwareNoError) {
221                ms_error("get kAudioHardwarePropertyDevices error %ld", err);
222                return;
223        }
224        AudioDeviceID V[slen / sizeof(AudioDeviceID)];
225        err =
226        AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &slen, V);
227        if (err != kAudioHardwareNoError) {
228                ms_error("get kAudioHardwarePropertyDevices error %ld", err);
229                return;
230        }
231        count = slen / sizeof(AudioDeviceID);
232        for (i = 0; i < count; i++) {
233                char devname_in[256];
234                char uidname_in[256];
235                char devname_out[256];
236                char uidname_out[256];
237                int cap = 0;
238               
239                /* OUTPUT CARDS */
240                slen = 256;
241                err =
242                AudioDeviceGetProperty(V[i], 0, FALSE,
243                                                           kAudioDevicePropertyDeviceName, &slen,
244                                                           devname_out);
245                if (err != kAudioHardwareNoError) {
246                        ms_error("get kAudioDevicePropertyDeviceName error %ld", err);
247                        continue;
248                }
249                slen = strlen(devname_out);
250                /* trim whitespace */
251                while ((slen > 0) && (devname_out[slen - 1] == ' ')) {
252                        slen--;
253                }
254                devname_out[slen] = '\0';
255               
256                err =
257                AudioDeviceGetPropertyInfo(V[i], 0, FALSE,
258                                                                   kAudioDevicePropertyStreamConfiguration,
259                                                                   &slen, &writable);
260                if (err != kAudioHardwareNoError) {
261                        ms_error("get kAudioDevicePropertyDeviceName error %ld", err);
262                        continue;
263                }
264               
265                AudioBufferList *buflist = ms_malloc(slen);
266                if (buflist == NULL) {
267                        ms_error("alloc AudioBufferList %ld", err);
268                        continue;
269                }
270               
271                err =
272                AudioDeviceGetProperty(V[i], 0, FALSE,
273                                                           kAudioDevicePropertyStreamConfiguration,
274                                                           &slen, buflist);
275                if (err != kAudioHardwareNoError) {
276                        ms_error("get kAudioDevicePropertyDeviceName error %ld", err);
277                        ms_free(buflist);
278                        continue;
279                }
280               
281                UInt32 j;
282                for (j = 0; j < buflist->mNumberBuffers; j++) {
283                        if (buflist->mBuffers[j].mNumberChannels > 0) {
284                                cap = MS_SND_CARD_CAP_PLAYBACK;
285                                break;
286                        }
287                }
288               
289                ms_free(buflist);
290               
291                /* INPUT CARDS */
292                slen = 256;
293                err =
294                AudioDeviceGetProperty(V[i], 0, TRUE,
295                                                           kAudioDevicePropertyDeviceName, &slen,
296                                                           devname_in);
297                if (err != kAudioHardwareNoError) {
298                        ms_error("get kAudioDevicePropertyDeviceName error %ld", err);
299                        continue;
300                }
301                slen = strlen(devname_in);
302                /* trim whitespace */
303                while ((slen > 0) && (devname_in[slen - 1] == ' ')) {
304                        slen--;
305                }
306                devname_in[slen] = '\0';
307               
308                err =
309                AudioDeviceGetPropertyInfo(V[i], 0, TRUE,
310                                                                   kAudioDevicePropertyStreamConfiguration,
311                                                                   &slen, &writable);
312                if (err != kAudioHardwareNoError) {
313                        ms_error("get kAudioDevicePropertyDeviceName error %ld", err);
314                        continue;
315                }
316               
317               
318                err =
319                AudioDeviceGetPropertyInfo(V[i], 0, TRUE,
320                                                                   kAudioDevicePropertyStreamConfiguration,
321                                                                   &slen, &writable);
322                if (err != kAudioHardwareNoError) {
323                        ms_error("get kAudioDevicePropertyDeviceName error %ld", err);
324                        continue;
325                }
326                buflist = ms_malloc(slen);
327                if (buflist == NULL) {
328                        ms_error("alloc error %ld", err);
329                        continue;
330                }
331               
332                err =
333                AudioDeviceGetProperty(V[i], 0, TRUE,
334                                                           kAudioDevicePropertyStreamConfiguration,
335                                                           &slen, buflist);
336                if (err != kAudioHardwareNoError) {
337                        ms_error("get kAudioDevicePropertyDeviceName error %ld", err);
338                        ms_free(buflist);
339                        continue;
340                }
341               
342                for (j = 0; j < buflist->mNumberBuffers; j++) {
343                        if (buflist->mBuffers[j].mNumberChannels > 0) {
344                                cap |= MS_SND_CARD_CAP_CAPTURE;
345                                break;
346                        }
347                }
348               
349                ms_free(buflist);
350               
351                if (cap & MS_SND_CARD_CAP_PLAYBACK) {
352                        CFStringRef dUID_out;
353                        dUID_out = NULL;
354                        slen = sizeof(CFStringRef);
355                        err =
356                    AudioDeviceGetProperty(V[i], 0, false,
357                                                                   kAudioDevicePropertyDeviceUID, &slen,
358                                                                   &dUID_out);
359                        if (err != kAudioHardwareNoError) {
360                                ms_error("get kAudioHardwarePropertyDevices error %ld", err);
361                                continue;
362                        }
363                        CFStringGetCString(dUID_out, uidname_out, 256,
364                                                           CFStringGetSystemEncoding());
365                        ms_message("CA: devname_out:%s uidname_out:%s", devname_out, uidname_out);
366                       
367                        AudioStreamBasicDescription devicewriteFormat;
368                        slen = sizeof(devicewriteFormat);
369                        err = AudioDeviceGetProperty(V[i], 0, false,
370                                                                                 kAudioDevicePropertyStreamFormat,
371                                                                                 &slen, &devicewriteFormat);
372                        if (err == kAudioHardwareNoError) {
373                                show_format("output device", &devicewriteFormat);
374                        }
375                        MSSndCard *card = ca_card_new(devname_out, dUID_out, V[i], MS_SND_CARD_CAP_PLAYBACK);
376                        ms_snd_card_manager_add_card(m, card);
377                }
378               
379                if (cap & MS_SND_CARD_CAP_CAPTURE) {
380                        CFStringRef dUID_in;
381                        dUID_in = NULL;
382                        slen = sizeof(CFStringRef);
383                        err =
384                    AudioDeviceGetProperty(V[i], 0, true,
385                                                                   kAudioDevicePropertyDeviceUID, &slen,
386                                                                   &dUID_in);
387                        if (err != kAudioHardwareNoError) {
388                                ms_error("get kAudioHardwarePropertyDevices error %ld", err);
389                                continue;
390                        }
391                        CFStringGetCString(dUID_in, uidname_in, 256,
392                                                           CFStringGetSystemEncoding());
393                        ms_message("CA: devname_in:%s uidname_in:%s", devname_in, uidname_in);
394                       
395                        AudioStreamBasicDescription devicereadFormat;
396                        slen = sizeof(devicereadFormat);
397                        err = AudioDeviceGetProperty(V[i], 0, true,
398                                                                                 kAudioDevicePropertyStreamFormat,
399                                                                                 &slen, &devicereadFormat);
400                        if (err == kAudioHardwareNoError) {
401                                show_format("input device", &devicereadFormat);
402                        }
403                        MSSndCard *card = ca_card_new(devname_in, dUID_in, V[i], MS_SND_CARD_CAP_CAPTURE);
404                        ms_snd_card_manager_add_card(m, card);
405                }
406        }
407#else
408        AudioStreamBasicDescription deviceFormat;
409        memset(&deviceFormat, 0, sizeof(AudioStreamBasicDescription));
410       
411        MSSndCard *card = ca_card_new("AudioUnit Device", NULL, 0 /*?*/, MS_SND_CARD_CAP_PLAYBACK|MS_SND_CARD_CAP_CAPTURE);
412        ms_snd_card_manager_add_card(m, card);
413#endif
414}
415
416
417// Convenience function to dispose of our audio buffers
418void DestroyAudioBufferList(AudioBufferList* list)
419{
420        UInt32                                          i;
421       
422        if(list) {
423                for(i = 0; i < list->mNumberBuffers; i++) {
424                        if(list->mBuffers[i].mData)
425                                free(list->mBuffers[i].mData);
426                }
427                free(list);
428        }
429}
430
431// Convenience function to allocate our audio buffers
432AudioBufferList *AllocateAudioBufferList(UInt32 numChannels, UInt32 size)
433{
434        AudioBufferList*                        list;
435        UInt32                                          i;
436       
437        list = (AudioBufferList*)calloc(1, sizeof(AudioBufferList) + numChannels * sizeof(AudioBuffer));
438        if(list == NULL)
439                return NULL;
440       
441        list->mNumberBuffers = numChannels;
442        for(i = 0; i < numChannels; ++i) {
443                list->mBuffers[i].mNumberChannels = 1;
444                list->mBuffers[i].mDataByteSize = size;
445                list->mBuffers[i].mData = malloc(size);
446                if(list->mBuffers[i].mData == NULL) {
447                        DestroyAudioBufferList(list);
448                        return NULL;
449                }
450        }
451        return list;
452}
453
454OSStatus writeACInputProc (
455                                                   AudioConverterRef inAudioConverter,
456                                                   UInt32 *ioNumberDataPackets,
457                                                   AudioBufferList *ioData,
458                                                   AudioStreamPacketDescription **outDataPacketDescription,
459                                                   void* inUserData)
460{
461    OSStatus    err = noErr;
462        CAData *d=(CAData*)inUserData;
463        UInt32 packetSize = (d->bits / 8) * (d->stereo ? 2 : 1);
464       
465        if(*ioNumberDataPackets) {
466                if(d->caSourceBuffer != NULL) {
467                        free(d->caSourceBuffer);
468                        d->caSourceBuffer = NULL;
469                }
470               
471                d->caSourceBuffer = (void *) calloc (1, *ioNumberDataPackets * packetSize);
472               
473                ioData->mBuffers[0].mData = d->caSourceBuffer;                  // tell the Audio Converter where it's source data is
474               
475                ms_mutex_lock(&d->mutex);
476                int readsize = ms_bufferizer_read(d->bufferizer,d->caSourceBuffer,*ioNumberDataPackets * packetSize);
477                ms_mutex_unlock(&d->mutex);
478                if(readsize != *ioNumberDataPackets * packetSize) {
479                        memset(d->caSourceBuffer, 0, *ioNumberDataPackets * packetSize);
480                        ioData->mBuffers[0].mDataByteSize = *ioNumberDataPackets * packetSize;          // tell the Audio Converter how much source data there is
481                } else {
482                        ioData->mBuffers[0].mDataByteSize = readsize;           // tell the Audio Converter how much source data there is
483                }
484        }
485       
486        return err;
487}
488
489OSStatus readACInputProc (AudioConverterRef inAudioConverter,
490                                                  UInt32* ioNumberDataPackets,
491                                                  AudioBufferList* ioData,
492                                                  AudioStreamPacketDescription** ioASPD,
493                                                  void* inUserData)
494{
495        CAData *d=(CAData*)inUserData;
496        AudioBufferList* l_inputABL = d->fAudioBuffer;
497        UInt32 totalInputBufferSizeBytes = ((*ioNumberDataPackets) * sizeof (float));
498        int counter = d->caInASBD.mChannelsPerFrame;
499        ioData->mNumberBuffers = d->caInASBD.mChannelsPerFrame;
500       
501        while (--counter >= 0)  {
502                AudioBuffer* l_ioD_AB = &(ioData->mBuffers[counter]);
503                l_ioD_AB->mNumberChannels = 1;
504                l_ioD_AB->mData = (float*)(l_inputABL->mBuffers[counter].mData);
505                l_ioD_AB->mDataByteSize = totalInputBufferSizeBytes;
506        }
507       
508        return (noErr);
509}
510
511OSStatus readRenderProc(void *inRefCon, 
512                                                AudioUnitRenderActionFlags *inActionFlags,
513                                                const AudioTimeStamp *inTimeStamp, 
514                                                UInt32 inBusNumber,
515                                                UInt32 inNumFrames, 
516                                                AudioBufferList *ioData)
517{
518        CAData *d=(CAData*)inRefCon;
519        OSStatus        err = noErr;
520       
521        err = AudioUnitRender(d->caInAudioUnit, inActionFlags, inTimeStamp, inBusNumber,
522                                                  inNumFrames, d->fAudioBuffer);
523        if(err != noErr)
524        {
525                ms_error("AudioUnitRender %d size = %d", err, d->fAudioBuffer->mBuffers[0].mDataByteSize);
526                return err;
527        }
528       
529        UInt32 AvailableOutputBytes = inNumFrames * sizeof (float) * d->caInASBD.mChannelsPerFrame;
530    UInt32 propertySize = sizeof (AvailableOutputBytes);
531    err = AudioConverterGetProperty (d->caInConverter,
532                                                                         kAudioConverterPropertyCalculateOutputBufferSize,
533                                                                         &propertySize,
534                                                                         &AvailableOutputBytes);
535       
536        if(err != noErr)
537        {
538                ms_error("AudioConverterGetProperty kAudioConverterPropertyCalculateOutputBufferSize %d", err);
539                return err;
540        }
541       
542        if (AvailableOutputBytes>d->fMSBuffer->mBuffers[0].mDataByteSize)
543        {       
544                DestroyAudioBufferList(d->fMSBuffer);
545                d->fMSBuffer = AllocateAudioBufferList(d->stereo ? 2 : 1,
546                                                                                           AvailableOutputBytes);
547        }
548       
549        UInt32 ActualOutputFrames = AvailableOutputBytes / ((d->bits / 8) * 1) / d->caInASBD.mChannelsPerFrame;
550        err = AudioConverterFillComplexBuffer (d->caInConverter,
551                                                                                   (AudioConverterComplexInputDataProc)(readACInputProc),
552                                                                                   inRefCon,
553                                                                                   &ActualOutputFrames,
554                                                                                   d->fMSBuffer,
555                                                                                   NULL);
556        if(err != noErr)
557        {
558                ms_error("readRenderProc:AudioConverterFillComplexBuffer %d", err);
559                return err;
560        }
561       
562        mblk_t *rm=NULL;
563        rm=allocb(ActualOutputFrames*2,0);
564        memcpy(rm->b_wptr, d->fMSBuffer->mBuffers[0].mData, ActualOutputFrames*2);
565        rm->b_wptr+=ActualOutputFrames*2;
566       
567        if (gain_volume_in != 1.0f)
568        {
569                int16_t *ptr=(int16_t *)rm->b_rptr;
570                for (;ptr<(int16_t *)rm->b_wptr;ptr++)
571                {
572                        *ptr=(int16_t)(((float)(*ptr))*gain_volume_in);
573                }
574        }
575       
576        ms_mutex_lock(&d->mutex);
577        putq(&d->rq,rm);
578        ms_mutex_unlock(&d->mutex);
579        rm=NULL;
580       
581        return err;
582}
583
584OSStatus writeRenderProc(void *inRefCon, 
585                                                 AudioUnitRenderActionFlags *inActionFlags,
586                                                 const AudioTimeStamp *inTimeStamp, 
587                                                 UInt32 inBusNumber,
588                                                 UInt32 inNumFrames, 
589                                                 AudioBufferList *ioData)
590{
591    OSStatus err= noErr;
592    void *inInputDataProcUserData=NULL;
593        CAData *d=(CAData*)inRefCon;
594        if (gain_changed_out == true)
595        {
596                err = AudioUnitSetParameter(d->caOutAudioUnit, kAudioUnitParameterUnit_LinearGain,
597                                                                           kAudioUnitScope_Global, 0, (Float32)gain_volume_out, 0);
598                if(err != noErr)
599                {
600                        ms_error("failed to set output volume %i", err);
601                }
602            gain_changed_out = false;
603                err= noErr;
604        }
605       
606       
607        if(d->write_started != FALSE) {
608                AudioStreamPacketDescription* outPacketDescription = NULL;
609                err = AudioConverterFillComplexBuffer(d->caOutConverter, writeACInputProc, inRefCon,
610                                                                                          &inNumFrames, ioData, outPacketDescription);
611                if(err != noErr)
612                        ms_error("writeRenderProc:AudioConverterFillComplexBuffer err %08x %d", err, ioData->mNumberBuffers);
613        }
614    return err;
615}
616
617static int ca_open_r(CAData *d){
618        OSStatus result;
619        UInt32 param;
620        AudioDeviceID fInputDeviceID;
621       
622        ComponentDescription desc; 
623        Component comp;
624       
625        // Get Default Input audio unit
626        desc.componentType = kAudioUnitType_Output;
627        desc.componentSubType = kAudioUnitSubType_HALOutput;
628        desc.componentManufacturer = kAudioUnitManufacturer_Apple;
629        desc.componentFlags = 0;
630        desc.componentFlagsMask = 0;
631       
632        comp = FindNextComponent(NULL, &desc);
633        if (comp == NULL)
634        {
635                ms_message("Cannot find audio component");
636                return -1;
637        }
638       
639        result = OpenAComponent(comp, &d->caInAudioUnit);
640        if(result != noErr)
641        {
642                ms_message("Cannot open audio component %x", result);
643                return -1;
644        }
645       
646        param = 1;
647        result = AudioUnitSetProperty(d->caInAudioUnit,
648                                                                  kAudioOutputUnitProperty_EnableIO,
649                                                                  kAudioUnitScope_Input,
650                                                                  1,
651                                                                  &param,
652                                                                  sizeof(UInt32));
653        ms_message("AudioUnitSetProperty %i %x", result, result);
654       
655        param = 0;
656        result = AudioUnitSetProperty(d->caInAudioUnit,
657                                                                  kAudioOutputUnitProperty_EnableIO,
658                                                                  kAudioUnitScope_Output,
659                                                                  0,
660                                                                  &param,
661                                                                  sizeof(UInt32));
662       
663        ms_message("AudioUnitSetProperty %i %x", result, result);
664       
665        // Set the current device to the default input unit.
666        result = AudioUnitSetProperty(d->caInAudioUnit,
667                                                                  kAudioOutputUnitProperty_CurrentDevice,
668                                                                  kAudioUnitScope_Global,
669                                                                  0,
670                                                                  &d->dev,
671                                                                  sizeof(AudioDeviceID));
672        ms_message("AudioUnitSetProperty %i %x", result, result);
673       
674        UInt32 asbdsize = sizeof(AudioStreamBasicDescription);
675        memset((char *)&d->caInASBD, 0, asbdsize);
676       
677        result = AudioUnitGetProperty (d->caInAudioUnit,
678                                                                   kAudioUnitProperty_StreamFormat,
679                                                                   kAudioUnitScope_Input,
680                                                                   1,
681                                                                   &d->caInASBD,
682                                                                   &asbdsize);
683       
684        ms_message("AudioUnitGetProperty %i %x", result, result);
685       
686       
687        if (d->caInASBD.mChannelsPerFrame>1)
688        {
689                d->caInASBD.mBytesPerFrame = d->caInASBD.mBytesPerFrame / d->caInASBD.mChannelsPerFrame;
690                d->caInASBD.mBytesPerPacket = d->caInASBD.mBytesPerPacket / d->caInASBD.mChannelsPerFrame;             
691                d->caInASBD.mChannelsPerFrame = 1;
692        }
693       
694        result = AudioUnitSetProperty(d->caInAudioUnit,
695                                                                  kAudioUnitProperty_StreamFormat,
696                                                                  kAudioUnitScope_Output,
697                                                                  1,
698                                                                  &d->caInASBD,
699                                                                  sizeof(AudioStreamBasicDescription));
700        ms_message("AudioUnitSetProperty %i %x", result, result);
701       
702       
703        d->caSourceBuffer=NULL;
704       
705        // Get the number of frames in the IO buffer(s)
706        param = sizeof(UInt32);
707        UInt32 fAudioSamples;
708        result = AudioUnitGetProperty(d->caInAudioUnit,
709                                                                  kAudioDevicePropertyBufferFrameSize,
710                                                                  kAudioUnitScope_Input,
711                                                                  1,
712                                                                  &fAudioSamples,
713                                                                  &param);
714        if(result != noErr)
715        {
716                ms_error("failed to get audio sample size");
717                return -1;
718        }
719       
720        result = AudioUnitInitialize(d->caInAudioUnit);
721        if(result != noErr)
722        {
723                ms_error("failed to AudioUnitInitialize input %i", result);
724                return -1;
725        }
726       
727        // Allocate our low device audio buffers
728        d->fAudioBuffer = AllocateAudioBufferList(d->caInASBD.mChannelsPerFrame,
729                                                                                          fAudioSamples * d->caInASBD.mBytesPerFrame * 2);
730        if(d->fAudioBuffer == NULL)
731        {
732                ms_error("failed to allocate buffers fAudioBuffer");
733                return -1;
734        }
735        // Allocate our low device audio buffers
736        d->fMSBuffer = AllocateAudioBufferList( d->stereo ? 2 : 1,
737                                                                                   fAudioSamples * ((d->bits / 8)*(d->stereo ? 2 : 1)) *2);
738        if(d->fMSBuffer == NULL)
739        {
740                ms_error("failed to allocate buffers fMSBuffer");
741                return -1;
742        }
743       
744        return 0;
745}
746
747static int ca_open_w(CAData *d){
748        OSStatus result;
749        UInt32 param;
750        AudioDeviceID fInputDeviceID;
751       
752        ComponentDescription desc; 
753        Component comp;
754       
755        // Get Default Input audio unit
756        desc.componentType = kAudioUnitType_Output;
757        desc.componentSubType = kAudioUnitSubType_HALOutput;
758        desc.componentManufacturer = kAudioUnitManufacturer_Apple;
759        desc.componentFlags = 0;
760        desc.componentFlagsMask = 0;
761       
762        comp = FindNextComponent(NULL, &desc);
763        if (comp == NULL)
764        {
765                ms_message("Cannot find audio component");
766                return -1;
767        }
768       
769        result = OpenAComponent(comp, &d->caOutAudioUnit);
770        if(result != noErr)
771        {
772                ms_message("Cannot open audio component %x", result);
773                return -1;
774        }
775       
776        param = 1;
777        result = AudioUnitSetProperty(d->caOutAudioUnit,
778                                                                  kAudioOutputUnitProperty_EnableIO,
779                                                                  kAudioUnitScope_Output,
780                                                                  0,
781                                                                  &param,
782                                                                  sizeof(UInt32));
783        ms_message("AudioUnitSetProperty %i %x", result, result);
784       
785        param = 0;
786        result = AudioUnitSetProperty(d->caOutAudioUnit,
787                                                                  kAudioOutputUnitProperty_EnableIO,
788                                                                  kAudioUnitScope_Input,
789                                                                  1,
790                                                                  &param,
791                                                                  sizeof(UInt32));
792        ms_message("AudioUnitSetProperty %i %x", result, result);
793       
794        // Set the current device to the default input unit.
795        result = AudioUnitSetProperty(d->caOutAudioUnit,
796                                                                  kAudioOutputUnitProperty_CurrentDevice,
797                                                                  kAudioUnitScope_Global,
798                                                                  0,
799                                                                  &d->dev,
800                                                                  sizeof(AudioDeviceID));
801        if (result == kAudioUnitErr_InvalidPropertyValue)
802                ms_message("AudioUnitSetProperty kAudioUnitErr_InvalidPropertyValue");
803        else
804                ms_message("AudioUnitSetProperty %i %x", result, result);
805       
806        UInt32 asbdsize = sizeof(AudioStreamBasicDescription);
807        memset((char *)&d->caOutASBD, 0, asbdsize);
808       
809        // Setup Output audio unit
810        result = AudioUnitGetProperty (d->caOutAudioUnit,
811                                                                   kAudioUnitProperty_StreamFormat,
812                                                                   kAudioUnitScope_Output,
813                                                                   0,
814                                                                   &d->caOutASBD,
815                                                                   &asbdsize);
816        ms_message("AudioUnitGetProperty %i %x", result, result);
817        result = AudioUnitSetProperty (d->caOutAudioUnit,
818                                                                   kAudioUnitProperty_StreamFormat,
819                                                                   kAudioUnitScope_Input,
820                                                                   0,
821                                                                   &d->caOutASBD,
822                                                                   asbdsize);
823        ms_message("AudioUnitSetProperty %i %x", result, result);
824       
825        d->caSourceBuffer=NULL;
826       
827        result = AudioUnitInitialize(d->caOutAudioUnit);
828        if(result != noErr)
829        {
830                ms_error("failed to AudioUnitInitialize output %i", result);
831                return -1;
832        }
833        return 0;
834}
835
836static void ca_start_r(CAData *d){
837        OSStatus err= noErr;
838       
839        if (d->read_started==FALSE){
840                AudioStreamBasicDescription outASBD;
841                int i;
842               
843                i = ca_open_r(d);
844                if (i<0)
845                        return;
846               
847                outASBD = d->caInASBD;
848                outASBD.mSampleRate = d->rate;
849                outASBD.mFormatID = kAudioFormatLinearPCM;
850                outASBD.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
851                if (htonl(0x1234) == 0x1234)
852                  outASBD.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
853                outASBD.mChannelsPerFrame = d->stereo ? 2 : 1;
854                outASBD.mBytesPerPacket = (d->bits / 8) * outASBD.mChannelsPerFrame;
855                outASBD.mBytesPerFrame = (d->bits / 8) * outASBD.mChannelsPerFrame;
856                outASBD.mFramesPerPacket = 1;
857                outASBD.mBitsPerChannel = d->bits;
858
859                err = AudioConverterNew( &d->caInASBD, &outASBD, &d->caInConverter);
860                if(err != noErr)
861                        ms_error("AudioConverterNew %x %d", err, outASBD.mBytesPerFrame);
862                else
863                        CAShow(d->caInConverter);
864
865                d->caInRenderCallback.inputProc = readRenderProc;
866                d->caInRenderCallback.inputProcRefCon = d;
867                err = AudioUnitSetProperty(d->caInAudioUnit,
868                                                kAudioOutputUnitProperty_SetInputCallback,
869                                                kAudioUnitScope_Global,
870                                                0,
871                                                &d->caInRenderCallback,
872                                                sizeof(AURenderCallbackStruct));
873
874                if(AudioOutputUnitStart(d->caInAudioUnit) == noErr)
875                        d->read_started = TRUE;
876        }
877}
878
879static void ca_stop_r(CAData *d){
880        OSErr err;
881        if(d->read_started == TRUE) {
882                if(AudioOutputUnitStop(d->caInAudioUnit) == noErr)
883                        d->read_started=FALSE;
884        }
885        if (d->caInConverter!=NULL)
886        {
887                AudioConverterDispose(d->caInConverter);
888                d->caInConverter=NULL;
889        }
890        if (d->caInAudioUnit!=NULL)
891        {
892                AudioUnitUninitialize(d->caInAudioUnit);
893                d->caInAudioUnit=NULL;
894        }
895        if (d->fAudioBuffer)
896                DestroyAudioBufferList(d->fAudioBuffer);
897        d->fAudioBuffer=NULL;
898        if (d->fMSBuffer)
899                DestroyAudioBufferList(d->fMSBuffer);
900        d->fMSBuffer=NULL;
901}
902
903static void ca_start_w(CAData *d){
904        OSStatus err= noErr;
905
906        if (d->write_started==FALSE){
907                AudioStreamBasicDescription inASBD;
908                int i;
909               
910                i = ca_open_w(d);
911                if (i<0)
912                        return;
913
914                inASBD = d->caOutASBD;
915                inASBD.mSampleRate = d->rate;
916                inASBD.mFormatID = kAudioFormatLinearPCM;
917                inASBD.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
918                if (htonl(0x1234) == 0x1234)
919                  inASBD.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
920                inASBD.mChannelsPerFrame = d->stereo ? 2 : 1;
921                inASBD.mBytesPerPacket = (d->bits / 8) * inASBD.mChannelsPerFrame;
922                inASBD.mBytesPerFrame = (d->bits / 8) * inASBD.mChannelsPerFrame;
923                inASBD.mFramesPerPacket = 1;
924                inASBD.mBitsPerChannel = d->bits;
925
926
927                err = AudioConverterNew( &inASBD, &d->caOutASBD, &d->caOutConverter);
928                if(err != noErr)
929                        ms_error("AudioConverterNew %x %d", err, inASBD.mBytesPerFrame);
930                else
931                        CAShow(d->caOutConverter);
932
933                if (inASBD.mChannelsPerFrame == 1 && d->caOutASBD.mChannelsPerFrame == 2)
934                {
935                        if (d->caOutConverter)
936                        {
937                                // This should be as large as the number of output channels,
938                                // each element specifies which input channel's data is routed to that output channel
939                                SInt32 channelMap[] = { 0, 0 };
940                                err = AudioConverterSetProperty(d->caOutConverter, kAudioConverterChannelMap, 2*sizeof(SInt32), channelMap);
941                        }
942                }
943
944                memset((char*)&d->caOutRenderCallback, 0, sizeof(AURenderCallbackStruct));
945                d->caOutRenderCallback.inputProc = writeRenderProc;
946                d->caOutRenderCallback.inputProcRefCon = d;
947                err = AudioUnitSetProperty (d->caOutAudioUnit, 
948                            kAudioUnitProperty_SetRenderCallback, 
949                            kAudioUnitScope_Input, 
950                            0,
951                            &d->caOutRenderCallback, 
952                            sizeof(AURenderCallbackStruct));
953                if(err != noErr)
954                        ms_error("AudioUnitSetProperty %x", err);
955
956                if(err == noErr) {
957                        if(AudioOutputUnitStart(d->caOutAudioUnit) == noErr)
958                                d->write_started=TRUE;
959                }
960        }
961}
962
963static void ca_stop_w(CAData *d){
964        OSErr err;
965        if(d->write_started == TRUE) {
966                if(AudioOutputUnitStop(d->caOutAudioUnit) == noErr)
967                        d->write_started=FALSE;
968        }
969        if (d->caOutConverter!=NULL)
970        {
971                AudioConverterDispose(d->caOutConverter);
972                d->caOutConverter=NULL;
973        }
974        if (d->caOutAudioUnit!=NULL)
975        {
976                AudioUnitUninitialize(d->caOutAudioUnit);
977                d->caOutAudioUnit=NULL;
978        }       
979}
980
981
982static mblk_t *ca_get(CAData *d){
983        mblk_t *m;
984        ms_mutex_lock(&d->mutex);
985        m=getq(&d->rq);
986        ms_mutex_unlock(&d->mutex);
987        return m;
988}
989
990static void ca_put(CAData *d, mblk_t *m){
991        ms_mutex_lock(&d->mutex);
992        ms_bufferizer_put(d->bufferizer,m);
993        ms_mutex_unlock(&d->mutex);
994}
995
996
997static void ca_init(MSFilter *f){
998        CAData *d = ms_new0(CAData, 1);
999        d->read_started=FALSE;
1000        d->write_started=FALSE;
1001        d->bits=16;
1002        d->rate=8000;
1003        d->stereo=FALSE;
1004        qinit(&d->rq);
1005        d->bufferizer=ms_bufferizer_new();
1006        ms_mutex_init(&d->mutex,NULL);
1007        f->data=d;
1008}       
1009
1010static void ca_uninit(MSFilter *f){
1011        CAData *d = (CAData *) f->data;
1012        ms_bufferizer_destroy(d->bufferizer);
1013        flushq(&d->rq,0);
1014        ms_mutex_destroy(&d->mutex);
1015        ms_free(d);
1016}
1017
1018static void ca_read_preprocess(MSFilter *f){
1019        CAData *d = (CAData *) f->data;
1020        ca_start_r(d);
1021}
1022
1023static void ca_read_postprocess(MSFilter *f){
1024        CAData *d = (CAData *) f->data;
1025        ca_stop_r(d);
1026}
1027
1028static void ca_read_process(MSFilter *f){
1029        CAData *d = (CAData *) f->data;
1030        mblk_t *m;
1031        while((m=ca_get(d))!=NULL){
1032                ms_queue_put(f->outputs[0],m);
1033        }
1034}
1035
1036static void ca_write_preprocess(MSFilter *f){
1037        CAData *d = (CAData *) f->data;
1038        ca_start_w(d);
1039}
1040
1041static void ca_write_postprocess(MSFilter *f){
1042        CAData *d = (CAData *) f->data;
1043        ca_stop_w(d);
1044}
1045
1046static void ca_write_process(MSFilter *f){
1047        CAData *d = (CAData *) f->data;
1048        mblk_t *m;
1049        while((m=ms_queue_get(f->inputs[0]))!=NULL){
1050                ca_put(d,m);
1051        }
1052}
1053
1054static int set_rate(MSFilter *f, void *arg){
1055        CAData *d = (CAData *) f->data;
1056        d->rate = *((int *) arg);
1057        return 0;
1058}
1059
1060static int get_rate(MSFilter * f, void *arg)
1061{
1062        CAData *d = (CAData *) f->data;
1063        *((int *) arg) = d->rate;
1064        return 0;
1065}
1066
1067static int set_nchannels(MSFilter *f, void *arg){
1068        CAData *d = (CAData *) f->data;
1069        d->stereo=(*((int*)arg)==2);
1070        return 0;
1071}
1072
1073static MSFilterMethod ca_methods[]={
1074        {       MS_FILTER_SET_SAMPLE_RATE       , set_rate      },
1075        {       MS_FILTER_GET_SAMPLE_RATE       , get_rate },
1076        {       MS_FILTER_SET_NCHANNELS         , set_nchannels },
1077        {       0                               , NULL          }
1078};
1079
1080MSFilterDesc ca_read_desc={
1081        .id=MS_CA_READ_ID,
1082        .name="MSCARead",
1083        .text=N_("Sound capture filter for MacOS X Core Audio drivers"),
1084        .category=MS_FILTER_OTHER,
1085        .ninputs=0,
1086        .noutputs=1,
1087        .init=ca_init,
1088        .preprocess=ca_read_preprocess,
1089        .process=ca_read_process,
1090        .postprocess=ca_read_postprocess,
1091        .uninit=ca_uninit,
1092        .methods=ca_methods
1093};
1094
1095MSFilterDesc ca_write_desc={
1096        .id=MS_CA_WRITE_ID,
1097        .name="MSCAWrite",
1098        .text=N_("Sound playback filter for MacOS X Core Audio drivers"),
1099        .category=MS_FILTER_OTHER,
1100        .ninputs=1,
1101        .noutputs=0,
1102        .init=ca_init,
1103        .preprocess=ca_write_preprocess,
1104        .process=ca_write_process,
1105        .postprocess=ca_write_postprocess,
1106        .uninit=ca_uninit,
1107        .methods=ca_methods
1108};
1109
1110MSFilter *ms_ca_read_new(MSSndCard *card){
1111        MSFilter *f = ms_filter_new_from_desc(&ca_read_desc);
1112        CaSndDsCard *wc = (CaSndDsCard *) card->data;
1113        CAData *d = (CAData *) f->data;
1114        d->dev = wc->dev;
1115        return f;
1116}
1117
1118
1119MSFilter *ms_ca_write_new(MSSndCard *card){
1120        MSFilter *f=ms_filter_new_from_desc(&ca_write_desc);
1121        CaSndDsCard *wc = (CaSndDsCard *) card->data;
1122        CAData *d = (CAData *) f->data;
1123        d->dev = wc->dev;
1124        return f;
1125}
1126
1127MS_FILTER_DESC_EXPORT(ca_read_desc)
1128MS_FILTER_DESC_EXPORT(ca_write_desc)
Note: See TracBrowser for help on using the repository browser.