source: mediastreamer2/src/msiounit.c @ 1116:c97579eb19a5

Last change on this file since 1116:c97579eb19a5 was 1116:c97579eb19a5, checked in by Jehan Monnier <jehan.monnier@…>, 3 years ago

add audiot unit base iPhone sound integration

File size: 18.2 KB
Line 
1/*
2 * auiosnd.c -I/O unit Media plugin for Linphone-
3 *
4 *
5 * Copyright (C) 2009  Belledonne Comunications, Grenoble, France
6 *
7 *  This program is free software; you can redistribute it and/or modify
8 *  it under the terms of the GNU General Public License as published by
9 *  the Free Software Foundation; either version 2 of the License, or
10 *  (at your option) any later version.
11 *
12 *  This program is distributed in the hope that it will be useful,
13 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 *  GNU Library General Public License for more details.
16 *
17 *  You should have received a copy of the GNU General Public License
18 *  along with this program; if not, write to the Free Software
19 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 */
21#include <AudioToolbox/AudioToolbox.h>
22#include "mediastreamer2/mssndcard.h"
23#include "mediastreamer2/msfilter.h"
24
25#define PREFERRED_HW_SAMPLE_RATE 44100
26
27#if 0
28#undef ms_debug
29#define ms_debug ms_message
30#endif
31
32static MSFilter *ms_au_read_new(MSSndCard *card);
33static MSFilter *ms_au_write_new(MSSndCard *card);
34
35typedef struct AUData_t{
36        AudioUnit       io_unit;
37        unsigned int    rate;
38        unsigned int    bits;
39        unsigned int    nchannels;
40        ms_mutex_t      mutex;
41        queue_t         rq;
42        MSBufferizer    *bufferizer;
43        bool_t          started;
44        bool_t          read_started;
45        bool_t          write_started;
46        AudioTimeStamp readTimeStamp;
47        unsigned int n_lost_frame;
48        bool_t io_unit_must_be_started;
49} AUData;
50
51
52/*
53 mediastreamer2 function
54 */
55
56static void au_set_level(MSSndCard *card, MSSndCardMixerElem e, int percent)
57{
58}
59
60static int au_get_level(MSSndCard *card, MSSndCardMixerElem e)
61{
62        return 0;
63}
64
65static void au_set_source(MSSndCard *card, MSSndCardCapture source)
66{
67}
68
69static void au_init(MSSndCard *card){
70        ms_debug("au_init");
71        AUData *d=ms_new(AUData,1);
72        //OSStatus auresult;
73        d->bits=16;
74        d->rate=PREFERRED_HW_SAMPLE_RATE;
75        d->nchannels=1;
76       
77        d->read_started=FALSE;
78        d->write_started=FALSE;
79        d->bufferizer=ms_bufferizer_new();
80        d->n_lost_frame=0;
81        d->started=FALSE;
82        d->io_unit_must_be_started=FALSE;
83        qinit(&d->rq);
84        d->readTimeStamp.mSampleTime=-1;
85        ms_mutex_init(&d->mutex,NULL);
86        card->data=d;
87}
88
89static void au_uninit(MSSndCard *card){
90        AUData *d=(AUData*)card->data;
91        ms_bufferizer_destroy(d->bufferizer);
92        ms_mutex_destroy(&d->mutex);
93        ms_free(d);
94}
95
96static void au_detect(MSSndCardManager *m);
97static MSSndCard *au_duplicate(MSSndCard *obj);
98
99MSSndCardDesc au_card_desc={
100.driver_type="AU",
101.detect=au_detect,
102.init=au_init,
103.set_level=au_set_level,
104.get_level=au_get_level,
105.set_capture=au_set_source,
106.set_control=NULL,
107.get_control=NULL,
108.create_reader=ms_au_read_new,
109.create_writer=ms_au_write_new,
110.uninit=au_uninit,
111.duplicate=au_duplicate
112};
113
114static MSSndCard *au_duplicate(MSSndCard *obj){
115        MSSndCard *card=ms_snd_card_new(&au_card_desc);
116        card->name=ms_strdup(obj->name);
117        return card;
118}
119#define check_auresult(au,method) \
120if (au!=0) ms_error("AudioUnit error for %s: ret=%i",method,au)
121
122static void au_interuption_listener(void* inClientData, UInt32 inInterruptionState) {
123        if (((MSSndCard*)inClientData)->data == NULL) return;
124       
125        AUData *d=(AUData*)(((MSSndCard*)inClientData)->data);
126        if (d->started == FALSE) {
127                //nothing to do
128                return;
129        }
130        switch (inInterruptionState) {
131                case kAudioSessionBeginInterruption:
132                        ms_message ("IO unit interruption begin");
133                        AudioOutputUnitStop(d->io_unit);
134                        break;
135                case kAudioSessionEndInterruption:
136                        // make sure we are again the active session
137                        ms_message ("IO unit interruption end");
138                        OSStatus auresult = AudioSessionSetActive(true);
139                        check_auresult(auresult,"AudioSessionSetActive");
140                        d->io_unit_must_be_started=TRUE;
141                        break;
142                default:
143                        ms_warning ("unexpected interuption %i",inInterruptionState);
144        }
145}
146
147static MSSndCard *au_card_new(){
148        MSSndCard *card=ms_snd_card_new(&au_card_desc);
149        card->name=ms_strdup("Audio Unit");
150        OSStatus auresult = AudioSessionInitialize(NULL, NULL, au_interuption_listener, card);
151        check_auresult(auresult,"AudioSessionInitialize");
152        return card;
153}
154
155static void au_detect(MSSndCardManager *m){
156        ms_debug("au_detect");
157        MSSndCard *card=au_card_new();
158        ms_snd_card_manager_add_card(m,card);
159}
160
161static OSStatus au_read_cb (
162                                                          void                        *inRefCon,
163                                                          AudioUnitRenderActionFlags  *ioActionFlags,
164                                                          const AudioTimeStamp        *inTimeStamp,
165                                                          UInt32                      inBusNumber,
166                                                          UInt32                      inNumberFrames,
167                                                          AudioBufferList             *ioData
168)
169{
170        AUData *d=(AUData*)inRefCon;
171        if (d->readTimeStamp.mSampleTime <0) {
172                d->readTimeStamp=*inTimeStamp;
173        }
174        OSStatus err=0;
175        mblk_t * rm=NULL;
176        if (d->read_started) {
177                rm=allocb(ioData->mBuffers[0].mDataByteSize,0);
178                ioData->mBuffers[0].mData=rm->b_wptr;
179        }
180        err = AudioUnitRender(d->io_unit, ioActionFlags, &d->readTimeStamp, inBusNumber,inNumberFrames, ioData);
181        if (d->read_started){
182                if (err == 0) {
183                        rm->b_wptr += ioData->mBuffers[0].mDataByteSize;
184                        ms_mutex_lock(&d->mutex);
185                        putq(&d->rq,rm);
186                        ms_mutex_unlock(&d->mutex);
187                        d->readTimeStamp.mSampleTime+=ioData->mBuffers[0].mDataByteSize/(d->bits/2);
188                }else ms_warning("AudioUnitRender() failed: %i",err);
189        }
190        return err;
191}
192
193/********************read/write cb******************/
194
195static OSStatus au_render_cb (
196                                                          void                        *inRefCon,
197                                                          AudioUnitRenderActionFlags  *ioActionFlags,
198                                                          const AudioTimeStamp        *inTimeStamp,
199                                                          UInt32                      inBusNumber,
200                                                          UInt32                      inNumberFrames,
201                                                          AudioBufferList             *ioData
202) {
203        ms_debug("render cb");
204        AUData *d=(AUData*)inRefCon;
205       
206        if (d->write_started == TRUE) {
207                ms_mutex_lock(&d->mutex);
208                if(ms_bufferizer_get_avail(d->bufferizer) >= inNumberFrames*d->bits/8) {
209                        ms_bufferizer_read(d->bufferizer, ioData->mBuffers[0].mData, inNumberFrames*d->bits/8);
210
211                        if (ms_bufferizer_get_avail(d->bufferizer) >10*inNumberFrames*d->bits/8) {
212                                ms_debug("we are late, bufferizer sise is %i bytes in framezize is %i bytes",ms_bufferizer_get_avail(d->bufferizer),inNumberFrames*d->bits/8);
213                                ms_bufferizer_flush(d->bufferizer);
214                        }
215                        ioData->mBuffers[0].mDataByteSize=inNumberFrames*d->bits/8;
216                        ms_mutex_unlock(&d->mutex);
217                       
218                       
219                } else {
220                       
221                        ms_mutex_unlock(&d->mutex);
222                        memset(ioData->mBuffers[0].mData, 0,ioData->mBuffers[0].mDataByteSize);
223                        ms_debug("nothing to write, pushing silences, bufferizer sise is %i bytes in framezize is %i bytes mDataByteSize %i"
224                                         ,ms_bufferizer_get_avail(d->bufferizer)
225                                         ,inNumberFrames*d->bits/8
226                                         ,ioData->mBuffers[0].mDataByteSize);
227                        d->n_lost_frame+=inNumberFrames;
228                }
229                AudioBufferList readAudioBufferList;
230                readAudioBufferList.mBuffers[0].mDataByteSize=inNumberFrames*d->bits/8; 
231                readAudioBufferList.mNumberBuffers=1;
232                readAudioBufferList.mBuffers[0].mData=NULL;
233                readAudioBufferList.mBuffers[0].mNumberChannels=d->nchannels;
234                AudioUnitElement inputBus = 1;
235                au_read_cb(d, ioActionFlags, inTimeStamp, inputBus, inNumberFrames, &readAudioBufferList);
236        }
237        return 0;
238}
239
240/****************config**************/
241
242static void au_configure(AUData *d) {
243        AudioStreamBasicDescription audioFormat;
244        AudioComponentDescription au_description;
245        AudioComponent foundComponent;
246        OSStatus auresult;
247       
248        if (d->started == TRUE) {
249                //nothing to do
250                return;
251        }
252       
253        auresult = AudioSessionSetActive(true);
254        check_auresult(auresult,"AudioSessionSetActive");
255
256        UInt32 audioCategory = kAudioSessionCategory_PlayAndRecord;
257        auresult =AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(audioCategory), &audioCategory);
258        check_auresult(auresult,"Configuring audio session for play/record");
259       
260        au_description.componentType          = kAudioUnitType_Output;
261        au_description.componentSubType       = kAudioUnitSubType_VoiceProcessingIO;
262        au_description.componentManufacturer  = kAudioUnitManufacturer_Apple;
263        au_description.componentFlags         = 0;
264        au_description.componentFlagsMask     = 0;
265       
266        foundComponent = AudioComponentFindNext (NULL,&au_description);
267       
268        auresult=AudioComponentInstanceNew (foundComponent, &d->io_unit);
269       
270        check_auresult(auresult,"AudioComponentInstanceNew");
271
272        audioFormat.mSampleRate                 = d->rate;
273        audioFormat.mFormatID                   = kAudioFormatLinearPCM;
274        audioFormat.mFormatFlags                = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
275        audioFormat.mFramesPerPacket    = 1;
276        audioFormat.mChannelsPerFrame   = d->nchannels;
277        audioFormat.mBitsPerChannel             = d->bits;
278        audioFormat.mBytesPerPacket             = d->bits / 8;
279        audioFormat.mBytesPerFrame              = d->nchannels * d->bits / 8;
280        UInt32 doSetProperty      = 1;
281        UInt32 doNotSetProperty    = 0;
282        AudioUnitElement outputBus = 0;
283        AudioUnitElement inputBus = 1;
284        auresult=AudioUnitUninitialize (d->io_unit);
285       
286        check_auresult(auresult,"AudioUnitUninitialize");
287       
288        //read
289        auresult=AudioUnitSetProperty (
290                                                                   d->io_unit,
291                                                                   kAudioOutputUnitProperty_EnableIO,
292                                                                   kAudioUnitScope_Input ,
293                                                                   inputBus,
294                                                                   &doSetProperty,
295                                                                   sizeof (doSetProperty)
296                                                                   );
297        check_auresult(auresult,"kAudioOutputUnitProperty_EnableIO,kAudioUnitScope_Input");
298       
299        auresult=AudioUnitSetProperty (
300                                                                   d->io_unit,
301                                                                   kAudioUnitProperty_StreamFormat,
302                                                                   kAudioUnitScope_Output,
303                                                                   inputBus,
304                                                                   &audioFormat,
305                                                                   sizeof (audioFormat)
306                                                                   );
307        check_auresult(auresult,"kAudioUnitProperty_StreamFormat,kAudioUnitScope_Output");
308        //write
309        //enable output bus
310        auresult =AudioUnitSetProperty (
311                                                                        d->io_unit,
312                                                                        kAudioOutputUnitProperty_EnableIO,
313                                                                        kAudioUnitScope_Output ,
314                                                                        outputBus,
315                                                                        &doSetProperty,
316                                                                        sizeof (doSetProperty)
317                                                                        );
318        check_auresult(auresult,"kAudioOutputUnitProperty_EnableIO,kAudioUnitScope_Output");
319       
320        //setup stream format
321        auresult=AudioUnitSetProperty (
322                                                                   d->io_unit,
323                                                                   kAudioUnitProperty_StreamFormat,
324                                                                   kAudioUnitScope_Input,
325                                                                   outputBus,
326                                                                   &audioFormat,
327                                                                   sizeof (audioFormat)
328                                                                   );
329        check_auresult(auresult,"kAudioUnitProperty_StreamFormat,kAudioUnitScope_Input");
330       
331        //disable unit buffer allocation
332        auresult=AudioUnitSetProperty (
333                                                                   d->io_unit,
334                                                                   kAudioUnitProperty_ShouldAllocateBuffer,
335                                                                   kAudioUnitScope_Output,
336                                                                   outputBus,
337                                                                   &doNotSetProperty,
338                                                                   sizeof (doNotSetProperty)
339                                                                   );
340        check_auresult(auresult,"kAudioUnitProperty_ShouldAllocateBuffer,kAudioUnitScope_Output");
341       
342       
343        AURenderCallbackStruct renderCallbackStruct;           
344        renderCallbackStruct.inputProc       = au_render_cb; 
345        renderCallbackStruct.inputProcRefCon = d;         
346       
347        auresult=AudioUnitSetProperty (
348                                                                   d->io_unit,                                 
349                                                                   kAudioUnitProperty_SetRenderCallback,       
350                                                                   kAudioUnitScope_Input,                       
351                                                                   outputBus,                                   
352                                                                   &renderCallbackStruct,                             
353                                                                   sizeof (renderCallbackStruct)                       
354                                                                   );
355        check_auresult(auresult,"kAudioUnitProperty_SetRenderCallback,kAudioUnitScope_Input");
356       
357        const Float64 preferredSampleRate = d->rate;//PREFERRED_HW_SAMPLE_RATE; /*optimum to minimize delay, must put a software resampler to deal with 8khz*/
358       
359        auresult=AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareSampleRate
360                                                                         ,sizeof(preferredSampleRate)
361                                                                         , &preferredSampleRate);
362        check_auresult(auresult,"kAudioSessionProperty_PreferredHardwareSampleRate");
363       
364       
365        //start io unit
366        auresult=AudioUnitInitialize (d->io_unit);
367        Float32 preferredBufferSize;
368        switch (d->rate) {
369                case 11025:
370                case 22050:
371                        preferredBufferSize= .020;
372                        break;
373                default:
374                        preferredBufferSize= .015;
375        }
376                       
377        auresult=AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration
378                                                                         ,sizeof(preferredBufferSize)
379                                                                         , &preferredBufferSize);
380       
381       
382        if (auresult != 0) ms_message("kAudioSessionProperty_PreferredHardwareIOBufferDuration returns %i ",auresult);
383       
384        Float64 delay;
385        UInt32 delaySize = sizeof(delay);
386        auresult=AudioUnitGetProperty(d->io_unit
387                                                                  ,kAudioUnitProperty_Latency
388                                                                  , kAudioUnitScope_Global
389                                                                  , 0
390                                                                  , &delay
391                                                                  , &delaySize);
392
393        UInt32 quality;
394        UInt32 qualitySize = sizeof(quality);
395        auresult=AudioUnitGetProperty(d->io_unit
396                                                                  ,kAudioUnitProperty_RenderQuality
397                                                                  , kAudioUnitScope_Global
398                                                                  , 0
399                                                                  , &quality
400                                                                  , &qualitySize);
401       
402       
403       
404        ms_message("I/O unit latency [%f], quality [%i]",delay,quality);
405        Float32 hwoutputlatency;
406        UInt32 hwoutputlatencySize=sizeof(hwoutputlatency);
407        auresult=AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareOutputLatency
408                                                                         ,&hwoutputlatencySize
409                                                                         , &hwoutputlatency);
410        Float32 hwinputlatency;
411        UInt32 hwinputlatencySize=sizeof(hwoutputlatency);
412        auresult=AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareInputLatency
413                                                                         ,&hwinputlatencySize
414                                                                         , &hwinputlatency);
415       
416        Float32 hwiobuf;
417        UInt32 hwiobufSize=sizeof(hwiobuf);
418        auresult=AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareIOBufferDuration
419                                                                         ,&hwiobufSize
420                                                                         , &hwiobuf);
421       
422        Float64 hwsamplerate;
423        UInt32 hwsamplerateSize=sizeof(hwsamplerate);
424        auresult=AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareSampleRate
425                                                                         ,&hwsamplerateSize
426                                                                         ,&hwsamplerate);
427
428        ms_message("current hw output latency [%f] input [%f] iobuf[%f] sample rate [%f]",hwoutputlatency,hwinputlatency,hwiobuf,hwsamplerate);
429        auresult=AudioOutputUnitStart(d->io_unit);
430        check_auresult(auresult,"AudioOutputUnitStart");
431        d->started=TRUE;
432        return;
433}       
434
435static void au_configure_read(AUData *d) {
436        d->read_started=TRUE;
437        au_configure(d);
438        ms_mutex_lock(&d->mutex);
439        flushq(&d->rq,0);
440        ms_mutex_unlock(&d->mutex);
441       
442}
443
444static void au_configure_write(AUData *d) {
445        d->write_started=TRUE;
446        au_configure(d);
447        ms_mutex_lock(&d->mutex);
448        ms_bufferizer_flush(d->bufferizer);
449        ms_mutex_unlock(&d->mutex);     
450}
451
452
453static void au_unconfigure(AUData *d) {
454        if (d->write_started==FALSE && d->read_started==FALSE) {
455                AudioUnitUninitialize(d->io_unit);
456                AudioOutputUnitStop(d->io_unit);
457                AudioComponentInstanceDispose (d->io_unit);
458                d->started=FALSE;
459        }
460}
461
462static void au_unconfigure_read(AUData *d){
463        if(d->read_started == TRUE) {
464                d->read_started=FALSE;
465                AudioUnitElement inputBus = 1;
466                AudioUnitReset(d->io_unit,
467                        kAudioUnitScope_Global,
468                        inputBus);
469        }
470        au_unconfigure(d);
471        ms_mutex_lock(&d->mutex);
472        flushq(&d->rq,0);
473        ms_mutex_unlock(&d->mutex);
474}
475
476static void au_unconfigure_write(AUData *d){
477        if(d->write_started == TRUE) {
478                d->write_started=FALSE;
479                AudioUnitElement outputBus = 0;
480                AudioUnitReset(d->io_unit,
481                        kAudioUnitScope_Global,
482                        outputBus);             
483        }
484        ms_message("[%i] frames of silence inserted for [%i] ms",d->n_lost_frame,(d->n_lost_frame*1000)/d->rate);
485        au_unconfigure(d);
486        ms_mutex_lock(&d->mutex);
487        ms_bufferizer_flush(d->bufferizer);
488        ms_mutex_unlock(&d->mutex);
489}
490
491
492
493
494/***********************************read function********************/
495
496static void au_read_preprocess(MSFilter *f){
497        ms_debug("au_read_preprocess");
498        AUData *d=(AUData*)((MSSndCard*)f->data)->data;
499        au_configure_read(d);
500       
501}
502
503static void au_read_postprocess(MSFilter *f){
504        AUData *d=(AUData*)((MSSndCard*)f->data)->data;
505        au_unconfigure_read(d);
506}
507
508static void au_read_process(MSFilter *f){
509        AUData *d=(AUData*)((MSSndCard*)f->data)->data;
510        mblk_t *m;
511        struct timeval tv;
512       
513        if (d->io_unit_must_be_started) {
514                gettimeofday(&tv, 0);
515                if ((tv.tv_usec % 10) == 0) { /*more or less every 100ms*/
516                        if (AudioOutputUnitStart(d->io_unit) == 0) {
517                                d->io_unit_must_be_started=FALSE;
518                        };
519                }
520        }
521        do {
522                ms_mutex_lock(&d->mutex);
523                m=getq(&d->rq);
524                ms_mutex_unlock(&d->mutex);
525                if (m != NULL) ms_queue_put(f->outputs[0],m); 
526        }while(m!=NULL);
527       
528}
529
530
531
532/***********************************write function********************/
533
534static void au_write_preprocess(MSFilter *f){
535        ms_debug("au_write_preprocess");
536        AUData *d=(AUData*)((MSSndCard*)f->data)->data;
537        au_configure_write(d);
538}
539
540static void au_write_postprocess(MSFilter *f){
541        ms_debug("au_write_postprocess");
542        AUData *d=(AUData*)((MSSndCard*)f->data)->data;
543        au_unconfigure_write(d);
544}
545
546
547
548static void au_write_process(MSFilter *f){
549        ms_debug("au_write_process");
550        mblk_t *m;
551        AUData *d=(AUData*)((MSSndCard*)f->data)->data;
552       
553        while((m=ms_queue_get(f->inputs[0]))!=NULL){
554                ms_mutex_lock(&d->mutex);
555                ms_bufferizer_put(d->bufferizer,m);
556                ms_mutex_unlock(&d->mutex);
557        }
558}
559
560static int set_rate(MSFilter *f, void *arg){
561        int proposed_rate = *((int*)arg);
562        ms_debug("set_rate %d",proposed_rate);
563        /*if (proposed_rate != PREFERRED_HW_SAMPLE_RATE) {
564                return -1;//only support 1 rate
565        }*/
566        MSSndCard *card=(MSSndCard*)f->data;
567        AUData *d=(AUData*)card->data;
568        d->rate=proposed_rate;
569        return 0;
570}
571
572static int get_rate(MSFilter *f, void *data){
573        MSSndCard *card=(MSSndCard*)f->data;
574        AUData *d=(AUData*)card->data;
575        *(int*)data=d->rate;
576        return 0;
577}
578
579
580static int set_nchannels(MSFilter *f, void *arg){
581        ms_debug("set_nchannels %d", *((int*)arg));
582        MSSndCard *card=(MSSndCard*)f->data;
583        AUData *d=(AUData*)card->data;
584        d->nchannels=*(int*)arg;
585        return 0;
586}
587
588static MSFilterMethod au_methods[]={
589        {       MS_FILTER_SET_SAMPLE_RATE       , set_rate      },
590        {       MS_FILTER_GET_SAMPLE_RATE       , get_rate      },
591        {       MS_FILTER_SET_NCHANNELS         , set_nchannels },
592        {       0                               , NULL          }
593};
594
595MSFilterDesc au_read_desc={
596.id=MS_IOUNIT_READ_ID,
597.name="MSAURead",
598.text=N_("Sound capture filter for MacOS X Audio Unit Service"),
599.category=MS_FILTER_OTHER,
600.ninputs=0,
601.noutputs=1,
602.preprocess=au_read_preprocess,
603.process=au_read_process,
604.postprocess=au_read_postprocess,
605.methods=au_methods
606};
607
608
609MSFilterDesc au_write_desc={
610.id=MS_IOUNIT_WRITE_ID,
611.name="MSAUWrite",
612.text=N_("Sound playback filter for MacOS X Audio Unit Service"),
613.category=MS_FILTER_OTHER,
614.ninputs=1,
615.noutputs=0,
616.preprocess=au_write_preprocess,
617.process=au_write_process,
618.postprocess=au_write_postprocess,
619.methods=au_methods
620};
621
622static MSFilter *ms_au_read_new(MSSndCard *card){
623        ms_debug("ms_au_read_new");
624        MSFilter *f=ms_filter_new_from_desc(&au_read_desc);
625        f->data=card;
626        return f;
627}
628
629
630static MSFilter *ms_au_write_new(MSSndCard *card){
631        ms_debug("ms_au_write_new");
632        MSFilter *f=ms_filter_new_from_desc(&au_write_desc);
633        f->data=card;
634        return f;
635}
636
637MS_FILTER_DESC_EXPORT(au_read_desc)
638MS_FILTER_DESC_EXPORT(au_write_desc)
639
640void ms_au_register_card() {
641        /**
642         * register audio unit plugin should be move to linphone code
643         */
644        ms_snd_card_manager_register_desc(ms_snd_card_manager_get(),&au_card_desc);
645}       
Note: See TracBrowser for help on using the repository browser.