1 /**
2  * coreaudio.cpp
3  * This file is part of the YATE Project http://YATE.null.ro
4  *
5  * CoreAudio sound channel driver for Mac OS X.
6  *
7  * Yet Another Telephony Engine - a fully featured software PBX and IVR
8  * Copyright (C) 2004-2014 Null Team
9  *
10  * This software is distributed under multiple licenses;
11  * see the COPYING file in the main directory for licensing
12  * information for this specific distribution.
13  *
14  * This use of this software may be subject to additional restrictions.
15  * See the LEGAL file in the main directory for details.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20  */
21 
22 
23 #include <yatephone.h>
24 
25 #include <AudioUnit/AudioUnit.h>
26 #include <AudioToolbox/AudioToolbox.h>
27 
28 #define FRAME_SIZE 320
29 #define DEFAULT_SAMPLE_RATE 8000
30 
31 using namespace TelEngine;
32 
33 namespace { //anonymous
34 
35 class CoreAudioSource : public ThreadedSource
36 {
37 public:
38     CoreAudioSource(unsigned int rate = DEFAULT_SAMPLE_RATE);
39     ~CoreAudioSource();
40     // inherited methods
41     bool init();
42     virtual void run();
43     virtual void cleanup();
44     virtual bool control(NamedList& params);
45 
46     // append to the internal buffer data read from input source
47     void sendData(AudioBufferList *buf);
48     // provide data to the AudioConverter taken from the internal buffer
49     DataBlock getData(UInt32 pkts);
50 
51     // helper function for allocating buffers
52     AudioBufferList* allocateAudioBufferList(UInt32 numChannels, UInt32 size);
53     // helper function for freeing buffers
54     void destroyAudioBufferList(AudioBufferList* list);
55     // helper function for obtaining an AudioConverter
56     OSStatus buildConverter(AudioStreamBasicDescription inFormat, AudioConverterRef* ac);
57 
58     // obtain the output format of the AudioUnit
outFormat() const59     inline AudioStreamBasicDescription outFormat() const
60 	{ return m_outDevFormat; }
61     // obtain the output sample rate
rate() const62     inline unsigned int rate() const
63 	{ return m_rate; }
64 
65 private:
66     // callback for obtaining data from input source
67     static OSStatus inputCallback(void* inRefCon, AudioUnitRenderActionFlags* ioActionFlags, const AudioTimeStamp* inTimeStamp,
68 				  UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList* ioData);
69     // default input AudioUnit
70     AudioUnit fAudioUnit;
71     // input buffer
72     AudioBufferList* m_inAudioBuffer;
73     // sample rate converter
74     AudioConverterRef m_audioConvert;
75     // input device id
76     AudioDeviceID fInputDevID;
77     // output format of the AudioUnit
78     AudioStreamBasicDescription	m_outDevFormat;
79     // the desired format for yate, passed to the sample rate converter
80     AudioStreamBasicDescription	m_convertToFormat;
81     // total amount of bytes sent
82     unsigned int m_total;
83     // check if the AudioDevice supports setting the volume
84     bool m_volSettable;
85     // number of channels for the device
86     unsigned int m_channels;
87     // internal buffer
88     DataBlock m_data;
89     // output sample rate
90     unsigned int m_rate;
91 };
92 
93 class CoreAudioConsumer : public DataConsumer, public Mutex
94 {
95 public:
96     CoreAudioConsumer(unsigned int rate = DEFAULT_SAMPLE_RATE);
97     ~CoreAudioConsumer();
98     bool init();
99     // inherited methods
100     virtual unsigned long Consume(const DataBlock &data, unsigned long tStamp, unsigned long flags);
101     virtual bool control(NamedList& params);
102     virtual void getData(AudioBufferList* buf);
103     // obtain the input sample rate
rate() const104     inline unsigned int rate() const
105 	{ return m_rate; }
106 
107 private:
108     // callback through which the AudioUnit requires data to play
109     static OSStatus outputCallback(void* inRefCon, AudioUnitRenderActionFlags* ioActionFlags, const AudioTimeStamp* inTimeStamp,
110 				  UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList* ioData);
111     // the AudioUnit
112     AudioUnit fAudioUnit;
113     // total amount of data written to the output
114     unsigned int m_total;
115     // check if the AudioDevice supports setting the volume
116     bool m_volSettable;
117     // number of channels for the device
118     unsigned int m_channels;
119     // AudioDevice ID
120     AudioDeviceID fOutputDevID;
121     // internal buffer
122     DataBlock m_data;
123     // input sample rate
124     unsigned int m_rate;
125 };
126 
127 class CoreAudioChan : public CallEndpoint
128 {
129 public:
130     CoreAudioChan(const String& dev, unsigned int rate = DEFAULT_SAMPLE_RATE);
131     ~CoreAudioChan();
132     bool init();
133     virtual void disconnected(bool final, const char *reason);
134     void answer();
setTarget(const char * target=0)135     inline void setTarget(const char* target = 0)
136 	{ m_target = target; }
getTarget() const137     inline const String& getTarget() const
138 	{ return m_target; }
rate() const139     inline unsigned int rate() const
140 	{ return m_rate; }
141 private:
142     String m_dev;
143     String m_target;
144     unsigned int m_rate;
145 };
146 
147 class CoreAudioHandler;
148 
149 class CoreAudioPlugin : public Plugin
150 {
151 public:
152     CoreAudioPlugin();
153     virtual void initialize();
154     virtual bool isBusy() const;
155 private:
156     CoreAudioHandler* m_handler;
157 };
158 
159 static CoreAudioChan* s_audioChan = 0;
160 
161 INIT_PLUGIN(CoreAudioPlugin);
162 
163 class CoreAudioHandler : public MessageHandler
164 {
165 public:
CoreAudioHandler(const char * name)166     CoreAudioHandler(const char *name)
167 	: MessageHandler(name,100,__plugin.name())
168 	{ }
169     virtual bool received(Message &msg);
170 };
171 
172 class StatusHandler : public MessageHandler
173 {
174 public:
StatusHandler()175     StatusHandler()
176 	: MessageHandler("engine.status",100,__plugin.name())
177 	{ }
178     virtual bool received(Message &msg);
179 };
180 
181 class DropHandler : public MessageHandler
182 {
183 public:
DropHandler()184     DropHandler()
185 	: MessageHandler("call.drop",100,__plugin.name())
186 	{ }
187     virtual bool received(Message &msg);
188 };
189 
190 class MasqHandler : public MessageHandler
191 {
192 public:
MasqHandler(int prio)193     MasqHandler(int prio)
194 	: MessageHandler("chan.masquerade",prio,__plugin.name())
195 	{ }
196     virtual bool received(Message &msg);
197 };
198 
199 class AttachHandler : public MessageHandler
200 {
201 public:
AttachHandler()202     AttachHandler()
203 	: MessageHandler("chan.attach",100,__plugin.name())
204 	{ }
205     virtual bool received(Message &msg);
206 };
207 
208 // test if a device permits setting the volume
checkVolumeSettable(AudioDeviceID devId,UInt32 inChannel,Boolean isInput)209 static bool checkVolumeSettable(AudioDeviceID devId, UInt32 inChannel,Boolean isInput)
210 {
211     Boolean isWritable = false;
212 
213     AudioObjectPropertyScope volumeScope = isInput ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput;
214     AudioObjectPropertyAddress volumeAddress = {kAudioDevicePropertyVolumeScalar,volumeScope,inChannel};
215 
216     Boolean hasProperty = AudioObjectHasProperty(devId,&volumeAddress);
217     if (!hasProperty) {
218         DDebug(DebugAll, "CoreAudio - %s AudioUnit does not have 'kAudioDevicePropertyVolumeScalar' property on channel %u",
219                (isInput ? "Input" : "Output"),(unsigned int)inChannel);
220         return false;
221     }
222 
223     OSStatus err = AudioObjectIsPropertySettable(devId,&volumeAddress,&isWritable);
224     if (err != noErr) {
225 	DDebug(DebugAll, "CoreAudio - %s AudioUnit Failed to get if volume property is settable on channel=%u, err=%4.4s, %ld",(isInput ? "Input" : "Output"),
226                (unsigned int)inChannel,(char*)&err,(long int)err);
227 	return false;
228     }
229     return isWritable;
230 }
231 
232 // callback for the sample rate converter
convertCallback(AudioConverterRef inAudioConverter,UInt32 * ioNumberDataPackets,AudioBufferList * ioData,AudioStreamPacketDescription ** outDataPacketDescription,void * inUserData)233 OSStatus convertCallback(AudioConverterRef inAudioConverter, UInt32* ioNumberDataPackets, AudioBufferList* ioData,
234 			 AudioStreamPacketDescription**	outDataPacketDescription, void* inUserData)
235 {
236     CoreAudioSource* src = static_cast<CoreAudioSource*> (inUserData);
237     if (!src)
238 	return 1;
239     // try to get data with the required length
240     DataBlock data = src->getData(*ioNumberDataPackets);
241     if (data.length() > 0)
242 	XDebug(DebugInfo,"CoreAudio::convertCallBack() packetsReq=%d pktsAvailable=%d", (int)*ioNumberDataPackets,data.length()/2);
243 
244     // signal that we have no data to convert and return
245     if (data.length() == 0) {
246 	*ioNumberDataPackets = 0;
247 	return 1;
248     }
249     // determine how much we can read into the converter's input buffer
250     UInt32 maxPackets = data.length() / src->outFormat().mBytesPerFrame;
251     if (*ioNumberDataPackets > maxPackets)
252 	*ioNumberDataPackets = maxPackets;
253     else
254 	maxPackets = *ioNumberDataPackets;
255 
256     // fill the converters input buffer
257     ioData->mBuffers[0].mData = data.data();
258     ioData->mBuffers[0].mDataByteSize = maxPackets * src->outFormat().mBytesPerFrame;
259     ioData->mBuffers[0].mNumberChannels = 1;
260     data.cut(-(maxPackets * src->outFormat().mBytesPerFrame));
261     return noErr;
262 }
263 
CoreAudioSource(unsigned int rate)264 CoreAudioSource::CoreAudioSource(unsigned int rate)
265     : m_inAudioBuffer(0), m_audioConvert(NULL), fInputDevID(0),
266       m_total(0), m_volSettable(false), m_channels(0), m_rate(rate)
267 {
268     Debug(DebugAll,"CoreAudioSource::CoreAudioSource() [%p]",this);
269     if (m_rate != DEFAULT_SAMPLE_RATE)
270 	m_format << "/" << m_rate;
271 }
272 
~CoreAudioSource()273 CoreAudioSource::~CoreAudioSource()
274 {
275     Debug(DebugAll,"CoreAudioSource::~CoreAudioSource() [%p] total=%u",this,m_total);
276     OSStatus err = AudioOutputUnitStop(fAudioUnit);
277     if(err != noErr)
278 	Debug(DebugInfo,"CoreAudioSource::~CoreAudioSource() [%p] - Failed to stop AU",this);
279     err = AudioUnitUninitialize(fAudioUnit);
280     if(err != noErr)
281 	Debug(DebugInfo,"CoreAudioSource::~CoreAudioSource() [%p] - Failed to uninitialize AU",this);
282     destroyAudioBufferList(m_inAudioBuffer);
283 }
284 
init()285 bool CoreAudioSource::init()
286 {
287     OSStatus err = noErr;
288     UInt32  param;
289 
290     // open the AudioOutputUnit, provide description
291 #ifdef MAC_OS_X_VERSION_10_6
292     AudioComponent component;
293     AudioComponentDescription description;
294 #else
295     Component component;
296     ComponentDescription description;
297 #endif
298 
299     description.componentType = kAudioUnitType_Output;
300     description.componentSubType = kAudioUnitSubType_HALOutput;
301     description.componentManufacturer = kAudioUnitManufacturer_Apple;
302     description.componentFlags = 0;
303     description.componentFlagsMask = 0;
304 
305 #ifdef MAC_OS_X_VERSION_10_6
306     if((component = AudioComponentFindNext(NULL,&description)))
307 	err = AudioComponentInstanceNew(component,&fAudioUnit);
308 #else
309     if((component = FindNextComponent(NULL,&description)))
310 	err = OpenAComponent(component,&fAudioUnit);
311 #endif
312 
313     if(err != noErr) {
314         fAudioUnit = NULL;
315         Debug(DebugInfo,"CoreAudioSource::init() [%p] - failed to open component error==%4.4s, %ld",this,(char*)&err,(long int)err);
316         return false;
317     }
318 
319     // configure AudioOutputUnit for input, enable input on the AUHAL
320     param = 1;
321     err = AudioUnitSetProperty(fAudioUnit,kAudioOutputUnitProperty_EnableIO,kAudioUnitScope_Input,1,&param,sizeof(UInt32));
322     if (err == noErr) {
323 	// disable output on the AUHAL
324 	param = 0;
325 	err = AudioUnitSetProperty(fAudioUnit,kAudioOutputUnitProperty_EnableIO,kAudioUnitScope_Output,0,&param,sizeof(UInt32));
326     }
327     else {
328 	Debug(DebugInfo,"CoreAudioSource::init() [%p] - failed to configure AudioUnit for input error==%4.4s, %ld",this,(char*)&err,(long int)err);
329 	return false;
330     }
331 
332     // select the default input device
333     param = sizeof(AudioDeviceID);
334 
335     AudioObjectPropertyAddress devAddress = {kAudioHardwarePropertyDefaultInputDevice,kAudioObjectPropertyScopeGlobal,kAudioObjectPropertyElementMaster};
336     err = AudioObjectGetPropertyData(kAudioObjectSystemObject,&devAddress,0,NULL,&param,&fInputDevID);
337     if(err != noErr) {
338 	Debug(DebugInfo,"CoreAudioSource::init() [%p] - failed to get input device error==%4.4s, %ld",this,(char*)&err,(long int)err);
339 	return false;
340     }
341 
342     // set the current device to the AudioUnit
343     err = AudioUnitSetProperty(fAudioUnit,kAudioOutputUnitProperty_CurrentDevice,kAudioUnitScope_Global,0,&fInputDevID,sizeof(AudioDeviceID));
344     if (err != noErr) {
345 	Debug(DebugInfo,"CoreAudioSource::init() [%p] - failed to set AU input device=%4.4s, %ld",this,(char*)&err,(long int)err);
346 	return false;
347     }
348 
349     // setup render callback
350     AURenderCallbackStruct callback;
351     callback.inputProc = CoreAudioSource::inputCallback;
352     callback.inputProcRefCon = this;
353     err = AudioUnitSetProperty(fAudioUnit,kAudioOutputUnitProperty_SetInputCallback,kAudioUnitScope_Global,0,&callback,sizeof(AURenderCallbackStruct));
354     if (err != noErr) {
355 	Debug(DebugInfo,"CoreAudioSource::init() [%p] - could not set callback error==%4.4s, %ld",this,(char*)&err,(long int)err);
356 	return false;
357     }
358 
359     // get hardware device format
360     param = sizeof(AudioStreamBasicDescription);
361     AudioStreamBasicDescription devFormat;
362     err = AudioUnitGetProperty(fAudioUnit,kAudioUnitProperty_StreamFormat,kAudioUnitScope_Input,1,&devFormat,&param);
363     if(err != noErr) {
364 	Debug(DebugInfo,"CoreAudioSource::init() [%p] - failed to get input device AudioStreamBasicDescription error==%4.4s, %ld",this,(char*)&err,(long int)err);
365 	return false;
366     }
367 
368     DDebug(DebugInfo,"CoreAudioSource::init() [%p] - hardware device input format is : channels/frame=%u, sampleRate=%f, bits/channel=%u, "
369 	   "bytes/frame=%u, frames/packet=%u, bytes/packet=%u, formatFlags=0x%x",
370 	   this,(unsigned int)devFormat.mChannelsPerFrame,devFormat.mSampleRate,(unsigned int)devFormat.mBitsPerChannel,
371 	   (unsigned int)devFormat.mBytesPerFrame,(unsigned int)devFormat.mFramesPerPacket,(unsigned int)devFormat.mBytesPerPacket,
372 	   (unsigned int)devFormat.mFormatFlags);
373 
374     m_outDevFormat.mChannelsPerFrame = 1;
375     m_outDevFormat.mSampleRate = devFormat.mSampleRate;
376     m_outDevFormat.mFormatID = kAudioFormatLinearPCM;
377     m_outDevFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
378     m_outDevFormat.mFormatFlags &= ~kAudioFormatFlagIsBigEndian;
379 #if __BIG_ENDIAN__
380     m_outDevFormat.mFormatFlags |= kAudioFormatFlagIsBigEndian;
381 #endif
382     m_outDevFormat.mBytesPerFrame = sizeof(int16_t) * devFormat.mChannelsPerFrame;
383     m_outDevFormat.mBitsPerChannel = m_outDevFormat.mBytesPerFrame * 8;
384     m_outDevFormat.mFramesPerPacket = 1;
385     m_outDevFormat.mBytesPerPacket = m_outDevFormat.mBytesPerFrame;
386 
387     // remembering the number of channels for the device
388     m_channels = devFormat.mChannelsPerFrame;
389 
390     // set the AudioUnit output data format
391     err = AudioUnitSetProperty(fAudioUnit,kAudioUnitProperty_StreamFormat,kAudioUnitScope_Output,1,&m_outDevFormat,sizeof(AudioStreamBasicDescription));
392     if(err != noErr) {
393 	Debug(DebugInfo, "CoreAudioSource::init() [%p] - failed to set output data format error==%4.4s, %ld",this,(char*)&err,(long int)err);
394 	return false;
395     }
396 
397     DDebug(DebugInfo,"CoreAudioSource::init() [%p] - AudioUnit output format is : channels/frame=%u, sampleRate=%f, bits/channel=%u, "
398 	   "bytes/frame=%u, frames/packet=%u, bytes/packet=%u, formatFlags=0x%x",
399 	   this,(unsigned int)m_outDevFormat.mChannelsPerFrame,m_outDevFormat.mSampleRate,(unsigned int)m_outDevFormat.mBitsPerChannel,
400 	   (unsigned int)m_outDevFormat.mBytesPerFrame,(unsigned int)m_outDevFormat.mFramesPerPacket,(unsigned int)m_outDevFormat.mBytesPerPacket,
401 	   (unsigned int)m_outDevFormat.mFormatFlags);
402 
403     // obtain a sample rate converter
404     err = buildConverter(m_outDevFormat,&m_audioConvert);
405     if (err != noErr) {
406 	Debug(DebugInfo,"CoreAudioSource::init() [%p] - failed to get sample rate converter error==%4.4s, %ld",this,(char*)&err,(long int)err);
407 	return false;
408     }
409 
410     // get the number of frames in the IO buffer
411     UInt32 audioSamples;
412     param = sizeof(UInt32);
413     err = AudioUnitGetProperty(fAudioUnit,kAudioDevicePropertyBufferFrameSize,kAudioUnitScope_Global,0,&audioSamples,&param);
414     if(err != noErr) {
415 	Debug(DebugInfo,"CoreAudioSource::init() [%p] - failed to get audio sample size error==%4.4s, %ld",this,(char*)&err,(long int)err);
416 	return false;
417     }
418 
419     // Initialize the AU
420     err = AudioUnitInitialize(fAudioUnit);
421     if(err != noErr) {
422 	Debug(DebugInfo,"CoreAudioSource::init() [%p] - Failed to initialize AU error==%4.4s, %ld",this,(char*)&err,(long int)err);
423 	return false;
424     }
425 
426     // allocate AudioBufferList
427     m_inAudioBuffer = allocateAudioBufferList(m_outDevFormat.mChannelsPerFrame,audioSamples *  m_outDevFormat.mBytesPerFrame);
428     if(m_inAudioBuffer == NULL) {
429 	Debug(DebugInfo,"CoreAudioSource::init() [%p] - Failed to allocate audio buffers",this);
430 	return false;
431     }
432 
433     // Start pulling for audio data
434     err = AudioOutputUnitStart(fAudioUnit);
435     if(err != noErr) {
436 	Debug(DebugInfo,"CoreAudioSource::init() [%p] - Failed to start the AudioUnit error==%4.4s, %ld",this,(char*)&err,(long int)err);
437 	return false;
438     }
439     else
440 	Debug(DebugInfo,"CoreAudioSource::init() [%p] - AudioUnit started",this);
441 
442     // check if the device lets us set the volume
443     m_volSettable = false;
444     for (unsigned int i = 0; i <= m_channels; i++)
445         m_volSettable = checkVolumeSettable(fInputDevID,i,true) || m_volSettable;
446     Debug(DebugAll,"CoreAudioSource::init() [%p] - volume %s settable",this,(m_volSettable ? "is" : "isn't"));
447 
448     return start("CoreAudioSource");
449 }
450 
buildConverter(AudioStreamBasicDescription inputFormat,AudioConverterRef * ac)451 OSStatus CoreAudioSource::buildConverter(AudioStreamBasicDescription inputFormat, AudioConverterRef* ac)
452 {
453     m_convertToFormat.mChannelsPerFrame = 1;
454     m_convertToFormat.mSampleRate = rate();
455     m_convertToFormat.mFormatID = kAudioFormatLinearPCM;
456     m_convertToFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
457     m_convertToFormat.mFormatFlags &= ~kAudioFormatFlagIsBigEndian;
458 #if __BIG_ENDIAN__
459     m_convertToFormat.mFormatFlags |= kAudioFormatFlagIsBigEndian;
460 #endif
461     m_convertToFormat.mBitsPerChannel = sizeof(int16_t) * 8;
462     m_convertToFormat.mBytesPerFrame = m_convertToFormat.mBitsPerChannel / 8;
463     m_convertToFormat.mFramesPerPacket = 1;
464     m_convertToFormat.mBytesPerPacket = m_convertToFormat.mBytesPerFrame;
465 
466     DDebug(DebugInfo,"CoreAudioSource::buildConverter() [%p] - AudioConverter output format is : channels/frame=%u, sampleRate=%f, bits/channel=%u, "
467 	   "bytes/frame=%u, frames/packet=%u, bytes/packet=%u, formatFlags=0x%x",
468            this,(unsigned int)m_convertToFormat.mChannelsPerFrame,m_convertToFormat.mSampleRate,(unsigned int)m_convertToFormat.mBitsPerChannel,
469 	   (unsigned int)m_convertToFormat.mBytesPerFrame,(unsigned int)m_convertToFormat.mFramesPerPacket,(unsigned int)m_convertToFormat.mBytesPerPacket,
470 	   (unsigned int)m_convertToFormat.mFormatFlags);
471 
472     OSStatus err = noErr;
473     err = AudioConverterNew(&inputFormat,&m_convertToFormat,ac);
474     if (err != noErr) {
475 	Debug(DebugInfo,"CoreAudioSource::buildConverter() [%p] failed to get converter error==%4.4s, %ld",this,(char*)&err,(long int)err);
476 	return err;
477     }
478 
479     // set channel map
480     SInt32 channelMap[] = { 0 };
481     err = AudioConverterSetProperty(*ac, kAudioConverterChannelMap, sizeof(SInt32), channelMap);
482     // set converter complexity
483     UInt32 size = sizeof(kAudioConverterSampleRateConverterComplexity_Mastering);
484     UInt32 prop = kAudioConverterSampleRateConverterComplexity_Mastering;
485     err = AudioConverterSetProperty(*ac,kAudioConverterSampleRateConverterComplexity,size,&prop);
486     if (err != noErr)
487 	Debug(DebugInfo,"CoreAudioSource::buildConverter() [%p] failed to set converter complexity error==%4.4s, %ld",this,(char*)&err,(long int)err);
488     return noErr;
489 }
490 
allocateAudioBufferList(UInt32 numChannels,UInt32 size)491 AudioBufferList* CoreAudioSource::allocateAudioBufferList(UInt32 numChannels, UInt32 size)
492 {
493     AudioBufferList* list;
494     DDebug(DebugAll,"CoreAudioSource::allocateAudioBufferList(channels= %d,size=%d) [%p]",(int)numChannels,(int)size,this);
495     list = (AudioBufferList*)calloc(1, sizeof(AudioBufferList) + numChannels * sizeof(AudioBuffer));
496     if(list == NULL)
497 	return NULL;
498 
499     list->mNumberBuffers = numChannels;
500     for(UInt32 i = 0; i < numChannels; ++i) {
501 	list->mBuffers[i].mNumberChannels = 1;
502 	list->mBuffers[i].mDataByteSize = size;
503 	list->mBuffers[i].mData = malloc(size);
504 	if(list->mBuffers[i].mData == NULL) {
505 	    destroyAudioBufferList(list);
506 	    return NULL;
507 	}
508     }
509     return list;
510 }
511 
destroyAudioBufferList(AudioBufferList * list)512 void CoreAudioSource::destroyAudioBufferList(AudioBufferList* list)
513 {
514     DDebug(DebugAll,"CoreAudioSource::destroyAudioBufferList(list=%p) [%p]",list,this);
515     if(list) {
516 	for(UInt32 i = 0; i < list->mNumberBuffers; i++) {
517 	    if(list->mBuffers[i].mData)
518 		free(list->mBuffers[i].mData);
519 	}
520 	free(list);
521     }
522 }
523 
sendData(AudioBufferList * buf)524 void CoreAudioSource::sendData(AudioBufferList* buf)
525 {
526     // append to internal buffer data we receive from input
527     if (!buf)
528 	return;
529     lock();
530     for (unsigned int i = 0; i < m_outDevFormat.mChannelsPerFrame; i++)
531 	m_data.append(buf->mBuffers[i].mData,buf->mBuffers[i].mDataByteSize);
532     XDebug(DebugAll,"CoreAudioSource::sendData(buffer=%p,buffer_length=%d), internal buffer length=%d [%p]",buf,(int)buf->mBuffers[0].mDataByteSize,m_data.length(),this);
533     unlock();
534 }
535 
getData(UInt32 pkts)536 DataBlock CoreAudioSource::getData(UInt32 pkts)
537 {
538     // return to the converter a data block with the required size or the maximum available
539     DataBlock data;
540     lock();
541     if (pkts * m_outDevFormat.mBytesPerFrame > m_data.length())
542 	pkts = m_data.length() / m_outDevFormat.mBytesPerFrame;
543     data.assign(m_data.data(),pkts * m_outDevFormat.mBytesPerFrame);
544     m_data.cut(-pkts * m_outDevFormat.mBytesPerFrame );
545     unlock();
546     return data;
547 }
548 
inputCallback(void * inRefCon,AudioUnitRenderActionFlags * ioActionFlags,const AudioTimeStamp * inTimeStamp,UInt32 inBusNumber,UInt32 inNumberFrames,AudioBufferList * ioData)549 OSStatus CoreAudioSource::inputCallback(void* inRefCon, AudioUnitRenderActionFlags* ioActionFlags, const AudioTimeStamp* inTimeStamp,
550 							UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList* ioData)
551 {
552     CoreAudioSource* source = (CoreAudioSource*) inRefCon;
553     OSStatus err = noErr;
554     // Render into audio buffer
555     err = AudioUnitRender(source->fAudioUnit,ioActionFlags,inTimeStamp,inBusNumber,inNumberFrames,source->m_inAudioBuffer);
556     if(err)
557 	Debug(DebugInfo,"CoreAudioSource::inputCallback() [%p] AudioUnitRender() failed with error=%4.4s, %ld",source,(char*)&err,(long int)err);
558 
559     source->sendData(source->m_inAudioBuffer);
560     return err;
561 }
562 
run()563 void CoreAudioSource::run()
564 {
565     DataBlock frame;
566     AudioBufferList fillBufList;
567     fillBufList.mNumberBuffers = 1;
568     fillBufList.mBuffers[0].mNumberChannels = 1;
569     fillBufList.mBuffers[0].mData = new char[FRAME_SIZE];
570 
571     do {
572 	if (!looping())
573 	    break;
574 	if (frame.length() < FRAME_SIZE) {
575 	    // try to get more data from input and convert it to the desired sample rate
576 	    UInt32 outBuffSize = FRAME_SIZE / m_convertToFormat.mBytesPerPacket;
577 	    //AudioStreamPacketDescription* pktDesc = NULL;
578 	    fillBufList.mBuffers[0].mDataByteSize = FRAME_SIZE;
579 	    OSStatus err = AudioConverterFillComplexBuffer(m_audioConvert,convertCallback,this,&outBuffSize,&fillBufList,NULL/*pktDesc*/);
580 	    if (err != noErr && err != 1)
581 		Debug(DebugInfo,"CoreAudioSource::run() - AudioConvertFillComplexBuffer() failed with error=%4.4s, %ld", (char*)&err, (long int)err);
582 	    if (outBuffSize == 0) {
583 		Thread::idle();
584 		continue;
585 	    }
586 	    frame.append(fillBufList.mBuffers[0].mData,outBuffSize * m_convertToFormat.mBytesPerPacket);
587 	}
588 
589 	if (frame.length() >= FRAME_SIZE) {
590 	    // we have enough data to send forward
591 	    DataBlock data(frame.data(),FRAME_SIZE,false);
592 	    Forward(data);
593 	    data.clear(false);
594 	    frame.cut(-FRAME_SIZE);
595 	    m_total += FRAME_SIZE;
596 	}
597     }
598     while (true);
599     delete [] (char*)fillBufList.mBuffers[0].mData;
600     Debug(DebugAll,"CoreAudioSource [%p] end of data",this);
601 }
602 
cleanup()603 void CoreAudioSource::cleanup()
604 {
605     Debug(DebugAll,"CoreAudioSource [%p] cleanup, total=%u",this,m_total);
606     AudioConverterDispose(m_audioConvert);
607     ThreadedSource::cleanup();
608 }
609 
control(NamedList & params)610 bool CoreAudioSource::control(NamedList& params)
611 {
612     DDebug(DebugAll,"CoreAudioSource::control() [%p]",this);
613     if (!m_volSettable)
614 	return TelEngine::controlReturn(&params,false);
615     int vol = params.getIntValue("in_volume",-1);
616     if (vol == -1) {
617 	Debug(DebugAll,"CoreAudioSource::control() [%p] - invalid value to set for volume",this);
618 	return TelEngine::controlReturn(&params,false);
619     }
620     Float32 volValue = vol / 100.0;
621 
622     bool setVolStatus = false;
623     bool getVolStatus = false;
624     int setVolValue = 0;
625     for (unsigned int i = 0; i <= m_channels; i++) {
626         AudioObjectPropertyAddress volumeAddress = {kAudioDevicePropertyVolumeScalar,kAudioDevicePropertyScopeInput,i};
627         OSStatus err = AudioObjectSetPropertyData(fInputDevID,&volumeAddress,0,NULL,sizeof(Float32),&volValue);
628         if (err != noErr)
629             DDebug(DebugAll,"CoreAudioSource::control() [%p] - set volume failed with error=%4.4s, %ld on channel %u",this,(char*)&err,(long int)err,i);
630         setVolStatus = (err == noErr) || setVolStatus;
631 
632         // get the actual set volume value
633         Float32 setVolumePerChannel = 0;
634         UInt32 size = sizeof(setVolumePerChannel);
635         err = AudioObjectGetPropertyData(fInputDevID,&volumeAddress,0,NULL,&size,&setVolumePerChannel);
636         if (err != noErr)
637             DDebug(DebugAll,"CoreAudioSource::control() [%p] - get volume failed with error=%4.4s, %ld on channel %u",this,(char*)&err,(long int)err,i);
638         else {
639             if (setVolValue / 100.0 < setVolumePerChannel)
640                 setVolValue = setVolumePerChannel * 100;
641         }
642         getVolStatus = (err == noErr) || getVolStatus;
643     }
644     if (getVolStatus)
645         params.setParam("in_volume",String(setVolValue));
646     if (!setVolStatus)
647         Debug(DebugAll,"CoreAudioSource::control() [%p] - set volume failed on all channels",this);
648 
649     if(params.getParam("out_volume"))
650 	return TelEngine::controlReturn(&params,false);
651     return TelEngine::controlReturn(&params,setVolStatus);
652 }
653 
654 
CoreAudioConsumer(unsigned int rate)655 CoreAudioConsumer::CoreAudioConsumer(unsigned int rate)
656     : Mutex(false,"CoreAudioConsumer"),
657       m_total(0), m_volSettable(false), m_channels(0), fOutputDevID(0), m_rate(rate)
658 {
659     Debug(DebugAll,"CoreAudioConsumer::CoreAudioConsumer() [%p]",this);
660     if (m_rate != DEFAULT_SAMPLE_RATE)
661 	m_format << "/" << m_rate;
662 }
663 
~CoreAudioConsumer()664 CoreAudioConsumer::~CoreAudioConsumer()
665 {
666     Debug(DebugAll,"CoreAudioConsumer::~CoreAudioConsumer() [%p] total=%u",this,m_total);
667     OSStatus err = AudioOutputUnitStop(fAudioUnit);
668     if(err != noErr)
669 	Debug(DebugInfo,"CoreAudioConsumer::~CoreAudioConsumer() [%p] - Failed to stop output AudioUnit error=%4.4s, %ld",this,(char*)&err,(long int)err);
670     err = AudioUnitUninitialize(fAudioUnit);
671     if(err != noErr)
672     	Debug(DebugInfo,"CoreAudioConsumer::~CoreAudioConsumer() [%p] - Failed to uninitialize the AudioUnit error=%4.4s, %ld",this,(char*)&err,(long int)err);
673 }
674 
init()675 bool CoreAudioConsumer::init()
676 {
677     OSStatus err = noErr;
678 
679     // open the AudioOutputUnit, provide description
680 #ifdef MAC_OS_X_VERSION_10_6
681     AudioComponent component;
682     AudioComponentDescription description;
683 #else
684     Component component;
685     ComponentDescription description;
686 #endif
687 
688     description.componentType = kAudioUnitType_Output;
689     description.componentSubType = kAudioUnitSubType_DefaultOutput;
690     description.componentManufacturer = kAudioUnitManufacturer_Apple;
691     description.componentFlags = 0;
692     description.componentFlagsMask = 0;
693 
694 #ifdef MAC_OS_X_VERSION_10_6
695     if((component = AudioComponentFindNext(NULL,&description)))
696 	err = AudioComponentInstanceNew(component,&fAudioUnit);
697 #else
698     if((component = FindNextComponent(NULL,&description)))
699 	err = OpenAComponent(component,&fAudioUnit);
700 #endif
701 
702     if(err != noErr) {
703         Debug(DebugInfo,"CoreAudioConsumer::init() [%p] - failed to open component error==%4.4s, %ld",this,(char*)&err,(long int)err);
704         fAudioUnit = NULL;
705         return false;
706     }
707 
708     // set up the callback to generate output to the output unit
709     AURenderCallbackStruct callback;
710     callback.inputProc = CoreAudioConsumer::outputCallback;
711     callback.inputProcRefCon = this;
712     err = AudioUnitSetProperty (fAudioUnit,kAudioUnitProperty_SetRenderCallback,kAudioUnitScope_Input,0,&callback,sizeof(callback));
713     if (err != noErr)
714 	Debug(DebugInfo,"CoreAudioConsumer::init() [%p]- callback could not be set error=%4.4s, %ld",this,(char*)&err,(long int)err);
715 
716     // provide the input format of the date we're supplying
717     AudioStreamBasicDescription inputFormat;
718     inputFormat.mSampleRate = rate();
719     inputFormat.mFormatID = kAudioFormatLinearPCM;
720     inputFormat.mBitsPerChannel = sizeof(int16_t) * 8; //  = 16
721     inputFormat.mBytesPerFrame = inputFormat.mBitsPerChannel / 8;
722     inputFormat.mFramesPerPacket = 1;
723     inputFormat.mBytesPerPacket = inputFormat.mBytesPerFrame;
724     inputFormat.mChannelsPerFrame = 1;
725     inputFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
726     inputFormat.mFormatFlags &= ~kLinearPCMFormatFlagIsNonInterleaved;
727 
728     err = AudioUnitSetProperty(fAudioUnit,kAudioUnitProperty_StreamFormat,kAudioUnitScope_Input,0,&inputFormat,sizeof(AudioStreamBasicDescription));
729     if (err != noErr) {
730 	Debug(DebugInfo,"CoreAudioConsumer::init() [%p] - set input format failed error==%4.4s, %ld",this,(char*)&err,(long int)err);
731 	return false;
732     }
733     DDebug(DebugInfo,"CoreAudioConsumer::init() [%p] - intput format is : channels/frame=%u, sampleRate=%f, bits/channel=%u, "
734 	   "bytes/frame=%u, frames/packet=%u, bytes/packet=%u, formatFlags=0x%x",
735 	   this,(unsigned int)inputFormat.mChannelsPerFrame,inputFormat.mSampleRate,(unsigned int)inputFormat.mBitsPerChannel,
736 	   (unsigned int)inputFormat.mBytesPerFrame,(unsigned int)inputFormat.mFramesPerPacket,(unsigned int)inputFormat.mBytesPerPacket,
737 	   (unsigned int)inputFormat.mFormatFlags);
738 
739     // initialize the AudioUnit
740     err = AudioUnitInitialize(fAudioUnit);
741     if (err != noErr) {
742 	Debug(DebugInfo,"CoreAudioConsumer::init() [%p] - AudioUnitInitialize failed error=%4.4s, %ld",this,(char*)&err,(long int)err);
743 	return false;
744     }
745 
746     // start the AudioUnit
747     err = AudioOutputUnitStart(fAudioUnit);
748     if (err != noErr) {
749 	Debug(DebugInfo,"CoreAudioConsumer::init() [%p] - AudioUnitStart failed error=%4.4s, %ld",this,(char*)&err,(long int)err);
750 	return false;
751     }
752 
753     // get the id of the default output device
754     UInt32 param = sizeof(AudioDeviceID);
755     param = sizeof(AudioDeviceID);
756     AudioObjectPropertyAddress devAddress = {kAudioHardwarePropertyDefaultOutputDevice,kAudioObjectPropertyScopeGlobal,kAudioObjectPropertyElementMaster};
757     err = AudioObjectGetPropertyData(kAudioObjectSystemObject,&devAddress,0,NULL,&param,&fOutputDevID);
758     if(err != noErr)
759 	Debug(DebugMild,"CoreAudioConsumer::init() [%p] - Failed to get the device id of the output device error==%4.4s, %ld",this,(char*)&err,(long int)err);
760 
761     // get hardware device format
762     param = sizeof(AudioStreamBasicDescription);
763     AudioStreamBasicDescription devFormat;
764     err = AudioUnitGetProperty(fAudioUnit,kAudioUnitProperty_StreamFormat,kAudioUnitScope_Output,0,&devFormat,&param);
765     if(err != noErr) {
766 	Debug(DebugInfo,"CoreAudioConsumer::init() [%p] - failed to get input device AudioStreamBasicDescription error==%4.4s, %ld",this,(char*)&err,(long int)err);
767 	// we didn't get the hardware format, but it's a safe bet that we have at least 1 channel
768         m_channels = 1;
769     }
770     else {
771         m_channels = devFormat.mChannelsPerFrame;
772 
773         DDebug(DebugInfo,"CoreAudioConsumer::init() [%p] - hardware device input format is : channels/frame=%u, sampleRate=%f, bits/channel=%u, "
774                "bytes/frame=%u, frames/packet=%u, bytes/packet=%u, formatFlags=0x%x",
775                this,(unsigned int)devFormat.mChannelsPerFrame,devFormat.mSampleRate,(unsigned int)devFormat.mBitsPerChannel,
776                (unsigned int)devFormat.mBytesPerFrame,(unsigned int)devFormat.mFramesPerPacket,(unsigned int)devFormat.mBytesPerPacket,
777                (unsigned int)devFormat.mFormatFlags);
778     }
779 
780     m_volSettable = false;
781     for (unsigned int i = 0; i <= m_channels; i++)
782         m_volSettable = checkVolumeSettable(fOutputDevID,i,false) || m_volSettable;
783     Debug(DebugAll,"CoreAudioConsumer::init() - volume %s settable",(m_volSettable ? "is" : "isn't"));
784     return true;
785 }
786 
getData(AudioBufferList * buf)787 void CoreAudioConsumer::getData(AudioBufferList* buf)
788 {
789     if (!buf)
790         return;
791     // put the data into the output buffer
792     UInt32 len = buf->mBuffers[0].mDataByteSize; // there should be only one buffer;
793     lock();
794     if (m_data.length() == 0) {
795         ::memset(buf->mBuffers[0].mData,0,len);
796         unlock();
797         return;
798     }
799     if (len > m_data.length())
800 	len = m_data.length();
801     if (len > 0) {
802 	::memcpy(buf->mBuffers[0].mData,m_data.data(),len);
803 	m_data.cut(-len);
804     }
805     unlock();
806 }
807 
outputCallback(void * inRefCon,AudioUnitRenderActionFlags * ioActionFlags,const AudioTimeStamp * inTimeStamp,UInt32 inBusNumber,UInt32 inNumberFrames,AudioBufferList * ioData)808 OSStatus CoreAudioConsumer::outputCallback(void* inRefCon, AudioUnitRenderActionFlags* ioActionFlags, const AudioTimeStamp* inTimeStamp,
809 							   UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList* ioData)
810 {
811     CoreAudioConsumer* dst = static_cast<CoreAudioConsumer*>(inRefCon);
812     if (!dst)
813 	return 1;
814     XDebug(DebugAll,"CoreAudioConsumer::outputCallback() [%p] inNumberFrames=%d buffersCount=%d buffersize=%d",dst,(unsigned int)inNumberFrames,
815 	   (unsigned int)ioData->mNumberBuffers,(unsigned int)ioData->mBuffers[0].mDataByteSize);
816     dst->getData(ioData);
817     return noErr;
818 }
819 
Consume(const DataBlock & data,unsigned long tStamp,unsigned long flags)820 unsigned long CoreAudioConsumer::Consume(const DataBlock &data, unsigned long tStamp, unsigned long flags)
821 {
822     // append to the internal buffer received data
823     if (data.null())
824 	return 0;
825     lock();
826     m_total += data.length();
827     m_data.append(data);
828     unlock();
829     return invalidStamp();
830 }
831 
control(NamedList & params)832 bool CoreAudioConsumer::control(NamedList& params)
833 {
834     DDebug(DebugAll,"CoreAudioConsumer::control() [%p]",this);
835     if (!m_volSettable)
836 	return TelEngine::controlReturn(&params,false);
837     int vol = params.getIntValue("out_volume",-1);
838     if (vol == -1) {
839 	Debug(DebugAll,"CoreAudioConsumer::control() [%p] invalid value to set for volume",this);
840 	return TelEngine::controlReturn(&params,false);
841     }
842     Float32 volValue = vol / 100.0;
843 
844     bool setVolStatus = false;
845     bool getVolStatus = false;
846     int setVolValue = 0;
847     for (unsigned int i = 0; i <= m_channels; i++) {
848         // set the volume for the output on every channel
849         AudioObjectPropertyAddress volumeAddress = {kAudioDevicePropertyVolumeScalar,kAudioDevicePropertyScopeOutput,i};
850         OSStatus err = AudioObjectSetPropertyData(fOutputDevID,&volumeAddress,0,NULL,sizeof(Float32),&volValue);
851         if (err != noErr)
852             DDebug(DebugAll,"CoreAudioConsumer::control() [%p] - set volume failed with error=%4.4s, %ld on channel %u",this,(char*)&err,(long int)err,i);
853         setVolStatus = (err == noErr) || setVolStatus;
854 
855         // get the actual set volume value
856         Float32 setVolumePerChannel = 0;
857         UInt32 size = sizeof(setVolumePerChannel);
858         err = AudioObjectGetPropertyData(fOutputDevID,&volumeAddress,0,NULL,&size,&setVolumePerChannel);
859         if (err != noErr)
860             DDebug(DebugAll,"CoreAudioComsumer::control() [%p] - get volume failed with error=%4.4s, %ld on channel %u",this,(char*)&err,(long int)err,i);
861         else {
862             if (setVolValue / 100.0 < setVolumePerChannel)
863                 setVolValue = setVolumePerChannel * 100;
864         }
865         getVolStatus = (err == noErr) || getVolStatus;
866     }
867     if (getVolStatus)
868         params.setParam("out_volume",String(setVolValue));
869     if (!setVolStatus)
870         Debug(DebugAll,"CoreAudioConsumer::control() [%p] - set volume failed on all channels",this);
871 
872     return TelEngine::controlReturn(&params,setVolStatus);
873 }
874 
CoreAudioChan(const String & dev,unsigned int rate)875 CoreAudioChan::CoreAudioChan(const String& dev, unsigned int rate)
876     : CallEndpoint("coreaudio"),
877       m_dev(dev), m_rate(rate)
878 {
879     Debug(DebugAll,"CoreAudioChan::CoreAudioChan ('%s') [%p]",dev.c_str(),this);
880     s_audioChan = this;
881 }
882 
~CoreAudioChan()883 CoreAudioChan::~CoreAudioChan()
884 {
885     Debug(DebugAll,"CoreAudioChan::~CoreAudioChan() [%p]",this);
886     setTarget();
887     setSource();
888     setConsumer();
889     s_audioChan = 0;
890 }
891 
init()892 bool CoreAudioChan::init()
893 {
894     CoreAudioSource* source = new CoreAudioSource(rate());
895     if (!source->init()) {
896 	source->deref();
897 	return false;
898     }
899     setSource(source);
900     source->deref();
901     CoreAudioConsumer* cons = new CoreAudioConsumer(rate());
902     if (!cons->init()) {
903 	cons->deref();
904 	setSource();
905 	return false;
906     }
907     setConsumer(cons);
908     cons->deref();
909     return true;
910 }
911 
disconnected(bool final,const char * reason)912 void CoreAudioChan::disconnected(bool final, const char *reason)
913 {
914     Debug(DebugInfo,"CoreAudioChan::disconnected() '%s' [%p]",reason,this);
915     setTarget();
916 }
917 
answer()918 void CoreAudioChan::answer()
919 {
920     Message* m = new Message("call.answered");
921     m->addParam("module","coreaudio");
922     String tmp("coreaudio/");
923     tmp += m_dev;
924     m->addParam("id",tmp);
925     if (m_target)
926 	m->addParam("targetid",m_target);
927     Engine::enqueue(m);
928 }
929 
received(Message & msg)930 bool CoreAudioHandler::received(Message &msg)
931 {
932     Debug(DebugInfo,"CoreAudio received call.execute");
933     String dest(msg.getValue("callto"));
934     if (dest.null())
935         return false;
936     static const Regexp r("^coreaudio/\\(.*\\)$");
937     if (!dest.matches(r))
938         return false;
939     if (s_audioChan) {
940         msg.setParam("error","busy");
941         return false;
942     }
943     CoreAudioChan *chan = new CoreAudioChan(dest.matchString(1).c_str(),msg.getIntValue("rate",DEFAULT_SAMPLE_RATE));
944     if (!chan->init()) 	{
945         chan->destruct();
946         return false;
947     }
948     CallEndpoint* ch = static_cast<CallEndpoint*>(msg.userData());
949     Debug(DebugInfo,"We are routing to device '%s'",dest.matchString(1).c_str());
950     if (ch && chan->connect(ch,msg.getValue("reason"))) {
951         chan->setTarget(msg.getValue("id"));
952         msg.setParam("peerid",dest);
953         msg.setParam("targetid",dest);
954         chan->answer();
955         chan->deref();
956     }
957     else {
958         const char *direct = msg.getValue("direct");
959         if (direct) {
960 	    Message m("call.execute");
961 	    m.addParam("module","audiocore");
962 	    m.addParam("cdrtrack",String::boolText(false));
963 	    m.addParam("id",dest);
964 	    m.addParam("caller",dest);
965 	    m.addParam("callto",direct);
966 	    m.userData(chan);
967 	    if (Engine::dispatch(m)) {
968 	        chan->setTarget(m.getValue("targetid"));
969 	        msg.addParam("targetid",chan->getTarget());
970 		chan->deref();
971 		return true;
972 	    }
973 	    Debug(DebugInfo,"CoreAudio outgoing call not accepted!");
974 	    chan->destruct();
975 	    return false;
976 	}
977 	const char *targ = msg.getValue("target");
978 	if (!targ) {
979 	    Debug(DebugWarn,"CoreAudio outgoing call with no target!");
980 	    chan->destruct();
981 	    return false;
982 	}
983 	Message m("call.route");
984 	m.addParam("module","audiocore");
985 	m.addParam("cdrtrack",String::boolText(false));
986 	m.addParam("id",dest);
987 	m.addParam("caller",dest);
988 	m.addParam("called",targ);
989 	if (Engine::dispatch(m)) {
990 	    m = "call.execute";
991 	    m.addParam("callto",m.retValue());
992 	    m.retValue() = 0;
993 	    m.userData(chan);
994 	    if (Engine::dispatch(m)) {
995 		chan->setTarget(m.getValue("targetid"));
996 		msg.addParam("targetid",chan->getTarget());
997 		chan->deref();
998 		return true;
999 	    }
1000 	    Debug(DebugInfo,"CoreAudio outgoing call not accepted!");
1001 	}
1002 	else
1003 	    Debug(DebugWarn,"CoreAudio outgoing call but no route!");
1004 	chan->destruct();
1005 	return false;
1006     }
1007 
1008     return true;
1009 }
1010 
received(Message & msg)1011 bool StatusHandler::received(Message &msg)
1012 {
1013     const String* sel = msg.getParam("module");
1014     if (sel && (*sel != "coreaudio"))
1015         return false;
1016     msg.retValue() << "name=coreaudio,type=misc;chan=" << (s_audioChan != 0 ) << "\r\n";
1017     return false;
1018 }
1019 
received(Message & msg)1020 bool MasqHandler::received(Message &msg)
1021 {
1022     String id(msg.getValue("id"));
1023     if (msg.getParam("message") && id.startsWith("coreaudio/")) {
1024 	msg = msg.getValue("message");
1025 	msg.clearParam("message");
1026 	if (s_audioChan) {
1027 	    msg.addParam("targetid",s_audioChan->getTarget());
1028 	    msg.userData(s_audioChan);
1029 	}
1030     }
1031     return false;
1032 }
1033 
received(Message & msg)1034 bool DropHandler::received(Message &msg)
1035 {
1036     String id(msg.getValue("id"));
1037     if (id.null() || id.startsWith("coreaudio/")) {
1038 	if (s_audioChan) {
1039 	    Debug("CoreAudio",DebugInfo,"ping call");
1040 	    s_audioChan->disconnect();
1041 	}
1042 	return !id.null();
1043     }
1044     return false;
1045 }
1046 
received(Message & msg)1047 bool AttachHandler::received(Message& msg)
1048 {
1049     int more = 2;
1050     String src(msg.getValue("source"));
1051     if (src.null())
1052     	more--;
1053     else {
1054     	if (!src.startSkip("coreaudio/",false))
1055 	    src = "";
1056     }
1057 
1058     String cons(msg.getValue("consumer"));
1059     if (cons.null())
1060 	more--;
1061     else {
1062 	if (!cons.startSkip("coreaudio/",false))
1063 	    cons = "";
1064     }
1065 
1066     if (src.null() && cons.null())
1067 	return false;
1068     if (src && cons && (src != cons)) {
1069 	Debug(DebugWarn,"CoreAudio asked to attach source '%s' and consumer '%s'",src.c_str(),cons.c_str());
1070 	return false;
1071     }
1072 
1073     RefPointer<DataEndpoint> dd = static_cast<DataEndpoint*>(msg.userObject(YATOM("DataEndpoint")));
1074     if (!dd) {
1075 	CallEndpoint *ch = static_cast<CallEndpoint*>(msg.userObject(YATOM("CallEndpoint")));
1076 	if (ch) {
1077 	    DataEndpoint::commonMutex().lock();
1078 	    dd = ch->setEndpoint();
1079 	    DataEndpoint::commonMutex().unlock();
1080 	    if (!dd)
1081 		return false;
1082 	}
1083     }
1084     if (!dd) {
1085 	Debug(DebugWarn,"CoreAudio attach request with no control or data channel!");
1086 	return false;
1087     }
1088 
1089     if (src) {
1090 	CoreAudioSource* s = new CoreAudioSource(msg.getIntValue("rate",DEFAULT_SAMPLE_RATE));
1091 	if (s->init())
1092 	    dd->setSource(s);
1093 	s->deref();
1094     }
1095 
1096     if (cons) {
1097 	CoreAudioConsumer* c = new CoreAudioConsumer(msg.getIntValue("rate",DEFAULT_SAMPLE_RATE));
1098 	if (c->init())
1099 	    dd->setConsumer(c);
1100 	c->deref();
1101     }
1102 
1103     // Stop dispatching if we handled all requested
1104     return !more;
1105 }
1106 
CoreAudioPlugin()1107 CoreAudioPlugin::CoreAudioPlugin()
1108 	: Plugin("coreaudio"),
1109 	  m_handler(0)
1110 {
1111     Output("Loaded module CoreAudio");
1112 }
1113 
initialize()1114 void CoreAudioPlugin::initialize()
1115 {
1116     Output("Initializing module CoreAudio");
1117     if (!m_handler) {
1118 	m_handler = new CoreAudioHandler("call.execute");
1119 	Engine::install(m_handler);
1120 	Engine::install(new MasqHandler(10));
1121 	Engine::install(new DropHandler());
1122 	Engine::install(new StatusHandler());
1123 	Engine::install(new AttachHandler());
1124     }
1125 }
1126 
isBusy() const1127 bool CoreAudioPlugin::isBusy() const
1128 {
1129     return (s_audioChan != 0);
1130 }
1131 
1132 }; // anonymous namespace
1133 
1134 /* vi: set ts=8 sw=4 sts=4 noet: */
1135