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

Diff of /linuxsampler/trunk/src/drivers/audio/AudioOutputDeviceCoreAudio.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1831 by iliev, Fri Jan 30 19:22:36 2009 UTC revision 1832 by iliev, Thu Feb 5 17:48:54 2009 UTC
# Line 26  Line 26 
26    
27  namespace LinuxSampler {  namespace LinuxSampler {
28    
29        void AudioOutputDeviceCoreAudio::AudioQueueListener (
30                void *inUserData, AudioQueueRef inAQ, AudioQueuePropertyID inID
31        ) {
32            switch(inID) {
33                case kAudioQueueProperty_IsRunning:
34                    
35                    break;
36                case kAudioQueueProperty_CurrentDevice:
37                    
38                    break;
39            }
40        }
41    
42      void AudioOutputDeviceCoreAudio::HandleOutputBuffer (      void AudioOutputDeviceCoreAudio::HandleOutputBuffer (
43          void                 *aqData,          void                 *aqData,
44          AudioQueueRef        inAQ,          AudioQueueRef        inAQ,
# Line 37  namespace LinuxSampler { Line 50  namespace LinuxSampler {
50              AudioQueueStop (pAqData->mQueue, true);              AudioQueueStop (pAqData->mQueue, true);
51              return;              return;
52          }          }
53    
54            if(atomic_read(&(pAqData->pDevice->restartQueue))) return;
55    
56          uint bufferSize = pAqData->pDevice->uiBufferSize;          uint bufferSize = pAqData->pDevice->uiBufferSize;
57    
58          // let all connected engines render 'fragmentSize' sample points          // let all connected engines render 'fragmentSize' sample points
# Line 63  namespace LinuxSampler { Line 79  namespace LinuxSampler {
79          if(res) std::cerr << "AudioQueueEnqueueBuffer: Error " << res << std::endl;          if(res) std::cerr << "AudioQueueEnqueueBuffer: Error " << res << std::endl;
80      }      }
81    
82      AudioOutputDeviceCoreAudio::DeviceInfo* AudioOutputDeviceCoreAudio::pDeviceInfo = NULL;      void AudioOutputDeviceCoreAudio::DeviceChanged() {
83            dmsg(1,("Restarting audio queue..."));
84      AudioOutputDeviceCoreAudio::DeviceInfo* AudioOutputDeviceCoreAudio::GetDeviceInfo() {          atomic_set(&restartQueue, 1);
         if(pDeviceInfo == NULL) {  
             pDeviceInfo = new DeviceInfo;  
   
             pDeviceInfo->uiSamplerate = 44100;  
             pDeviceInfo->uiChannelNumber = 2;  
   
             AudioStreamBasicDescription dataFormat;  
             SetAudioDataFormat(&dataFormat);  
             AudioQueueRef pQueue = NULL;  
   
             OSStatus res = AudioQueueNewOutput (  
                 &dataFormat, NULL, NULL, NULL, NULL, 0, &pQueue  
             );  
   
             if(res) {  
                 std::cerr << "Failed to retrieve device info: " << res << std::endl;  
                 return pDeviceInfo;  
             }  
   
             UInt32 chns = pDeviceInfo->uiChannelNumber;  
             UInt32 size = sizeof(chns);  
             res = AudioQueueGetProperty (  
                 pQueue,  
                 kAudioQueueDeviceProperty_NumberChannels,  
                 &chns, &size  
             );  
   
             if(res) std::cerr << "Failed to retrieve channel number: " << res << std::endl;  
             else pDeviceInfo->uiChannelNumber = chns;  
   
             Float64 sRate = pDeviceInfo->uiSamplerate;  
             size = sizeof(sRate);  
             res = AudioQueueGetProperty (  
                 pQueue,  
                 kAudioQueueDeviceProperty_SampleRate,  
                 &sRate, &size  
             );  
   
             if(res) std::cerr << "Failed to retrieve samplerate: " << res << std::endl;  
             else pDeviceInfo->uiSamplerate = (uint)sRate;  
   
             AudioQueueDispose(pQueue, true);  
         }  
   
         return pDeviceInfo;  
85      }      }
86    
87      AudioOutputDeviceCoreAudio::AudioOutputDeviceCoreAudio (      AudioOutputDeviceCoreAudio::AudioOutputDeviceCoreAudio (
88                      std::map<String,DeviceCreationParameter*> Parameters                      std::map<String,DeviceCreationParameter*> Parameters
89      ) : AudioOutputDevice(Parameters), Thread(true, true, 1, 0) {      ) : AudioOutputDevice(Parameters), Thread(true, true, 1, 0), CurrentDevice(0) {
90    
91          dmsg(2,("AudioOutputDeviceCoreAudio::AudioOutputDeviceCoreAudio()\n"));          dmsg(2,("AudioOutputDeviceCoreAudio::AudioOutputDeviceCoreAudio()\n"));
92            if(CAAudioDeviceListModel::GetModel()->GetOutputDeviceCount() < 1) {
93                throw Exception("No audio output device found");
94            }
95          atomic_set(&pausedNew, 0);          atomic_set(&pausedNew, 0);
96          pausedOld = 0;          pausedOld = 0;
97            atomic_set(&restartQueue, 0);
98    
99          uiCoreAudioChannels = ((DeviceCreationParameterInt*)Parameters["CHANNELS"])->ValueAsInt();          uiCoreAudioChannels = ((DeviceCreationParameterInt*)Parameters["CHANNELS"])->ValueAsInt();
100          uint samplerate     = ((DeviceCreationParameterInt*)Parameters["SAMPLERATE"])->ValueAsInt();          uint samplerate     = ((DeviceCreationParameterInt*)Parameters["SAMPLERATE"])->ValueAsInt();
101          uiBufferNumber     = ((DeviceCreationParameterInt*)Parameters["BUFFERS"])->ValueAsInt();          uiBufferNumber      = ((DeviceCreationParameterInt*)Parameters["BUFFERS"])->ValueAsInt();
102          uiBufferSize        = ((DeviceCreationParameterInt*)Parameters["BUFFERSIZE"])->ValueAsInt();          uiBufferSize        = ((DeviceCreationParameterInt*)Parameters["BUFFERSIZE"])->ValueAsInt();
103            int device = 0;
104            try { device = ((ParameterDevice*)Parameters["DEVICE"])->GetDeviceIndex(); }
105            catch(Exception x) { }
106    
107            CurrentDevice = CAAudioDeviceListModel::GetModel()->GetOutputDevice(device);
108            CurrentDevice.AddListener(this);
109    
110          aqPlayerState.mDataFormat.mSampleRate = samplerate;          aqPlayerState.mDataFormat.mSampleRate = samplerate;
111          aqPlayerState.mDataFormat.mFormatID = kAudioFormatLinearPCM;          aqPlayerState.mDataFormat.mFormatID = kAudioFormatLinearPCM;
# Line 167  namespace LinuxSampler { Line 148  namespace LinuxSampler {
148          AudioQueueDispose(aqPlayerState.mQueue, true);          AudioQueueDispose(aqPlayerState.mQueue, true);
149          destroyMutex.Unlock();          destroyMutex.Unlock();
150          delete [] aqPlayerState.mBuffers;          delete [] aqPlayerState.mBuffers;
151    
152            CurrentDevice.RemoveListener(this);
153      }      }
154    
155      void AudioOutputDeviceCoreAudio::SetAudioDataFormat(AudioStreamBasicDescription* pDataFormat) {      void AudioOutputDeviceCoreAudio::SetAudioDataFormat(AudioStreamBasicDescription* pDataFormat) {
# Line 192  namespace LinuxSampler { Line 175  namespace LinuxSampler {
175      }      }
176    
177      String AudioOutputDeviceCoreAudio::Version() {      String AudioOutputDeviceCoreAudio::Version() {
178         String s = "$Revision: 1.1 $";         String s = "$Revision: 1.2 $";
179         return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword         return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
180      }      }
181    
# Line 225  namespace LinuxSampler { Line 208  namespace LinuxSampler {
208          return new AudioChannel(ChannelNr, Channel(ChannelNr % uiCoreAudioChannels));          return new AudioChannel(ChannelNr, Channel(ChannelNr % uiCoreAudioChannels));
209      }      }
210    
211      /**      void AudioOutputDeviceCoreAudio::FillBuffers() {
212       * Entry point for the thread.          for (int i = 0; i < uiBufferNumber; ++i) {
213       */              HandleOutputBuffer (
     int AudioOutputDeviceCoreAudio::Main() {  
         dmsg(2,("CoreAudio thread started\n"));  
   
         bool initialized = aqPlayerState.mQueue != NULL;  
         if(!initialized) {  
             /*  
              * Initializing the audio queue  
              * Need to be run from this thread because of CFRunLoopGetCurrent()  
              * which returns the CFRunLoop object for the current thread.  
              */  
             OSStatus res = AudioQueueNewOutput (  
                 &aqPlayerState.mDataFormat,  
                 HandleOutputBuffer,  
214                  &aqPlayerState,                  &aqPlayerState,
215                  CFRunLoopGetCurrent(),                  aqPlayerState.mQueue,
216                  kCFRunLoopCommonModes,                  aqPlayerState.mBuffers[i]
                 0,  
                 &aqPlayerState.mQueue  
217              );              );
218            }
219        }
220    
221              if(res) {      void AudioOutputDeviceCoreAudio::PrimeAudioQueue() {
222                  String s = String("AudioQueueNewOutput: Error ") + ToString(res);          OSStatus res = AudioQueuePrime(aqPlayerState.mQueue, 0, NULL);
223                  throw Exception(s);          if(res) {
224              }              String s = String("AudioQueuePrime: Error ") + ToString(res);
225                throw Exception(s);
226            }
227        }
228    
229              for (int i = 0; i < uiBufferNumber; ++i) {      void AudioOutputDeviceCoreAudio::CreateAndStartAudioQueue() {
230                  OSStatus res = AudioQueueAllocateBuffer (          OSStatus res = AudioQueueNewOutput (
231                      aqPlayerState.mQueue,              &aqPlayerState.mDataFormat,
232                      aqPlayerState.bufferByteSize,              HandleOutputBuffer,
233                      &aqPlayerState.mBuffers[i]              &aqPlayerState,
234                  );              CFRunLoopGetCurrent(),
235                kCFRunLoopCommonModes,
236                  if(res) {              0,
237                      String s = String("AudioQueueAllocateBuffer: Error ");              &aqPlayerState.mQueue
238                      throw Exception(s + ToString(res));          );
239                  }  
240              }          if(res) {
241                String s = String("AudioQueueNewOutput: Error ") + ToString(res);
242                throw Exception(s);
243            }
244    
245            CFStringRef devUID = CFStringCreateWithCString (
246                NULL, CurrentDevice.GetUID().c_str(), kCFStringEncodingASCII
247            );
248            res = AudioQueueSetProperty (
249                aqPlayerState.mQueue,
250                kAudioQueueProperty_CurrentDevice,
251                &devUID, sizeof(CFStringRef)
252            );
253            CFRelease(devUID);
254    
255            if(res) {
256                String s = String("Failed to set audio device: ") + ToString(res);
257                throw Exception(s);
258          }          }
259    
260          for (int i = 0; i < uiBufferNumber; ++i) {          for (int i = 0; i < uiBufferNumber; ++i) {
261              HandleOutputBuffer (              res = AudioQueueAllocateBuffer (
                 &aqPlayerState,  
262                  aqPlayerState.mQueue,                  aqPlayerState.mQueue,
263                  aqPlayerState.mBuffers[i]                  aqPlayerState.bufferByteSize,
264                    &aqPlayerState.mBuffers[i]
265              );              );
266    
267                if(res) {
268                    String s = String("AudioQueueAllocateBuffer: Error ");
269                    throw Exception(s + ToString(res));
270                }
271          }          }
272    
273            res = AudioQueueAddPropertyListener (
274                aqPlayerState.mQueue,
275                kAudioQueueProperty_CurrentDevice,
276                AudioQueueListener,
277                NULL
278            );
279            if(res) std::cerr << "Failed to register device change listener: " << res << std::endl;
280    
281            res = AudioQueueAddPropertyListener (
282                aqPlayerState.mQueue,
283                kAudioQueueProperty_IsRunning,
284                AudioQueueListener,
285                NULL
286            );
287            if(res) std::cerr << "Failed to register running listener: " << res << std::endl;
288    
289          Float32 gain = 1.0;          Float32 gain = 1.0;
290    
291          OSStatus res = AudioQueueSetParameter (          res = AudioQueueSetParameter (
292              aqPlayerState.mQueue,              aqPlayerState.mQueue,
293              kAudioQueueParam_Volume,              kAudioQueueParam_Volume,
294              gain              gain
# Line 286  namespace LinuxSampler { Line 297  namespace LinuxSampler {
297          if(res) std::cerr << "AudioQueueSetParameter: Error " << res << std::endl;          if(res) std::cerr << "AudioQueueSetParameter: Error " << res << std::endl;
298    
299          atomic_set(&(aqPlayerState.mIsRunning), 1);          atomic_set(&(aqPlayerState.mIsRunning), 1);
300            FillBuffers();
301          if(!initialized) {          PrimeAudioQueue();
             res = AudioQueuePrime(aqPlayerState.mQueue, 0, NULL);  
             if(res) {  
                 String s = String("AudioQueuePrime: Error ") + ToString(res);  
                 throw Exception(s);  
             }  
         }  
302    
303          res = AudioQueueStart(aqPlayerState.mQueue, NULL);          res = AudioQueueStart(aqPlayerState.mQueue, NULL);
304          if(res) {          if(res) {
305              String s = String("AudioQueueStart: Error ") + ToString(res);              String s = String("AudioQueueStart: Error ") + ToString(res);
306              throw Exception(s);              throw Exception(s);
307          }          }
308        }
309    
310        void AudioOutputDeviceCoreAudio::DestroyAudioQueue() {
311            AudioQueueFlush(aqPlayerState.mQueue);
312            AudioQueueStop (aqPlayerState.mQueue, true);
313            AudioQueueDispose(aqPlayerState.mQueue, true);
314            aqPlayerState.mQueue = NULL;
315        }
316    
317        /**
318         * Entry point for the thread.
319         */
320        int AudioOutputDeviceCoreAudio::Main() {
321            dmsg(2,("CoreAudio thread started\n"));
322            OSStatus res;
323            std::cout<<"thread started ca\n";
324            if(aqPlayerState.mQueue == NULL) {
325                /*
326                 * Need to be run from this thread because of CFRunLoopGetCurrent()
327                 * which returns the CFRunLoop object for the current thread.
328                 */
329                CreateAndStartAudioQueue();
330            }
331    
332          destroyMutex.Lock();          destroyMutex.Lock();
333          do {          do {
# Line 316  namespace LinuxSampler { Line 344  namespace LinuxSampler {
344                      if(res) std::cerr << "AudioQueueStart: Error " << res << std::endl;                      if(res) std::cerr << "AudioQueueStart: Error " << res << std::endl;
345                  }                  }
346              }              }
347    
348                if(atomic_read(&restartQueue)) {
349                    DestroyAudioQueue();
350                    try { CreateAndStartAudioQueue(); }
351                    catch(Exception e) {
352                        destroyMutex.Unlock();
353                        throw e;
354                    }
355                    atomic_set(&restartQueue, 0);
356                    dmsg(1,("Audio queue restarted"));
357                }
358                            
359              CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.2, false);              CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.2, false);
360          } while (atomic_read(&(aqPlayerState.mIsRunning)));          } while (atomic_read(&(aqPlayerState.mIsRunning)));
# Line 327  namespace LinuxSampler { Line 366  namespace LinuxSampler {
366      }      }
367    
368    
369    // *************** ParameterDevice ***************
370    // *
371    
372        AudioOutputDeviceCoreAudio::ParameterDevice::ParameterDevice() : DeviceCreationParameterString() {
373            InitWithDefault(); // use default device
374        }
375    
376        AudioOutputDeviceCoreAudio::ParameterDevice::ParameterDevice(String s)
377                throw (Exception) : DeviceCreationParameterString(s) {
378        }
379    
380        String AudioOutputDeviceCoreAudio::ParameterDevice::Description() {
381            return "Output device to be used";
382        }
383    
384        bool AudioOutputDeviceCoreAudio::ParameterDevice::Fix() {
385            return true;
386        }
387    
388        bool AudioOutputDeviceCoreAudio::ParameterDevice::Mandatory() {
389            return false;
390        }
391    
392        std::map<String,DeviceCreationParameter*>
393        AudioOutputDeviceCoreAudio::ParameterDevice::DependsAsParameters() {
394            return std::map<String,DeviceCreationParameter*>(); // no dependencies
395        }
396    
397        optional<String>
398        AudioOutputDeviceCoreAudio::ParameterDevice::DefaultAsString(std::map<String,String> Parameters) {
399            CAAudioDeviceListModel* devs = CAAudioDeviceListModel::GetModel();
400            if (devs->GetOutputDeviceCount() < 1) {
401                throw Exception("AudioOutputDeviceCoreAudio: Can't find any output device");
402            }
403            UInt32 idx = devs->GetOutputDeviceIndex(devs->GetDefaultOutputDeviceID());
404            return CreateDeviceName(idx);
405        }
406    
407        std::vector<String>
408        AudioOutputDeviceCoreAudio::ParameterDevice::PossibilitiesAsString(std::map<String,String> Parameters) {
409            std::vector<String> deviceNames;
410    
411            CAAudioDeviceListModel* devs = CAAudioDeviceListModel::GetModel();
412            for(int i = 0; i < devs->GetOutputDeviceCount(); i++) {
413                if(devs->GetOutputDevice(i).GetChannelNumber() < 1) continue;
414    
415                deviceNames.push_back(CreateDeviceName(i));
416            }
417    
418            return deviceNames;
419        }
420    
421        String AudioOutputDeviceCoreAudio::ParameterDevice::CreateDeviceName(int devIndex) {
422            CAAudioDeviceListModel* devs = CAAudioDeviceListModel::GetModel();
423            // Note that the space " " is used as delimiter to obtain the
424            // device index. See GetDeviceIndex()
425            return ToString(devIndex + 1) + " " + devs->GetOutputDevice(devIndex).GetName();
426        }
427    
428        void AudioOutputDeviceCoreAudio::ParameterDevice::OnSetValue(String s) throw (Exception) {
429            // not posssible, as parameter is fix
430        }
431    
432        String AudioOutputDeviceCoreAudio::ParameterDevice::Name() {
433            return "DEVICE";
434        }
435    
436        int AudioOutputDeviceCoreAudio::ParameterDevice::GetDeviceIndex() {
437            String s = ValueAsString();
438            if(s.empty()) return -1;
439            int n = s.find(' ');
440            s = s.substr(0, n);
441            return ToInt(s) - 1;
442        }
443    
444  // *************** ParameterSampleRate ***************  // *************** ParameterSampleRate ***************
445  // *  // *
446    
# Line 340  namespace LinuxSampler { Line 454  namespace LinuxSampler {
454                    
455      }      }
456    
457        std::map<String,DeviceCreationParameter*>
458        AudioOutputDeviceCoreAudio::ParameterSampleRate::DependsAsParameters() {
459            static ParameterDevice device;
460            std::map<String,DeviceCreationParameter*> dependencies;
461            dependencies[device.Name()] = &device;
462            return dependencies;
463        }
464    
465      optional<int>      optional<int>
466      AudioOutputDeviceCoreAudio::ParameterSampleRate::DefaultAsInt(std::map<String,String> Parameters) {      AudioOutputDeviceCoreAudio::ParameterSampleRate::DefaultAsInt(std::map<String,String> Parameters) {
467          dmsg(2,("AudioOutputDeviceCoreAudio::ParameterSampleRate::DefaultAsInt()\n"));          dmsg(2,("AudioOutputDeviceCoreAudio::ParameterSampleRate::DefaultAsInt()\n"));
468          return GetDeviceInfo()->uiSamplerate;          ParameterDevice dev(Parameters["DEVICE"]);
469            int samplerate = 44100;
470    
471            try {
472                int idx = dev.GetDeviceIndex();
473    
474                CAAudioDeviceListModel* devs = CAAudioDeviceListModel::GetModel();
475                samplerate = devs->GetOutputDevice(idx).GetDefaultSamplerate();
476            } catch(Exception e) { }
477    
478            return samplerate;
479        }
480    
481        std::vector<int>
482        AudioOutputDeviceCoreAudio::ParameterSampleRate::PossibilitiesAsInt(std::map<String,String> Parameters) {
483            ParameterDevice dev(Parameters["DEVICE"]);
484            std::vector<int> srates;
485    
486            try {
487                int idx = dev.GetDeviceIndex();
488                CAAudioDeviceListModel* devs = CAAudioDeviceListModel::GetModel();
489                srates = devs->GetOutputDevice(idx).GetNominalSamplerates();
490            } catch(Exception x) { }
491    
492            return srates;
493      }      }
494    
495    
# Line 363  namespace LinuxSampler { Line 509  namespace LinuxSampler {
509      optional<int>      optional<int>
510      AudioOutputDeviceCoreAudio::ParameterChannels::DefaultAsInt(std::map<String,String> Parameters) {      AudioOutputDeviceCoreAudio::ParameterChannels::DefaultAsInt(std::map<String,String> Parameters) {
511          dmsg(2,("AudioOutputDeviceCoreAudio::ParameterChannels::DefaultAsInt()\n"));          dmsg(2,("AudioOutputDeviceCoreAudio::ParameterChannels::DefaultAsInt()\n"));
512          return GetDeviceInfo()->uiChannelNumber;          ParameterDevice dev(Parameters["DEVICE"]);
513            int chns = 2;
514    
515            try {
516                int idx = dev.GetDeviceIndex();
517                CAAudioDeviceListModel* devs = CAAudioDeviceListModel::GetModel();
518                chns = devs->GetOutputDevice(idx).GetChannelNumber();
519            } catch(Exception e) { }
520    
521            return chns;
522        }
523    
524        std::vector<int>
525        AudioOutputDeviceCoreAudio::ParameterChannels::PossibilitiesAsInt(std::map<String,String> Parameters) {
526            ParameterDevice dev(Parameters["DEVICE"]);
527            std::vector<int> chns;
528    
529            try {
530                int idx = dev.GetDeviceIndex();
531                CAAudioDeviceListModel* devs = CAAudioDeviceListModel::GetModel();
532                for(int i = 1; i <= devs->GetOutputDevice(idx).GetChannelNumber(); i++) {
533                    chns.push_back(i);
534                }
535            } catch(Exception x) { }
536    
537            return chns;
538      }      }
539    
540  // *************** ParameterBuffers ***************  // *************** ParameterBuffers ***************

Legend:
Removed from v.1831  
changed lines
  Added in v.1832

  ViewVC Help
Powered by ViewVC