/[svn]/linuxsampler/trunk/src/drivers/audio/CAAudioDeviceModel.cpp
ViewVC logotype

Annotation of /linuxsampler/trunk/src/drivers/audio/CAAudioDeviceModel.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2427 - (hide annotations) (download)
Sat Mar 2 07:03:04 2013 UTC (11 years, 3 months ago) by persson
File size: 19497 byte(s)
* code refactoring: added a lock guard class for exception safe mutex
  handling and used it everywhere appropriate

1 iliev 1832 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5 persson 2427 * Copyright (C) 2009 - 2013 Grigor Iliev *
6 iliev 1832 * *
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 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, *
20     * MA 02111-1307 USA *
21     ***************************************************************************/
22    
23     #include "CAAudioDeviceModel.h"
24    
25     #include <iostream>
26     #include "../../common/Exception.h"
27     #include "../../common/global_private.h"
28    
29     namespace LinuxSampler {
30    
31     CAAudioDeviceModel::CAAudioDeviceModel(AudioDeviceID Id) {
32     this->Id = Id;
33     ChannelNumber = 2;
34     DefaultSamplerate = 44100;
35    
36     charBufSize = 512;
37     charBuf = new char[charBufSize];
38    
39     Init();
40     }
41    
42     CAAudioDeviceModel::CAAudioDeviceModel(const CAAudioDeviceModel& m) : Uid(m.Uid),
43     Name(m.Name), NominalSamplerates(m.NominalSamplerates), AudioStreams(m.AudioStreams) {
44    
45     Id = m.Id;
46     ChannelNumber = m.ChannelNumber;
47     DefaultSamplerate = m.DefaultSamplerate;
48    
49     charBufSize = 512;
50     charBuf = new char[charBufSize];
51    
52     Init();
53     }
54    
55     CAAudioDeviceModel::~CAAudioDeviceModel() {
56     CAAudioDeviceListModel::GetModel()->RemoveListener(this);
57     delete [] charBuf;
58     }
59    
60     CAAudioDeviceModel& CAAudioDeviceModel::operator=(const CAAudioDeviceModel& m) {
61     Id = m.Id;
62     Uid = m.Uid;
63     Name = m.Name;
64     ChannelNumber = m.ChannelNumber;
65     DefaultSamplerate = m.DefaultSamplerate;
66     NominalSamplerates = m.NominalSamplerates;
67     AudioStreams = m.AudioStreams;
68    
69     return *this;
70     }
71    
72     void CAAudioDeviceModel::Init() {
73     CAAudioDeviceListModel::GetModel()->AddListener(this);
74     }
75    
76     void CAAudioDeviceModel::DeviceChanged(AudioDeviceID devID) {
77     if(GetID() == devID) FireDeviceChangedEvent();
78     }
79    
80     void CAAudioDeviceModel::FireDeviceChangedEvent() {
81     for(int i = 0; i < GetListenerCount(); i++) {
82     GetListener(i)->DeviceChanged();
83     }
84     }
85    
86     AudioDeviceID CAAudioDeviceModel::GetID() { return Id; }
87    
88     std::string CAAudioDeviceModel::GetUID() { return Uid; }
89    
90     void CAAudioDeviceModel::SetUID(CFStringRef s) {
91     Uid = GetStr(s);
92     }
93    
94     std::string CAAudioDeviceModel::GetName() { return Name; }
95    
96     void CAAudioDeviceModel::SetName(CFStringRef s) {
97     Name = GetStr(s);
98     }
99    
100     int CAAudioDeviceModel::GetChannelNumber() { return ChannelNumber; }
101    
102     int CAAudioDeviceModel::GetDefaultSamplerate() { return DefaultSamplerate; }
103    
104     const std::vector<int> CAAudioDeviceModel::GetNominalSamplerates() {
105     return NominalSamplerates;
106     }
107    
108     std::vector<CAAudioStream> CAAudioDeviceModel::GetAudioStreams() {
109     return AudioStreams;
110     }
111    
112     std::string CAAudioDeviceModel::GetStr(CFStringRef s) {
113     if(s == NULL) return std::string("Undefined");
114    
115     CFRetain(s);
116     CFIndex len = CFStringGetLength(s) + 1;
117     if(charBufSize < len) {
118     delete [] charBuf;
119     charBufSize *= 2;
120 iliev 1846 if(charBufSize < len) charBufSize = len;
121 iliev 1832 charBuf = new char[charBufSize];
122     }
123    
124     std::string s2;
125     if(CFStringGetCString(s, charBuf, charBufSize, kCFStringEncodingASCII)) {
126     s2 = charBuf;
127     }
128     CFRelease(s);
129    
130     return s2;
131     }
132    
133     //////////////////////////////////////////////////////////////////
134     ////
135    
136     CAAudioDeviceListModel* CAAudioDeviceListModel::pModel = NULL;
137    
138     CAAudioDeviceListModel* CAAudioDeviceListModel::GetModel() {
139     if(pModel == NULL) {
140     pModel = new CAAudioDeviceListModel();
141     pModel->RescanDevices();
142     pModel->InstallListeners();
143     }
144     return pModel;
145     }
146    
147     OSStatus CAAudioDeviceListModel::AudioHardwarePropertyListenerCallback (
148     AudioHardwarePropertyID inPropertyID, void* inClientData
149     ) {
150     CAAudioDeviceListModel* model = CAAudioDeviceListModel::GetModel();
151     switch(inPropertyID) {
152     case kAudioHardwarePropertyDevices:
153     model->RescanDevices();
154     break;
155     case kAudioHardwarePropertyDefaultOutputDevice:
156     model->UpdateDefaultOutputDevice();
157     model->FireDefaultOutputDeviceChangedEvent(model->GetDefaultOutputDeviceID());
158     break;
159     }
160     return noErr;
161     }
162    
163     OSStatus CAAudioDeviceListModel::AudioDevicePropertyListenerCallback (
164     AudioDeviceID inDevice,
165     UInt32 inChannel,
166     Boolean isInput,
167     AudioDevicePropertyID inPropertyID,
168     void* inClientData
169     ) {
170     CAAudioDeviceListModel* model = CAAudioDeviceListModel::GetModel();
171    
172     switch(inPropertyID) {
173     case kAudioDevicePropertyDeviceHasChanged:
174     model->FireDeviceChangedEvent(inDevice);
175     break;
176     }
177    
178     return noErr;
179     }
180    
181     CAAudioDeviceListModel::CAAudioDeviceListModel() {
182     DefaultOutputDeviceID = 0;
183     }
184    
185     CAAudioDeviceListModel::~CAAudioDeviceListModel() {
186     UninstallListeners();
187     }
188    
189     void CAAudioDeviceListModel::InstallListeners() {
190     InstallHardwareListeners();
191     InstallDeviceListeners();
192     }
193    
194     void CAAudioDeviceListModel::UninstallListeners() {
195     UninstallHardwareListeners();
196     UninstallDeviceListeners();
197     }
198    
199     void CAAudioDeviceListModel::InstallHardwareListeners() {
200     // Notify when device is added or removed
201     InstallHardwareListener(kAudioHardwarePropertyDevices);
202     //Notify when the default audio output device is changed
203     InstallHardwareListener(kAudioHardwarePropertyDefaultOutputDevice);
204     }
205    
206     void CAAudioDeviceListModel::UninstallHardwareListeners() {
207     UninstallHardwareListener(kAudioHardwarePropertyDevices);
208     UninstallHardwareListener(kAudioHardwarePropertyDefaultOutputDevice);
209     }
210    
211     void CAAudioDeviceListModel::InstallHardwareListener(AudioHardwarePropertyID id) {
212     AudioHardwareAddPropertyListener (
213     id, AudioHardwarePropertyListenerCallback, NULL
214     );
215     }
216    
217     void CAAudioDeviceListModel::UninstallHardwareListener(AudioHardwarePropertyID id) {
218     AudioHardwareRemovePropertyListener (
219     id, AudioHardwarePropertyListenerCallback
220     );
221     }
222    
223     void CAAudioDeviceListModel::InstallDeviceListeners() {
224     InstallDeviceListener(kAudioDevicePropertyDeviceHasChanged);
225     }
226    
227     void CAAudioDeviceListModel::UninstallDeviceListeners() {
228     UninstallDeviceListener(kAudioDevicePropertyDeviceHasChanged);
229     }
230    
231     void CAAudioDeviceListModel::InstallDeviceListener(AudioDevicePropertyID id) {
232     for(int i = 0; i < GetModel()->GetOutputDeviceCount(); i++) {
233     AudioDeviceAddPropertyListener (
234     GetModel()->GetOutputDevice(i).GetID(), 0, false,
235     id, AudioDevicePropertyListenerCallback, NULL
236     );
237     }
238     }
239    
240     void CAAudioDeviceListModel::UninstallDeviceListener(AudioDevicePropertyID id) {
241     for(int i = 0; i < GetModel()->GetOutputDeviceCount(); i++) {
242     AudioDeviceRemovePropertyListener (
243     GetModel()->GetOutputDevice(i).GetID(), 0, false,
244     id, AudioDevicePropertyListenerCallback
245     );
246     }
247     }
248    
249     void CAAudioDeviceListModel::FireDeviceChangedEvent(AudioDeviceID devID) {
250 persson 2427 LockGuard lock(DeviceMutex);
251 iliev 1832 for(int i = 0; i < GetListenerCount(); i++) {
252     GetListener(i)->DeviceChanged(devID);
253     }
254     }
255    
256     void CAAudioDeviceListModel::FireDeviceListChangedEvent() {
257 persson 2427 LockGuard lock(DeviceMutex);
258 iliev 1832 for(int i = 0; i < GetListenerCount(); i++) {
259     GetListener(i)->DeviceListChanged();
260     }
261     }
262    
263     void CAAudioDeviceListModel::FireDefaultOutputDeviceChangedEvent(AudioDeviceID newID) {
264 persson 2427 LockGuard lock(DeviceMutex);
265 iliev 1832 for(int i = 0; i < GetListenerCount(); i++) {
266     GetListener(i)->DefaultOutputDeviceChanged(newID);
267     }
268     }
269    
270     AudioDeviceID CAAudioDeviceListModel::GetDefaultOutputDeviceID() {
271     return DefaultOutputDeviceID;
272     }
273    
274     UInt32 CAAudioDeviceListModel::GetOutputDeviceCount() {
275 persson 2427 LockGuard lock(DeviceMutex);
276     return outDevices.size();
277 iliev 1832 }
278    
279     CAAudioDeviceModel CAAudioDeviceListModel::GetOutputDevice(UInt32 Index) {
280 persson 2427 LockGuard lock(DeviceMutex);
281 iliev 1832 if(Index < 0 || Index >= GetOutputDeviceCount()) {
282     throw Exception("Device index out of bounds");
283     }
284    
285 persson 2427 return outDevices[Index];
286 iliev 1832 }
287    
288     CAAudioDeviceModel CAAudioDeviceListModel::GetOutputDeviceByID(AudioDeviceID devID) {
289 persson 2427 LockGuard lock(DeviceMutex);
290 iliev 1832 for(int i = 0; i < outDevices.size(); i++) {
291     if(outDevices[i].GetID() == devID) {
292     CAAudioDeviceModel dev = outDevices[i];
293     return dev;
294     }
295     }
296     throw Exception("Unknown audio device ID: " + ToString(devID));
297     }
298    
299     UInt32 CAAudioDeviceListModel::GetOutputDeviceIndex(AudioDeviceID devID) {
300 persson 2427 LockGuard lock(DeviceMutex);
301 iliev 1832 for(UInt32 i = 0; i < outDevices.size(); i++) {
302     if(outDevices[i].GetID() == devID) {
303     return i;
304     }
305     }
306     throw Exception("Unknown audio device ID: " + ToString(devID));
307     }
308    
309     void CAAudioDeviceListModel::RescanDevices() {
310 persson 2427 LockGuard lock(DeviceMutex);
311 iliev 1832 inDevices.clear();
312     outDevices.clear();
313    
314     UInt32 outSize;
315     Boolean outWritable;
316    
317     UpdateDefaultOutputDevice();
318    
319     OSStatus res = AudioHardwareGetPropertyInfo (
320     kAudioHardwarePropertyDevices, &outSize, &outWritable
321     );
322    
323     if(res) {
324     std::cerr << "Failed to get device list: " << res << std::endl;
325     return;
326     }
327    
328     UInt32 deviceNumber = outSize / sizeof(AudioDeviceID);
329     if(deviceNumber < 1) {
330     std::cerr << "No audio devices found" << std::endl;
331     return;
332     }
333    
334     if(deviceNumber * sizeof(AudioDeviceID) != outSize) {
335     std::cerr << "Invalid device size. This is a bug!" << std::endl;
336     return;
337     }
338    
339     AudioDeviceID* devs = new AudioDeviceID[deviceNumber];
340    
341     res = AudioHardwareGetProperty (
342     kAudioHardwarePropertyDevices, &outSize, devs
343     );
344    
345     if(res) {
346     std::cerr << "Failed to get device IDs: " << res << std::endl;
347     delete [] devs;
348     return;
349     }
350    
351     for(int i = 0; i < deviceNumber; i++) {
352     // TODO: for now skip devices which are not alive
353     outSize = sizeof(UInt32);
354     UInt32 isAlive = 0;
355    
356     res = AudioDeviceGetProperty (
357     devs[i], 0, false,
358     kAudioDevicePropertyDeviceIsAlive,
359     &outSize, &isAlive
360     );
361    
362     if(res || !isAlive) continue;
363     ///////
364    
365     CAAudioDeviceModel dev(devs[i]);
366    
367     CFStringRef tempStringRef = NULL;
368    
369     // Get the name of the device
370     outSize = sizeof(CFStringRef);
371    
372     res = AudioDeviceGetProperty (
373     devs[i], 0, false,
374     kAudioObjectPropertyName,
375     &outSize, &tempStringRef
376     );
377    
378     dev.SetName(tempStringRef);
379     if(tempStringRef != NULL) CFRelease(tempStringRef);
380     ///////
381    
382     // Get the name of the device
383     outSize = sizeof(CFStringRef);
384    
385     res = AudioDeviceGetProperty (
386     devs[i], 0, false,
387     kAudioDevicePropertyDeviceUID,
388     &outSize, &tempStringRef
389     );
390    
391     dev.SetUID(tempStringRef);
392     if(tempStringRef != NULL) CFRelease(tempStringRef);
393     ///////
394    
395     GetChannels(&dev);
396     GetSamplerates(&dev);
397     if(dev.GetChannelNumber() > 0) outDevices.push_back(dev);
398     }
399    
400     delete [] devs;
401     FireDeviceListChangedEvent();
402    
403     /*for(int i = 0; i < GetOutputDeviceCount(); i++) {
404     std::cout << "Device ID: " << GetOutputDevice(i).GetID() << std::endl;
405     std::cout << "Device name: " << GetOutputDevice(i).GetName() << std::endl;
406     std::cout << "Device UID: " << GetOutputDevice(i).GetUID() << std::endl;
407     std::cout << "Channels: " << GetOutputDevice(i).GetChannelNumber() << std::endl;
408     std::cout << "Default samplerate: " << GetOutputDevice(i).GetDefaultSamplerate() << std::endl;
409    
410     const std::vector<int> rates = GetOutputDevice(i).GetNominalSamplerates();
411     std::cout << "Nominal samplerates: " << std::endl;
412     for(int j = 0; j < rates.size(); j++) {
413     std::cout << "\t" << rates[j] << std::endl;
414     }
415     std::cout << std::endl;
416     }*/
417     }
418    
419     void CAAudioDeviceListModel::UpdateDefaultOutputDevice() {
420     AudioDeviceID id;
421     UInt32 size = sizeof(AudioDeviceID);
422     OSStatus res = AudioHardwareGetProperty (
423     kAudioHardwarePropertyDefaultOutputDevice, &size, &id
424     );
425     if(res) std::cerr << "Failed to get default output device: " << res << std::endl;
426     else DefaultOutputDeviceID = id;
427     }
428    
429     void CAAudioDeviceListModel::GetChannels(CAAudioDeviceModel* pDev) {
430     UInt32 outSize;
431     bool isInput = false;
432    
433     OSStatus res = AudioDeviceGetPropertyInfo (
434     pDev->GetID(), 0, isInput,
435     kAudioDevicePropertyStreamConfiguration,
436     &outSize, NULL
437     );
438     if(res || outSize == 0) {
439     if(res) std::cerr << "Failed to get stream config: " << res << std::endl;
440     return;
441     }
442    
443     AudioBufferList* pBufferList = NULL;
444     pBufferList = (AudioBufferList*)malloc(outSize);
445     if(pBufferList == NULL) {
446     perror(NULL);
447     return;
448     }
449    
450     res = AudioDeviceGetProperty (
451     pDev->GetID(), 0, isInput,
452     kAudioDevicePropertyStreamConfiguration,
453     &outSize, pBufferList
454     );
455    
456     if(res = noErr) {
457     std::cerr << "Failed to get channel number: " << res << std::endl;
458     free(pBufferList);
459     return;
460     }
461    
462     UInt32 chns = 0;
463     for(int i = 0; i < pBufferList->mNumberBuffers; i++) {
464     chns += pBufferList->mBuffers[i].mNumberChannels;
465     }
466    
467     pDev->ChannelNumber = chns;
468    
469     free(pBufferList);
470     }
471    
472     /*void CAAudioDeviceListModel::GetStreams(CAAudioDeviceModel* pDev) {
473     UInt32 outSize = sizeof(AudioStreamID);
474    
475     OSStatus res = AudioDeviceGetPropertyInfo (
476     pDev->GetID(), 0, false,
477     kAudioDevicePropertyStreams,
478     &outSize, NULL
479     );
480    
481     if(res) {
482     std::cerr << "Failed to get device streams: " << res << std::endl;
483     return;
484     }
485    
486     UInt32 streamNumber = outSize / sizeof(AudioStreamID);
487     if(streamNumber < 1) {
488     std::cerr << "No streams found" << std::endl;
489     return;
490     }
491    
492     if(streamNumber * sizeof(AudioStreamID) != outSize) {
493     std::cerr << "Invalid AudioStreamID size. This is a bug!" << std::endl;
494     return;
495     }
496    
497     AudioStreamID* streams = new AudioStreamID[streamNumber];
498    
499     res = AudioDeviceGetProperty (
500     pDev->GetID(), 0, false,
501     kAudioDevicePropertyStreams,
502     &outSize, streams
503     );
504    
505     if(res) {
506     std::cerr << "Failed to get stream IDs: " << res << std::endl;
507     delete [] streams;
508     return;
509     }
510    
511     for(int i = 0; i < streamNumber; i++) {
512     UInt32 inStream;
513    
514     res = AudioStreamGetProperty (
515     streams[i], 0, kAudioStreamPropertyDirection, &outSize, &inStream
516     );
517    
518     if(res) {
519     std::cerr << "Failed to get stream direction: " << res << std::endl;
520     continue;
521     }
522    
523     //pDev->AudioStreams.push_back(CAAudioStream(inStream, chns));
524     }
525    
526     delete [] streams;
527     }*/
528    
529     void CAAudioDeviceListModel::GetSamplerates(CAAudioDeviceModel* pDev) {
530     UInt32 outSize;
531    
532     // Get current nominal sample rate
533     outSize = sizeof(Float64);
534     Float64 srate;
535    
536     OSStatus res = AudioDeviceGetProperty (
537     pDev->GetID(), 0, false,
538     kAudioDevicePropertyNominalSampleRate,
539     &outSize, &srate
540     );
541    
542     if(res) std::cerr << "Failed to get default samplerate: " << res << std::endl;
543     else pDev->DefaultSamplerate = srate;
544     ///////
545    
546     res = AudioDeviceGetPropertyInfo (
547     pDev->GetID(), 0, false,
548     kAudioDevicePropertyAvailableNominalSampleRates,
549     &outSize, NULL
550     );
551    
552     if(res) {
553     std::cerr << "Failed to get nominal samplerates: " << res << std::endl;
554     return;
555     }
556    
557     UInt32 rangeNumber = outSize / sizeof(AudioValueRange);
558     if(rangeNumber < 1) {
559     std::cerr << "No nominal samplerates found" << std::endl;
560     return;
561     }
562    
563     if(rangeNumber * sizeof(AudioValueRange) != outSize) {
564     std::cerr << "Invalid AudioValueRange size. This is a bug!" << std::endl;
565     return;
566     }
567    
568     AudioValueRange* ranges = new AudioValueRange[rangeNumber];
569    
570     res = AudioDeviceGetProperty (
571     pDev->GetID(), 0, false,
572     kAudioDevicePropertyAvailableNominalSampleRates,
573     &outSize, ranges
574     );
575    
576     if(res) {
577     std::cerr << "Failed to get samplerate ranges: " << res << std::endl;
578     delete [] ranges;
579     return;
580     }
581    
582     for(int i = 0; i < rangeNumber; i++) {
583     // FIXME: might be ranges of valid samplerates
584     UInt32 min = (UInt32)ranges[i].mMinimum;
585     UInt32 max = (UInt32)ranges[i].mMaximum;
586     pDev->NominalSamplerates.push_back(min);
587     if(min != max) pDev->NominalSamplerates.push_back(max);
588     }
589    
590     delete [] ranges;
591     }
592     } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC