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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2427 - (show annotations) (download)
Sat Mar 2 07:03:04 2013 UTC (11 years, 1 month 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 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2009 - 2013 Grigor Iliev *
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 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 if(charBufSize < len) charBufSize = len;
121 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 LockGuard lock(DeviceMutex);
251 for(int i = 0; i < GetListenerCount(); i++) {
252 GetListener(i)->DeviceChanged(devID);
253 }
254 }
255
256 void CAAudioDeviceListModel::FireDeviceListChangedEvent() {
257 LockGuard lock(DeviceMutex);
258 for(int i = 0; i < GetListenerCount(); i++) {
259 GetListener(i)->DeviceListChanged();
260 }
261 }
262
263 void CAAudioDeviceListModel::FireDefaultOutputDeviceChangedEvent(AudioDeviceID newID) {
264 LockGuard lock(DeviceMutex);
265 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 LockGuard lock(DeviceMutex);
276 return outDevices.size();
277 }
278
279 CAAudioDeviceModel CAAudioDeviceListModel::GetOutputDevice(UInt32 Index) {
280 LockGuard lock(DeviceMutex);
281 if(Index < 0 || Index >= GetOutputDeviceCount()) {
282 throw Exception("Device index out of bounds");
283 }
284
285 return outDevices[Index];
286 }
287
288 CAAudioDeviceModel CAAudioDeviceListModel::GetOutputDeviceByID(AudioDeviceID devID) {
289 LockGuard lock(DeviceMutex);
290 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 LockGuard lock(DeviceMutex);
301 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 LockGuard lock(DeviceMutex);
311 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