source: mediastreamer2/src/macsnd.c @ 1321:948eb8757c20

Last change on this file since 1321:948eb8757c20 was 1321:948eb8757c20, checked in by Simon Morlat <simon.morlat@…>, 2 years ago

iwip

File size: 17.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//#include <CoreServices/CarbonCore/Debugging.h>
52
53#include "mediastreamer2/mssndcard.h"
54#include "mediastreamer2/msfilter.h"
55
56
57MSFilter *ms_au_read_new(MSSndCard *card);
58MSFilter *ms_au_write_new(MSSndCard *card);
59
60#define CHECK_AURESULT(call)    do{ int _err; if ((_err=(call))!=noErr) ms_error( #call ": error [%i] %s %s",_err,GetMacOSStatusErrorString(_err),GetMacOSStatusCommentString(_err)); }while(0)
61
62typedef struct AUCommon{
63        int dev;
64        int rate;
65        int nchannels;
66        AudioUnit au;
67        ms_mutex_t mutex;
68} AUCommon;
69
70typedef struct AURead{
71        AUCommon common;
72        queue_t rq;
73}AURead;
74
75typedef struct AUWrite{
76        AUCommon common;
77        MSBufferizer *buffer;
78}AUWrite;
79
80
81typedef struct AuCard {
82        char * uidname;
83        AudioDeviceID dev;
84        int removed;
85} AuCard;
86
87static void au_card_set_level(MSSndCard *card, MSSndCardMixerElem e, int percent)
88{
89}
90
91static int au_card_get_level(MSSndCard *card, MSSndCardMixerElem e)
92{
93        return -1;
94}
95
96static void au_card_set_source(MSSndCard *card, MSSndCardCapture source)
97{
98}
99
100static void au_card_init(MSSndCard * card)
101{
102        AuCard *c = (AuCard *) ms_new0(AuCard, 1);
103        c->removed = 0;
104        card->data = c;
105}
106
107static void au_card_uninit(MSSndCard * card)
108{
109        AuCard *d = (AuCard *) card->data;
110        if (d->uidname != NULL)
111                ms_free(d->uidname);
112        ms_free(d);
113}
114
115static void au_card_detect(MSSndCardManager *m);
116static MSSndCard *au_card_duplicate(MSSndCard *obj);
117
118MSSndCardDesc ca_card_desc={
119        .driver_type="AudioUnit",
120        .detect=au_card_detect,
121        .init=au_card_init,
122        .set_level=au_card_set_level,
123        .get_level=au_card_get_level,
124        .set_capture=au_card_set_source,
125        .set_control=NULL,
126        .get_control=NULL,
127        .create_reader=ms_au_read_new,
128        .create_writer=ms_au_write_new,
129        .uninit=au_card_uninit,
130        .duplicate=au_card_duplicate
131};
132
133static MSSndCard *au_card_duplicate(MSSndCard * obj)
134{
135        AuCard *ca;
136        AuCard *cadup;
137        MSSndCard *card = ms_snd_card_new(&ca_card_desc);
138        card->name = ms_strdup(obj->name);
139        card->data = ms_new0(AuCard, 1);
140        memcpy(card->data, obj->data, sizeof(AuCard));
141        ca = obj->data;
142        cadup = card->data;
143        cadup->uidname = ms_strdup(ca->uidname);
144        return card;
145}
146
147static MSSndCard *ca_card_new(const char *name, const char * uidname, AudioDeviceID dev, unsigned cap)
148{
149        MSSndCard *card = ms_snd_card_new(&ca_card_desc);
150        AuCard *d = (AuCard *) card->data;
151        d->uidname = ms_strdup(uidname);
152        d->dev = dev;
153        card->name = ms_strdup(name);
154        card->capabilities = cap;
155        return card;
156}
157
158static void show_format(const char *name, AudioStreamBasicDescription * deviceFormat)
159{
160        ms_message("Format for %s", name);
161        ms_message("mSampleRate = %g", deviceFormat->mSampleRate);
162        char *the4CCString = (char *) &deviceFormat->mFormatID;
163        char outName[5];
164        outName[0] = the4CCString[0];
165        outName[1] = the4CCString[1];
166        outName[2] = the4CCString[2];
167        outName[3] = the4CCString[3];
168        outName[4] = 0;
169        ms_message("mFormatID = %s", outName);
170        ms_message("mFormatFlags = %08lX", deviceFormat->mFormatFlags);
171        ms_message("mBytesPerPacket = %ld", deviceFormat->mBytesPerPacket);
172        ms_message("mFramesPerPacket = %ld", deviceFormat->mFramesPerPacket);
173        ms_message("mChannelsPerFrame = %ld", deviceFormat->mChannelsPerFrame);
174        ms_message("mBytesPerFrame = %ld", deviceFormat->mBytesPerFrame);
175        ms_message("mBitsPerChannel = %ld", deviceFormat->mBitsPerChannel);
176}
177
178static bool_t check_card_capability(AudioDeviceID id, bool_t is_input, char * devname, char *uidname, size_t name_len){
179        unsigned int slen=name_len;
180        Boolean writable=0;
181        CFStringRef dUID=NULL;
182        bool_t ret=FALSE;
183
184        int err =AudioDeviceGetProperty(id, 0, is_input, kAudioDevicePropertyDeviceName, &slen,devname);
185        if (err != kAudioHardwareNoError) {
186                ms_error("get kAudioDevicePropertyDeviceName error %ld", err);
187                return FALSE;
188        }
189        err =AudioDeviceGetPropertyInfo(id, 0, is_input, kAudioDevicePropertyStreamConfiguration, &slen, &writable);
190        if (err != kAudioHardwareNoError) {
191                ms_error("get kAudioDevicePropertyDeviceName error %ld", err);
192                return FALSE;
193        }
194               
195        AudioBufferList *buflist = ms_malloc(slen);
196               
197        err =
198        AudioDeviceGetProperty(id, 0, is_input, kAudioDevicePropertyStreamConfiguration, &slen, buflist);
199        if (err != kAudioHardwareNoError) {
200                ms_error("get kAudioDevicePropertyDeviceName error %ld", err);
201                ms_free(buflist);
202                return FALSE;
203        }
204               
205        UInt32 j;
206        for (j = 0; j < buflist->mNumberBuffers; j++) {
207                if (buflist->mBuffers[j].mNumberChannels > 0) {
208                        ret=TRUE;
209                        break;
210                }
211        }
212        ms_free(buflist);
213        if (ret==FALSE) return FALSE;
214       
215        slen = sizeof(CFStringRef);
216        err =AudioDeviceGetProperty(id, 0, is_input, kAudioDevicePropertyDeviceUID, &slen,&dUID);
217        if (err != kAudioHardwareNoError) {
218                ms_error("get kAudioHardwarePropertyDevices error %ld", err);
219                return FALSE;
220        }
221        CFStringGetCString(dUID, uidname, sizeof(uidname),CFStringGetSystemEncoding());
222        ms_message("CA: devname:%s uidname:%s", devname, uidname);
223                       
224        AudioStreamBasicDescription devicewriteFormat;
225        slen = sizeof(devicewriteFormat);
226        err = AudioDeviceGetProperty(id, 0, is_input, kAudioDevicePropertyStreamFormat, &slen, &devicewriteFormat);
227        if (err == kAudioHardwareNoError) {
228                show_format("output device", &devicewriteFormat);
229        }
230        return ret;
231}
232
233static void au_card_detect(MSSndCardManager * m)
234{
235        OSStatus err;
236        UInt32 slen;
237        int count;
238        Boolean writable;
239        int i;
240        writable = 0;
241        slen = 0;
242        err =
243        AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &slen,
244                                                                 &writable);
245        if (err != kAudioHardwareNoError) {
246                ms_error("get kAudioHardwarePropertyDevices error %ld", err);
247                return;
248        }
249        AudioDeviceID devices[slen / sizeof(AudioDeviceID)];
250        err =
251        AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &slen, devices);
252        if (err != kAudioHardwareNoError) {
253                ms_error("get kAudioHardwarePropertyDevices error %ld", err);
254                return;
255        }
256        count = slen / sizeof(AudioDeviceID);
257        for (i = 0; i < count; i++) {
258                MSSndCard *card;
259                char uidname[256]={0},devname[256]={0};
260                if (check_card_capability(devices[i],FALSE,devname,uidname,sizeof(uidname))){
261                        card=ca_card_new(devname, uidname, devices[i], MS_SND_CARD_CAP_PLAYBACK);
262                        ms_snd_card_manager_add_card(m, card);
263                }
264                if (check_card_capability(devices[i],TRUE,devname,uidname,sizeof(uidname))){
265                        card=ca_card_new(devname, uidname, devices[i], MS_SND_CARD_CAP_CAPTURE);
266                        ms_snd_card_manager_add_card(m, card);
267                }
268        }
269}
270
271
272static OSStatus readRenderProc(void *inRefCon, 
273                                                AudioUnitRenderActionFlags *inActionFlags,
274                                                const AudioTimeStamp *inTimeStamp, 
275                                                UInt32 inBusNumber,
276                                                UInt32 inNumFrames, 
277                                                AudioBufferList *ioData)
278{
279        AURead *d=(AURead*)inRefCon;
280       
281        CHECK_AURESULT(AudioUnitRender(d->common.au, inActionFlags, inTimeStamp, inBusNumber,
282                                                  inNumFrames, ioData));
283        if( ioData==NULL)
284        {
285                return 0;
286        }
287        ms_message("Got input buffer of size %i",ioData->mBuffers[0].mDataByteSize);
288        mblk_t *rm=NULL;
289        rm=allocb(ioData->mBuffers[0].mDataByteSize,0);
290        memcpy(rm->b_wptr, ioData->mBuffers[0].mData, ioData->mBuffers[0].mDataByteSize);
291        rm->b_wptr+=ioData->mBuffers[0].mDataByteSize;
292       
293        ms_mutex_lock(&d->common.mutex);
294        putq(&d->rq,rm);
295        ms_mutex_unlock(&d->common.mutex);
296        rm=NULL;
297       
298        return 0;
299}
300
301static OSStatus writeRenderProc(void *inRefCon, 
302                                                 AudioUnitRenderActionFlags *inActionFlags,
303                                                 const AudioTimeStamp *inTimeStamp, 
304                                                 UInt32 inBusNumber,
305                                                 UInt32 inNumFrames, 
306                                                 AudioBufferList *ioData)
307{
308        OSStatus err= noErr;
309        AUWrite *d=(AUWrite*)inRefCon;
310        int read;
311        ms_mutex_lock(&d->common.mutex);
312        read=ms_bufferizer_read(d->buffer,ioData->mBuffers[0].mData,ioData->mBuffers[0].mDataByteSize);
313        ms_mutex_unlock(&d->common.mutex);
314        if (read==0){
315                ms_warning("Silence inserted in audio output unit (%i bytes)",ioData->mBuffers[0].mDataByteSize);
316                memset(ioData->mBuffers[0].mData,0,ioData->mBuffers[0].mDataByteSize);
317        }
318        err = AudioUnitRender(d->common.au, inActionFlags, inTimeStamp, inBusNumber,inNumFrames, ioData);
319        if(err != noErr){
320                ms_error("AudioUnitRender() failed for write: %i",err);
321        }
322        return 0;
323}
324
325static int audio_unit_open(AUCommon *d, bool_t is_read){
326        OSStatus result;
327        UInt32 param;
328        ComponentDescription desc; 
329        Component comp;
330        AudioStreamBasicDescription asbd;
331        const int input_bus=1;
332        const int output_bus=0;
333       
334        // Get Default Input audio unit
335        desc.componentType = kAudioUnitType_Output;
336        desc.componentSubType = kAudioUnitSubType_HALOutput;
337        desc.componentManufacturer = kAudioUnitManufacturer_Apple;
338        desc.componentFlags = 0;
339        desc.componentFlagsMask = 0;
340       
341        comp = FindNextComponent(NULL, &desc);
342        if (comp == NULL)
343        {
344                ms_message("Cannot find audio component");
345                return -1;
346        }
347       
348        result = OpenAComponent(comp, &d->au);
349        if(result != noErr)
350        {
351                ms_message("Cannot open audio component %x", result);
352                return -1;
353        }
354       
355        param = is_read;
356        CHECK_AURESULT(AudioUnitSetProperty(d->au,
357                                  kAudioOutputUnitProperty_EnableIO,
358                                  kAudioUnitScope_Input,
359                                  input_bus,
360                                  &param,
361                                  sizeof(UInt32)));
362       
363        param = !is_read;
364        CHECK_AURESULT(AudioUnitSetProperty(d->au,
365                                  kAudioOutputUnitProperty_EnableIO,
366                                  kAudioUnitScope_Output,
367                                  output_bus,
368                                  &param,
369                                  sizeof(UInt32)));
370       
371       
372       
373        // Set the current device
374        CHECK_AURESULT(AudioUnitSetProperty(d->au,
375                                  kAudioOutputUnitProperty_CurrentDevice,
376                                  kAudioUnitScope_Global,
377                                  0,
378                                  &d->dev,
379                                  sizeof(AudioDeviceID)));
380       
381        UInt32 asbdsize = sizeof(AudioStreamBasicDescription);
382        memset((char *)&asbd, 0, asbdsize);
383       
384        CHECK_AURESULT(AudioUnitGetProperty(d->au,
385                           kAudioUnitProperty_StreamFormat,
386                           is_read ? kAudioUnitScope_Input : kAudioUnitScope_Output,
387                           is_read ? input_bus : output_bus,
388                           &asbd,
389                           &asbdsize));
390       
391        show_format(is_read ? "Input audio unit" : "Output audio unit",&asbd);
392        if (asbd.mChannelsPerFrame>1)
393        {
394                asbd.mBytesPerFrame = asbd.mBytesPerFrame / asbd.mChannelsPerFrame;
395                asbd.mBytesPerPacket = asbd.mBytesPerPacket / asbd.mChannelsPerFrame;           
396                asbd.mChannelsPerFrame = 1;
397        }
398       
399        CHECK_AURESULT(AudioUnitSetProperty(d->au,
400                                          kAudioUnitProperty_StreamFormat,
401                                          is_read ? kAudioUnitScope_Input : kAudioUnitScope_Output ,
402                                          is_read ? output_bus : input_bus ,
403                                          &asbd,
404                                          sizeof(AudioStreamBasicDescription)));
405       
406        // Get the number of frames in the IO buffer(s)
407        param = sizeof(UInt32);
408        UInt32 fAudioSamples;
409        CHECK_AURESULT(AudioUnitGetProperty(d->au,
410                                          kAudioDevicePropertyBufferFrameSize,
411                                          kAudioUnitScope_Input,
412                                          1,
413                                          &fAudioSamples,
414                                          &param));
415       
416        result = AudioUnitInitialize(d->au);
417        if(result != noErr)
418        {
419                ms_error("failed to AudioUnitInitialize input %i", result);
420                return -1;
421        }
422        AURenderCallbackStruct cbs;
423       
424        cbs.inputProcRefCon = d;
425        if (is_read){
426                cbs.inputProc = readRenderProc;
427                CHECK_AURESULT(AudioUnitSetProperty(d->au,
428                                        kAudioOutputUnitProperty_SetInputCallback,
429                                        kAudioUnitScope_Global,
430                                        0,
431                                        &cbs,
432                                        sizeof(AURenderCallbackStruct)));
433        }else{
434                cbs.inputProc = writeRenderProc;
435                CHECK_AURESULT(AudioUnitSetProperty (d->au, 
436                            kAudioUnitProperty_SetRenderCallback, 
437                            kAudioUnitScope_Input, 
438                            0,
439                            &cbs, 
440                            sizeof(AURenderCallbackStruct)));
441        }
442
443        CHECK_AURESULT(AudioOutputUnitStart(d->au));
444        return 0;
445}
446
447static void audio_unit_close(AUCommon *d){
448       
449        CHECK_AURESULT(AudioOutputUnitStop(d->au));
450        CHECK_AURESULT(AudioUnitUninitialize(d->au));
451        d->au=NULL;
452}
453
454
455static mblk_t *au_read_get(AURead *d){
456        mblk_t *m;
457        ms_mutex_lock(&d->common.mutex);
458        m=getq(&d->rq);
459        ms_mutex_unlock(&d->common.mutex);
460        return m;
461}
462
463static void au_write_put(AUWrite *d, mblk_t *m){
464        ms_mutex_lock(&d->common.mutex);
465        ms_bufferizer_put(d->buffer,m);
466        ms_mutex_unlock(&d->common.mutex);
467}
468
469static void au_common_init(AUCommon *d){
470        d->rate=8000;
471        d->nchannels=1;
472        ms_mutex_init(&d->mutex,NULL);
473}
474
475static void au_common_uninit(AUCommon *d){
476        ms_mutex_destroy(&d->mutex);
477}
478
479static void au_read_init(MSFilter *f){
480        AURead *d = ms_new0(AURead, 1);
481        au_common_init(&d->common);
482        qinit(&d->rq);
483        f->data=d;
484}       
485
486static void au_read_preprocess(MSFilter *f){
487        AURead *d = (AURead *) f->data;
488        audio_unit_open(&d->common,TRUE);
489}
490
491static void au_read_process(MSFilter *f){
492        AURead *d = (AURead *) f->data;
493        mblk_t *m;
494        while((m=au_read_get(d))!=NULL){
495                ms_queue_put(f->outputs[0],m);
496        }
497}
498
499static void au_read_postprocess(MSFilter *f){
500        AURead *d = (AURead *) f->data;
501        audio_unit_close(&d->common);
502}
503
504static void au_read_uninit(MSFilter *f){
505        AURead *d = (AURead *) f->data;
506        flushq(&d->rq,0);
507        au_common_uninit(&d->common);
508        ms_free(d);
509}
510
511/* Audio unit write filter */
512
513static void au_write_init(MSFilter *f){
514        AUWrite *d = ms_new0(AUWrite, 1);
515        au_common_init(&d->common);
516        d->buffer=ms_bufferizer_new();
517        f->data=d;
518}       
519
520static void au_write_preprocess(MSFilter *f){
521        AUWrite *d = (AUWrite *) f->data;
522        audio_unit_open(&d->common,FALSE);
523}
524
525static void au_write_process(MSFilter *f){
526        AUWrite *d = (AUWrite *) f->data;
527        mblk_t *m;
528        while((m=ms_queue_get(f->inputs[0]))!=NULL){
529                au_write_put(d,m);
530        }
531}
532
533static void au_write_postprocess(MSFilter *f){
534        AUWrite *d = (AUWrite *) f->data;
535        audio_unit_close(&d->common);
536}
537
538static void au_write_uninit(MSFilter *f){
539        AUWrite *d = (AUWrite *) f->data;
540        ms_bufferizer_destroy(d->buffer);
541        au_common_uninit(&d->common);
542        ms_free(d);
543}
544
545static int set_rate(MSFilter *f, void *arg){
546        AUCommon *d = (AUCommon *) f->data;
547        d->rate = *((int *) arg);
548        return 0;
549}
550
551static int get_rate(MSFilter * f, void *arg)
552{
553        AUCommon *d = (AUCommon *) f->data;
554        *((int *) arg) = d->rate;
555        return 0;
556}
557
558static int set_nchannels(MSFilter *f, void *arg){
559        AUCommon *d = (AUCommon *) f->data;
560        d->nchannels=*((int*)arg);
561        return 0;
562}
563
564static MSFilterMethod au_methods[]={
565        {       MS_FILTER_SET_SAMPLE_RATE       , set_rate      },
566        {       MS_FILTER_GET_SAMPLE_RATE       , get_rate },
567        {       MS_FILTER_SET_NCHANNELS         , set_nchannels },
568        {       0                               , NULL          }
569};
570
571MSFilterDesc ms_au_read_desc={
572        .id=MS_CA_READ_ID,
573        .name="MSAuRead",
574        .text=N_("Sound capture filter for MacOS X Audio Unit"),
575        .category=MS_FILTER_OTHER,
576        .ninputs=0,
577        .noutputs=1,
578        .init=au_read_init,
579        .preprocess=au_read_preprocess,
580        .process=au_read_process,
581        .postprocess=au_read_postprocess,
582        .uninit=au_read_uninit,
583        .methods=au_methods
584};
585
586MSFilterDesc ms_au_write_desc={
587        .id=MS_CA_WRITE_ID,
588        .name="MSAuWrite",
589        .text=N_("Sound playback filter for MacOS X Audio Unit"),
590        .category=MS_FILTER_OTHER,
591        .ninputs=1,
592        .noutputs=0,
593        .init=au_write_init,
594        .preprocess=au_write_preprocess,
595        .process=au_write_process,
596        .postprocess=au_write_postprocess,
597        .uninit=au_write_uninit,
598        .methods=au_methods
599};
600
601MSFilter *ms_au_read_new(MSSndCard *card){
602        MSFilter *f = ms_filter_new_from_desc(&ms_au_read_desc);
603        AuCard *wc = (AuCard *) card->data;
604        AURead *d = (AURead *) f->data;
605        d->common.dev = wc->dev;
606        return f;
607}
608
609
610MSFilter *ms_au_write_new(MSSndCard *card){
611        MSFilter *f=ms_filter_new_from_desc(&ms_au_write_desc);
612        AuCard *wc = (AuCard *) card->data;
613        AUWrite *d = (AUWrite *) f->data;
614        d->common.dev = wc->dev;
615        return f;
616}
617
618MS_FILTER_DESC_EXPORT(ms_au_read_desc)
619MS_FILTER_DESC_EXPORT(ms_au_write_desc)
620
621
Note: See TracBrowser for help on using the repository browser.