/[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 1832 - (show annotations) (download)
Thu Feb 5 17:48:54 2009 UTC (15 years, 2 months ago) by iliev
File size: 19921 byte(s)
* CoreAudio: Improved hardware detection
* CoreAudio: Added new driver parameter DEVICE
* CoreAudio: Restart the audio queue when the device
  is changed, for example when headphones are plugged

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

  ViewVC Help
Powered by ViewVC