/[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 3054 - (hide annotations) (download)
Thu Dec 15 12:47:45 2016 UTC (7 years, 4 months ago) by schoenebeck
File size: 19587 byte(s)
* Fixed numerous compiler warnings.
* Bumped version (2.0.0.svn32).

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

  ViewVC Help
Powered by ViewVC