/[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 3054 - (show 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 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2009 Grigor Iliev *
6 * Copyright (C) 2013 - 2016 Andreas Persson and Christian Schoenebeck *
7 * *
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 if(charBufSize < len) charBufSize = (UInt32)len;
122 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 LockGuard lock(DeviceMutex);
252 for(int i = 0; i < GetListenerCount(); i++) {
253 GetListener(i)->DeviceChanged(devID);
254 }
255 }
256
257 void CAAudioDeviceListModel::FireDeviceListChangedEvent() {
258 LockGuard lock(DeviceMutex);
259 for(int i = 0; i < GetListenerCount(); i++) {
260 GetListener(i)->DeviceListChanged();
261 }
262 }
263
264 void CAAudioDeviceListModel::FireDefaultOutputDeviceChangedEvent(AudioDeviceID newID) {
265 LockGuard lock(DeviceMutex);
266 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 LockGuard lock(DeviceMutex);
277 return (UInt32) outDevices.size();
278 }
279
280 CAAudioDeviceModel CAAudioDeviceListModel::GetOutputDevice(UInt32 Index) {
281 LockGuard lock(DeviceMutex);
282 if(/*Index < 0 ||*/ Index >= GetOutputDeviceCount()) {
283 throw Exception("Device index out of bounds");
284 }
285
286 return outDevices[Index];
287 }
288
289 CAAudioDeviceModel CAAudioDeviceListModel::GetOutputDeviceByID(AudioDeviceID devID) {
290 LockGuard lock(DeviceMutex);
291 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 LockGuard lock(DeviceMutex);
302 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 LockGuard lock(DeviceMutex);
312 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 if(res) {
458 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