MythTV  0.26-pre
audiooutputca.cpp
Go to the documentation of this file.
00001 /*****************************************************************************
00002  * = NAME
00003  * audiooutputca.cpp
00004  *
00005  * = DESCRIPTION
00006  * Core Audio glue for Mac OS X.
00007  *
00008  * = REVISION
00009  * $Id$
00010  *
00011  * = AUTHORS
00012  * Jeremiah Morris, Andrew Kimpton, Nigel Pearson, Jean-Yves Avenard
00013  *****************************************************************************/
00014 
00015 #include <CoreServices/CoreServices.h>
00016 #include <CoreAudio/CoreAudio.h>
00017 #include <AudioUnit/AudioUnit.h>
00018 #include <AudioToolbox/AudioFormat.h>
00019 
00020 using namespace std;
00021 
00022 #include "mythcorecontext.h"
00023 #include "audiooutputca.h"
00024 #include "config.h"
00025 #include "SoundTouch.h"
00026 
00027 #define LOC QString("CoreAudio: ")
00028 
00029 #define CHANNELS_MIN 1
00030 #define CHANNELS_MAX 8
00031 
00032 #define OSS_STATUS(x) UInt32ToFourCC((UInt32*)&x)
00033 char* UInt32ToFourCC(UInt32* pVal)
00034 {
00035     UInt32 inVal = *pVal;
00036     char* pIn = (char*)&inVal;
00037     static char fourCC[5];
00038     fourCC[4] = 0;
00039     fourCC[3] = pIn[0];
00040     fourCC[2] = pIn[1];
00041     fourCC[1] = pIn[2];
00042     fourCC[0] = pIn[3];
00043     return fourCC;
00044 }
00045 
00046 QString StreamDescriptionToString(AudioStreamBasicDescription desc)
00047 {
00048     UInt32 formatId = desc.mFormatID;
00049     char* fourCC = UInt32ToFourCC(&formatId);
00050     QString str;
00051 
00052     switch (desc.mFormatID)
00053     {
00054         case kAudioFormatLinearPCM:
00055             str = QString("[%1] %2%3 Channel %4-bit %5 %6 (%7Hz)")
00056             .arg(fourCC)
00057             .arg((desc.mFormatFlags & kAudioFormatFlagIsNonMixable) ? "" : "Mixable ")
00058             .arg(desc.mChannelsPerFrame)
00059             .arg(desc.mBitsPerChannel)
00060             .arg((desc.mFormatFlags & kAudioFormatFlagIsFloat) ? "Floating Point" : "Signed Integer")
00061             .arg((desc.mFormatFlags & kAudioFormatFlagIsBigEndian) ? "BE" : "LE")
00062             .arg((UInt32)desc.mSampleRate);
00063             break;
00064         case kAudioFormatAC3:
00065             str = QString("[%1] AC-3/DTS (%2Hz)")
00066             .arg(fourCC)
00067             .arg((UInt32)desc.mSampleRate);
00068             break;
00069         case kAudioFormat60958AC3:
00070             str = QString("[%1] AC-3/DTS for S/PDIF %2 (%3Hz)")
00071             .arg(fourCC)
00072             .arg((desc.mFormatFlags & kAudioFormatFlagIsBigEndian) ? "BE" : "LE")
00073             .arg((UInt32)desc.mSampleRate);
00074 
00075             break;
00076         default:
00077             str = QString("[%1]").arg(fourCC);
00078             break;
00079     }
00080     return str;
00081 }
00082 
00087 class CoreAudioData {
00088 public:
00089     CoreAudioData(AudioOutputCA *parent);
00090     CoreAudioData(AudioOutputCA *parent, AudioDeviceID deviceID);
00091     CoreAudioData(AudioOutputCA *parent, QString deviceName);
00092     void Initialise();
00093 
00094     AudioDeviceID GetDefaultOutputDevice();
00095     int  GetTotalOutputChannels();
00096     QString *GetName();
00097     AudioDeviceID GetDeviceWithName(QString deviceName);
00098 
00099     bool OpenDevice();
00100     int  OpenAnalog();
00101     void CloseAnalog();
00102     bool OpenSPDIF ();
00103     void CloseSPDIF();
00104 
00105     void SetAutoHogMode(bool enable);
00106     bool GetAutoHogMode();
00107     pid_t GetHogStatus();
00108     bool SetHogStatus(bool hog);
00109     bool SetMixingSupport(bool mix);
00110     bool GetMixingSupport();
00111 
00112     bool FindAC3Stream();
00113     void ResetAudioDevices();
00114     void ResetStream(AudioStreamID s);
00115     int *RatesList(AudioDeviceID d);
00116     bool *ChannelsList(AudioDeviceID d, bool passthru);
00117 
00118     // Helpers for iterating. Returns a malloc'd array
00119     AudioStreamID               *StreamsList(AudioDeviceID d);
00120     AudioStreamBasicDescription *FormatsList(AudioStreamID s);
00121 
00122     int  AudioStreamChangeFormat(AudioStreamID               s,
00123                                  AudioStreamBasicDescription format);
00124 
00125     // TODO: Convert these to macros!
00126     void  Debug(QString msg)
00127     {   LOG(VB_AUDIO, LOG_INFO,      "CoreAudioData::" + msg);   }
00128 
00129     void  Error(QString msg)
00130     {    LOG(VB_GENERAL, LOG_ERR, "CoreAudioData Error:" + msg);   }
00131 
00132     void  Warn (QString msg)
00133     {    LOG(VB_GENERAL, LOG_WARNING, "CoreAudioData Warning:" + msg);   }
00134 
00135     AudioOutputCA  *mCA;    // We could subclass, but this ends up tidier
00136 
00137     // Analog output specific
00138     AudioUnit      mOutputUnit;
00139 
00140     // SPDIF mode specific
00141     bool           mDigitalInUse;   // Is the digital (SPDIF) output in use?
00142     pid_t          mHog;
00143     int            mMixerRestore;
00144     AudioDeviceID  mDeviceID;
00145     AudioStreamID  mStreamID;       // StreamID that has a cac3 streamformat
00146     int            mStreamIndex;    // Index of mStreamID in an AudioBufferList
00147     UInt32         mBytesPerPacket;
00148     AudioStreamBasicDescription
00149     mFormatOrig,     // The original format the stream
00150     mFormatNew;      // The format we changed the stream to
00151     bool           mRevertFormat;   // Do we need to revert the stream format?
00152     bool           mIoProc;
00153     bool           mInitialized;
00154     bool           mStarted;
00155     bool           mWasDigital;
00156 };
00157 
00158 // These callbacks communicate with Core Audio.
00159 static OSStatus RenderCallbackAnalog(void                       *inRefCon,
00160                                      AudioUnitRenderActionFlags *ioActionFlags,
00161                                      const AudioTimeStamp       *inTimeStamp,
00162                                      UInt32                     inBusNumber,
00163                                      UInt32                     inNumberFrames,
00164                                      AudioBufferList            *ioData);
00165 static OSStatus RenderCallbackSPDIF(AudioDeviceID        inDevice,
00166                                     const AudioTimeStamp *inNow,
00167                                     const void           *inInputData,
00168                                     const AudioTimeStamp *inInputTime,
00169                                     AudioBufferList      *outOutputData,
00170                                     const AudioTimeStamp *inOutputTime,
00171                                     void                 *threadGlobals);
00172 
00177 AudioOutputCA::AudioOutputCA(const AudioSettings &settings) :
00178 AudioOutputBase(settings)
00179 {
00180     main_device.remove(0, 10);
00181     VBAUDIO(QString("AudioOutputCA::AudioOutputCA searching %1").arg(main_device));
00182     d = new CoreAudioData(this, main_device);
00183 
00184     InitSettings(settings);
00185     if (settings.init)
00186         Reconfigure(settings);
00187 }
00188 
00189 AudioOutputCA::~AudioOutputCA()
00190 {
00191     KillAudio();
00192 
00193     delete d;
00194 }
00195 
00196 AudioOutputSettings* AudioOutputCA::GetOutputSettings(bool digital)
00197 {
00198     AudioOutputSettings *settings = new AudioOutputSettings();
00199 
00200     // Seek hardware sample rate available
00201     int rate;
00202     int *rates = d->RatesList(d->mDeviceID);
00203 
00204     if (rates == NULL)
00205     {
00206         // Error retrieving rates, assume 48kHz
00207         settings->AddSupportedRate(48000);
00208     }
00209     else
00210     {
00211         while ((rate = settings->GetNextRate()))
00212         {
00213                         int *p_rates = rates;
00214                         while (*p_rates > 0)
00215                         {
00216                                 if (*p_rates == rate)
00217                                 {
00218                                         settings->AddSupportedRate(*p_rates);
00219                                 }
00220                 p_rates++;
00221             }
00222         }
00223         free(rates);
00224     }
00225 
00226     // Supported format: 16 bits audio or float
00227     settings->AddSupportedFormat(FORMAT_S16);
00228     settings->AddSupportedFormat(FORMAT_FLT);
00229 
00230     bool *channels = d->ChannelsList(d->mDeviceID, digital);
00231     if (channels == NULL)
00232     {
00233         // Error retrieving list of supported channels, assume stereo only
00234         settings->AddSupportedChannels(2);
00235     }
00236     else
00237     {
00238         for (int i = CHANNELS_MIN; i <= CHANNELS_MAX; i++)
00239         {
00240             if (channels[i])
00241             {
00242                 Debug(QString("Support %1 channels").arg(i));
00243                 // In case 8 channels are supported but not 6, fake 6
00244                 if (i == 8 && !channels[6])
00245                     settings->AddSupportedChannels(6);
00246                 settings->AddSupportedChannels(i);
00247             }
00248         }
00249         free(channels);
00250     }
00251 
00252     if (d->FindAC3Stream())
00253     {
00254         settings->setPassthrough(1); // yes passthrough
00255     }
00256     return settings;
00257 }
00258 
00259 bool AudioOutputCA::OpenDevice()
00260 {
00261     bool deviceOpened = false;
00262 
00263     if (d->mWasDigital) 
00264     {
00265     }
00266     Debug("OpenDevice: Entering");
00267     if (passthru || enc)
00268     {
00269         Debug("OpenDevice() Trying Digital.");
00270         if (!(deviceOpened = d->OpenSPDIF()))
00271             d->CloseSPDIF();
00272     }
00273 
00274     if (!deviceOpened)
00275     {
00276         Debug("OpenDevice() Trying Analog.");
00277         int result = -1;
00278         //for (int i=0; result < 0 && i < 10; i++)
00279         {
00280             result = d->OpenAnalog();
00281             Debug(QString("OpenDevice: OpenAnalog = %1").arg(result));
00282             if (result < 0)
00283             {
00284                 d->CloseAnalog();
00285                 usleep(1000 * 1000);
00286             }
00287         }
00288         deviceOpened = (result > 0);
00289     }
00290 
00291     if (!deviceOpened)
00292     {
00293         Error("Couldn't open any audio device!");
00294         d->CloseAnalog();
00295         return false;
00296     }
00297 
00298     if (internal_vol && set_initial_vol)
00299     {
00300         QString controlLabel = gCoreContext->GetSetting("MixerControl", "PCM");
00301         controlLabel += "MixerVolume";
00302         SetCurrentVolume(gCoreContext->GetNumSetting(controlLabel, 80));
00303     }
00304 
00305     return true;
00306 }
00307 
00308 void AudioOutputCA::CloseDevice()
00309 {
00310     VBAUDIO(QString("CloseDevice [%1]: Entering")
00311             .arg(d->mDigitalInUse ? "SPDIF" : "Analog"));
00312     if (d->mDigitalInUse)
00313         d->CloseSPDIF();
00314     else
00315         d->CloseAnalog();
00316 }
00317 
00318 template <class AudioDataType>
00319 static inline void _ReorderSmpteToCA(AudioDataType *buf, uint frames)
00320 {
00321     AudioDataType tmpLS, tmpRS, tmpRLs, tmpRRs, *buf2;
00322     for (uint i = 0; i < frames; i++)
00323     {
00324         buf = buf2 = buf + 4;
00325         tmpRLs = *buf++;
00326         tmpRRs = *buf++;
00327         tmpLS = *buf++;
00328         tmpRS = *buf++;
00329 
00330         *buf2++ = tmpLS;
00331         *buf2++ = tmpRS;
00332         *buf2++ = tmpRLs;
00333         *buf2++ = tmpRRs;
00334     }
00335 }
00336 
00337 static inline void ReorderSmpteToCA(void *buf, uint frames, AudioFormat format)
00338 {
00339     switch(AudioOutputSettings::FormatToBits(format))
00340     {
00341         case  8: _ReorderSmpteToCA((uchar *)buf, frames); break;
00342         case 16: _ReorderSmpteToCA((short *)buf, frames); break;
00343         default: _ReorderSmpteToCA((int   *)buf, frames); break;
00344     }
00345 }
00346 
00348 bool AudioOutputCA::RenderAudio(unsigned char *aubuf,
00349                                 int size, unsigned long long timestamp)
00350 {
00351     if (pauseaudio || killaudio)
00352     {
00353         actually_paused = true;
00354         return false;
00355     }
00356 
00357     /* This callback is called when the sound system requests
00358      data.  We don't want to block here, because that would
00359      just cause dropouts anyway, so we always return whatever
00360      data is available.  If we haven't received enough, either
00361      because we've finished playing or we have a buffer
00362      underrun, we play silence to fill the unused space.  */
00363 
00364     int written_size = GetAudioData(aubuf, size, false);
00365     if (written_size && (size > written_size))
00366     {
00367         // play silence on buffer underrun
00368         memset(aubuf + written_size, 0, size - written_size);
00369     }
00370 
00371     //Audio received is in SMPTE channel order, reorder to CA unless passthru
00372     if (!passthru && channels == 8)
00373     {
00374         ReorderSmpteToCA(aubuf, size / output_bytes_per_frame, output_format);
00375     }
00376 
00377     /* update audiotime (bufferedBytes is read by GetBufferedOnSoundcard) */
00378     UInt64 nanos = AudioConvertHostTimeToNanos(timestamp -
00379                                                AudioGetCurrentHostTime());
00380     bufferedBytes = (int)((nanos / 1000000000.0) *    // secs
00381                           (effdsp / 100.0) *          // frames/sec
00382                           output_bytes_per_frame);    // bytes/frame
00383 
00384     return (written_size > 0);
00385 }
00386 
00387 void AudioOutputCA::WriteAudio(unsigned char *aubuf, int size)
00388 {
00389     (void)aubuf;
00390     (void)size;
00391     return;     // unneeded and unused in CA
00392 }
00393 
00394 int AudioOutputCA::GetBufferedOnSoundcard(void) const
00395 {
00396     return bufferedBytes;
00397 }
00398 
00402 int64_t AudioOutputCA::GetAudiotime(void)
00403 {
00404     int audbuf_timecode = GetBaseAudBufTimeCode();
00405 
00406     if (!audbuf_timecode)
00407         return 0;
00408 
00409     int totalbuffer = audioready() + GetBufferedOnSoundcard();
00410 
00411     return audbuf_timecode - (int)(totalbuffer * 100000.0 /
00412                                    (output_bytes_per_frame *
00413                                     effdsp * stretchfactor));
00414 }
00415 
00416 /* This callback provides converted audio data to the default output device. */
00417 OSStatus RenderCallbackAnalog(void                       *inRefCon,
00418                               AudioUnitRenderActionFlags *ioActionFlags,
00419                               const AudioTimeStamp       *inTimeStamp,
00420                               UInt32                     inBusNumber,
00421                               UInt32                     inNumberFrames,
00422                               AudioBufferList            *ioData)
00423 {
00424     (void)inBusNumber;
00425     (void)inNumberFrames;
00426 
00427     AudioOutputCA *inst = (static_cast<CoreAudioData *>(inRefCon))->mCA;
00428 
00429     if (!inst->RenderAudio((unsigned char *)(ioData->mBuffers[0].mData),
00430                            ioData->mBuffers[0].mDataByteSize,
00431                            inTimeStamp->mHostTime))
00432     {
00433         // play silence if RenderAudio returns false
00434         memset(ioData->mBuffers[0].mData, 0, ioData->mBuffers[0].mDataByteSize);
00435         *ioActionFlags = kAudioUnitRenderAction_OutputIsSilence;
00436     }
00437     return noErr;
00438 }
00439 
00440 int AudioOutputCA::GetVolumeChannel(int channel) const
00441 {
00442     // FIXME: this only returns global volume
00443     (void)channel;
00444     Float32 volume;
00445 
00446     if (!AudioUnitGetParameter(d->mOutputUnit,
00447                                kHALOutputParam_Volume,
00448                                kAudioUnitScope_Global, 0, &volume))
00449         return (int)lroundf(volume * 100.0f);
00450 
00451     return 0;    // error case
00452 }
00453 
00454 void AudioOutputCA::SetVolumeChannel(int channel, int volume)
00455 {
00456     // FIXME: this only sets global volume
00457     (void)channel;
00458     AudioUnitSetParameter(d->mOutputUnit, kHALOutputParam_Volume,
00459                           kAudioUnitScope_Global, 0, (volume * 0.01f), 0);
00460 }
00461 
00462 // IOProc style callback for SPDIF audio output
00463 static OSStatus RenderCallbackSPDIF(AudioDeviceID        inDevice,
00464                                     const AudioTimeStamp *inNow,
00465                                     const void           *inInputData,
00466                                     const AudioTimeStamp *inInputTime,
00467                                     AudioBufferList      *outOutputData,
00468                                     const AudioTimeStamp *inOutputTime,
00469                                     void                 *inRefCon)
00470 {
00471     CoreAudioData    *d = static_cast<CoreAudioData *>(inRefCon);
00472     AudioOutputCA    *a = d->mCA;
00473     int           index = d->mStreamIndex;
00474 
00475     (void)inDevice;     // unused
00476     (void)inNow;        // unused
00477     (void)inInputData;  // unused
00478     (void)inInputTime;  // unused
00479 
00480     /*
00481      * HACK: No idea why this would be the case, but after the second run, we get
00482      * incorrect value
00483      */
00484     if (d->mBytesPerPacket > 0 &&
00485         outOutputData->mBuffers[index].mDataByteSize > d->mBytesPerPacket)
00486     {
00487         outOutputData->mBuffers[index].mDataByteSize = d->mBytesPerPacket;
00488     }
00489     if (!a->RenderAudio((unsigned char *)(outOutputData->mBuffers[index].mData),
00490                         outOutputData->mBuffers[index].mDataByteSize,
00491                         inOutputTime->mHostTime))
00492     {
00493         // play silence if RenderAudio returns false
00494         memset(outOutputData->mBuffers[index].mData, 0,
00495               outOutputData->mBuffers[index].mDataByteSize);
00496     }
00497     return noErr;
00498 }
00499 
00500 void CoreAudioData::Initialise()
00501 {
00502     // Initialise private data
00503     mOutputUnit     = NULL;
00504     mDeviceID       = 0;
00505     mDigitalInUse   = false;
00506     mRevertFormat   = false;
00507     mHog            = -1;
00508     mMixerRestore   = -1;
00509     mStreamIndex    = -1;
00510     mIoProc         = false;
00511     mInitialized    = false;
00512     mStarted        = false;
00513     mBytesPerPacket = -1;
00514     mWasDigital     = false;
00515 }
00516 
00517 CoreAudioData::CoreAudioData(AudioOutputCA *parent) : mCA(parent)
00518 {
00519     Initialise();
00520     // Reset all the devices to a default 'non-hog' and mixable format.
00521     // If we don't do this we may be unable to find the Default Output device.
00522     // (e.g. if we crashed last time leaving it stuck in AC-3 mode)
00523     ResetAudioDevices();
00524 
00525     mDeviceID = GetDefaultOutputDevice();
00526 }
00527 
00528 CoreAudioData::CoreAudioData(AudioOutputCA *parent, AudioDeviceID deviceID) :
00529     mCA(parent)
00530 {
00531     Initialise();
00532     ResetAudioDevices();
00533     mDeviceID = deviceID;
00534 }
00535 
00536 CoreAudioData::CoreAudioData(AudioOutputCA *parent, QString deviceName) :
00537     mCA(parent)
00538 {
00539     Initialise();
00540     ResetAudioDevices();
00541     mDeviceID = GetDeviceWithName(deviceName);
00542     if (!mDeviceID)
00543     {
00544         // Didn't find specified device, use default one
00545         mDeviceID = GetDefaultOutputDevice();
00546         if (deviceName != "Default Output Device")
00547         {
00548             Warn(QString("CoreAudioData: \"%1\" not found, using default device %2.")
00549                  .arg(deviceName).arg(mDeviceID));
00550         }
00551     }
00552     Debug(QString("CoreAudioData: device number is %1")
00553           .arg(mDeviceID));
00554 }
00555 
00556 AudioDeviceID CoreAudioData::GetDeviceWithName(QString deviceName)
00557 {
00558     UInt32 size = 0;
00559     AudioDeviceID deviceID = 0;
00560 
00561     AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &size, NULL);
00562     UInt32 deviceCount = size / sizeof(AudioDeviceID);
00563     AudioDeviceID* pDevices = new AudioDeviceID[deviceCount];
00564 
00565     OSStatus err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &size, pDevices);
00566     if (err)
00567     {
00568         Warn(QString("GetDeviceWithName: Unable to retrieve the list of available devices. "
00569                      "Error [%1]")
00570              .arg(err));
00571     }
00572     else
00573     {
00574         for (UInt32 dev = 0; dev < deviceCount; dev++)
00575         {
00576             CoreAudioData device(NULL, pDevices[dev]);
00577             if (device.GetTotalOutputChannels() == 0)
00578                 continue;
00579             QString *name = device.GetName();
00580             if (name && name == deviceName)
00581             {
00582                 Debug(QString("GetDeviceWithName: Found: %1").arg(*name));
00583                 deviceID = pDevices[dev];
00584                 delete name;
00585             }
00586             if (deviceID)
00587                 break;
00588         }
00589     }
00590     delete[] pDevices;
00591     return deviceID;
00592 }
00593 
00594 AudioDeviceID CoreAudioData::GetDefaultOutputDevice()
00595 {
00596     UInt32        paramSize;
00597     OSStatus      err;
00598     AudioDeviceID deviceId = 0;
00599 
00600     // Find the ID of the default Device
00601     paramSize = sizeof(deviceId);
00602     err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice,
00603                                    &paramSize, &deviceId);
00604     if (err == noErr)
00605         Debug(QString("GetDefaultOutputDevice: default device ID = %1").arg(deviceId));
00606     else
00607     {
00608         Warn(QString("GetDefaultOutputDevice: could not get default audio device: [%1]")
00609              .arg(OSS_STATUS(err)));
00610         deviceId = 0;
00611     }
00612     return deviceId;
00613 }
00614 
00615 int CoreAudioData::GetTotalOutputChannels()
00616 {
00617     if (!mDeviceID)
00618         return 0;
00619     UInt32 channels = 0;
00620     UInt32 size = 0;
00621     AudioDeviceGetPropertyInfo(mDeviceID, 0, false,
00622                                kAudioDevicePropertyStreamConfiguration,
00623                                &size, NULL);
00624     AudioBufferList *pList = (AudioBufferList *)malloc(size);
00625     OSStatus err = AudioDeviceGetProperty(mDeviceID, 0, false,
00626                                           kAudioDevicePropertyStreamConfiguration,
00627                                           &size, pList); 
00628     if (!err)
00629     {
00630         for (UInt32 buffer = 0; buffer < pList->mNumberBuffers; buffer++)
00631             channels += pList->mBuffers[buffer].mNumberChannels;
00632     }
00633     else
00634     {
00635         Warn(QString("GetTotalOutputChannels: Unable to get "
00636                      "total device output channels - id: %1 Error = [%2]")
00637              .arg(mDeviceID)
00638              .arg(err));
00639     }
00640     Debug(QString("GetTotalOutputChannels: Found %1 channels in %2 buffers")
00641           .arg(channels).arg(pList->mNumberBuffers));
00642     free(pList);
00643     return channels;
00644 }
00645 
00646 QString *CoreAudioData::GetName()
00647 {
00648     if (!mDeviceID)
00649         return NULL;
00650     UInt32 propertySize;
00651     AudioObjectPropertyAddress propertyAddress;
00652 
00653     CFStringRef name;
00654     propertySize = sizeof(CFStringRef);
00655     propertyAddress.mSelector = kAudioObjectPropertyName;
00656     propertyAddress.mScope = kAudioObjectPropertyScopeGlobal;
00657     propertyAddress.mElement = kAudioObjectPropertyElementMaster;
00658     OSStatus err = AudioObjectGetPropertyData(mDeviceID, &propertyAddress,
00659                                               0, NULL, &propertySize, &name);
00660     if (err)
00661     {
00662         Error(QString("AudioObjectGetPropertyData for kAudioObjectPropertyName error: [%1]")
00663               .arg(err));
00664         return NULL;
00665     }
00666     char *cname = new char[CFStringGetLength(name) + 1];
00667     CFStringGetCString(name, cname, CFStringGetLength(name) + 1, kCFStringEncodingUTF8);
00668     QString *qname = new QString(cname);
00669     delete[] cname;
00670     return qname;
00671 }
00672 
00673 bool CoreAudioData::GetAutoHogMode()
00674 {
00675     UInt32 val = 0;
00676     UInt32 size = sizeof(val);
00677     OSStatus err = AudioHardwareGetProperty(kAudioHardwarePropertyHogModeIsAllowed,
00678                                             &size, &val);
00679     if (err)
00680     {
00681         Warn(QString("GetAutoHogMode: Unable to get auto 'hog' mode. Error = [%1]")
00682              .arg(err));
00683         return false;
00684     }
00685     return (val == 1);
00686 }
00687 
00688 void CoreAudioData::SetAutoHogMode(bool enable)
00689 {
00690     UInt32 val = enable ? 1 : 0;
00691     OSStatus err = AudioHardwareSetProperty(kAudioHardwarePropertyHogModeIsAllowed,
00692                                             sizeof(val), &val);
00693     if (err)
00694     {
00695         Warn(QString("SetAutoHogMode: Unable to set auto 'hog' mode. Error = [%1]")
00696              .arg(err));
00697     }
00698 }
00699 
00700 pid_t CoreAudioData::GetHogStatus()
00701 {
00702     OSStatus err;
00703     pid_t PID;
00704     UInt32 PIDsize = sizeof(PID);
00705 
00706     err = AudioDeviceGetProperty(mDeviceID, 0, FALSE,
00707                                  kAudioDevicePropertyHogMode,
00708                                  &PIDsize, &PID);
00709     if (err != noErr)
00710     {
00711         // This is not a fatal error.
00712         // Some drivers simply don't support this property
00713         Debug(QString("GetHogStatus: unable to check: [%1]")
00714               .arg(err));
00715         return -1;
00716     }
00717     return PID;
00718 }
00719 
00720 bool CoreAudioData::SetHogStatus(bool hog)
00721 {
00722     // According to Jeff Moore (Core Audio, Apple), Setting kAudioDevicePropertyHogMode
00723     // is a toggle and the only way to tell if you do get hog mode is to compare
00724     // the returned pid against getpid, if the match, you have hog mode, if not you don't.
00725     if (!mDeviceID)
00726         return false;
00727 
00728     if (hog)
00729     {
00730         if (mHog == -1) // Not already set
00731         {
00732             Debug(QString("SetHogStatus: Setting 'hog' status on device %1")
00733                   .arg(mDeviceID));
00734             OSStatus err = AudioDeviceSetProperty(mDeviceID, NULL, 0, false,
00735                                                   kAudioDevicePropertyHogMode,
00736                                                   sizeof(mHog), &mHog);
00737             if (err || mHog != getpid())
00738             {
00739                 Warn(QString("SetHogStatus: Unable to set 'hog' status. Error = [%1]")
00740                      .arg(OSS_STATUS(err)));
00741                 return false;
00742             }
00743             Debug(QString("SetHogStatus: Successfully set 'hog' status on device %1")
00744                   .arg(mDeviceID));
00745         }
00746     }
00747     else
00748     {
00749         if (mHog > -1) // Currently Set
00750         {
00751             Debug(QString("SetHogStatus: Releasing 'hog' status on device %1")
00752                   .arg(mDeviceID));
00753             pid_t hogPid = -1;
00754             OSStatus err = AudioDeviceSetProperty(mDeviceID, NULL, 0, false,
00755                                                   kAudioDevicePropertyHogMode,
00756                                                   sizeof(hogPid), &hogPid);
00757             if (err || hogPid == getpid())
00758             {
00759                 Warn(QString("SetHogStatus: Unable to release 'hog' status. Error = [%1]")
00760                      .arg(OSS_STATUS(err)));
00761                 return false;
00762             }
00763             mHog = hogPid; // Reset internal state
00764         }
00765     }
00766     return true;
00767 }
00768 
00769 bool CoreAudioData::SetMixingSupport(bool mix)
00770 {
00771     if (!mDeviceID)
00772         return false;
00773     int restore = -1;
00774     if (mMixerRestore == -1) // This is our first change to this setting. Store the original setting for restore
00775         restore = (GetMixingSupport() ? 1 : 0);
00776     UInt32 mixEnable = mix ? 1 : 0;
00777     Debug(QString("SetMixingSupport: %1abling mixing for device %2")
00778           .arg(mix ? "En" : "Dis")
00779           .arg(mDeviceID));
00780     OSStatus err = AudioDeviceSetProperty(mDeviceID, NULL, 0, false,
00781                                           kAudioDevicePropertySupportsMixing,
00782                                           sizeof(mixEnable), &mixEnable);
00783     if (err)
00784     {
00785         Warn(QString("SetMixingSupport: Unable to set MixingSupport to %1. Error = [%2]")
00786              .arg(mix ? "'On'" : "'Off'")
00787              .arg(OSS_STATUS(err)));
00788         return false;
00789     }
00790     if (mMixerRestore == -1) 
00791         mMixerRestore = restore;
00792     return true;
00793 }
00794 
00795 bool CoreAudioData::GetMixingSupport()
00796 {
00797     if (!mDeviceID)
00798         return false;
00799     UInt32 val = 0;
00800     UInt32 size = sizeof(val);
00801     OSStatus err = AudioDeviceGetProperty(mDeviceID, 0, false,
00802                                           kAudioDevicePropertySupportsMixing,
00803                                           &size, &val);
00804     if (err)
00805         return false;
00806     return (val > 0);
00807 }
00808 
00812 AudioStreamID *CoreAudioData::StreamsList(AudioDeviceID d)
00813 {
00814     OSStatus       err;
00815     UInt32         listSize;
00816     AudioStreamID  *list;
00817 
00818 
00819     err = AudioDeviceGetPropertyInfo(d, 0, FALSE,
00820                                      kAudioDevicePropertyStreams,
00821                                      &listSize, NULL);
00822     if (err != noErr)
00823     {
00824         Error(QString("StreamsList: could not get list size: [%1]")
00825               .arg(OSS_STATUS(err)));
00826         return NULL;
00827     }
00828 
00829     // Space for a terminating ID:
00830     listSize += sizeof(AudioStreamID);
00831     list      = (AudioStreamID *)malloc(listSize);
00832 
00833     if (list == NULL)
00834     {
00835         Error("StreamsList(): out of memory?");
00836         return NULL;
00837     }
00838 
00839     err = AudioDeviceGetProperty(d, 0, FALSE,
00840                                  kAudioDevicePropertyStreams,
00841                                  &listSize, list);
00842     if (err != noErr)
00843     {
00844         Error(QString("StreamsList: could not get list: [%1]")
00845               .arg(OSS_STATUS(err)));
00846         return NULL;
00847     }
00848     // Add a terminating ID:
00849     list[listSize/sizeof(AudioStreamID)] = kAudioHardwareBadStreamError;
00850 
00851     return list;
00852 }
00853 
00854 AudioStreamBasicDescription *CoreAudioData::FormatsList(AudioStreamID s)
00855 {
00856     OSStatus                     err;
00857     AudioStreamBasicDescription  *list;
00858     UInt32                       listSize;
00859     AudioDevicePropertyID        p;
00860 
00861 
00862     // This is deprecated for kAudioStreamPropertyAvailablePhysicalFormats,
00863     // but compiling on 10.3 requires the older constant
00864     p = kAudioStreamPropertyPhysicalFormats;
00865 
00866     // Retrieve all the stream formats supported by this output stream
00867     err = AudioStreamGetPropertyInfo(s, 0, p, &listSize, NULL);
00868     if (err != noErr)
00869     {
00870         Warn(QString("FormatsList(): couldn't get list size: [%1]")
00871              .arg(OSS_STATUS(err)));
00872         return NULL;
00873     }
00874 
00875     // Space for a terminating ID:
00876     listSize += sizeof(AudioStreamBasicDescription);
00877     list      = (AudioStreamBasicDescription *)malloc(listSize);
00878 
00879     if (list == NULL)
00880     {
00881         Error("FormatsList(): out of memory?");
00882         return NULL;
00883     }
00884 
00885     err = AudioStreamGetProperty(s, 0, p, &listSize, list);
00886     if (err != noErr)
00887     {
00888         Warn(QString("FormatsList: couldn't get list: [%1]")
00889              .arg(OSS_STATUS(err)));
00890         free(list);
00891         return NULL;
00892     }
00893 
00894     // Add a terminating ID:
00895     list[listSize/sizeof(AudioStreamBasicDescription)].mFormatID = 0;
00896 
00897     return list;
00898 }
00899 
00900 static UInt32   sNumberCommonSampleRates = 15;
00901 static Float64  sCommonSampleRates[] = {
00902     8000.0,   11025.0,  12000.0,
00903     16000.0,  22050.0,  24000.0,
00904     32000.0,  44100.0,  48000.0,
00905     64000.0,  88200.0,  96000.0,
00906     128000.0, 176400.0, 192000.0 };
00907 
00908 static bool IsRateCommon(Float64 inRate)
00909 {
00910     bool theAnswer = false;
00911     for(UInt32 i = 0; !theAnswer && (i < sNumberCommonSampleRates); i++)
00912     {
00913         theAnswer = inRate == sCommonSampleRates[i];
00914     }
00915     return theAnswer;
00916 }
00917 
00918 int *CoreAudioData::RatesList(AudioDeviceID d)
00919 {
00920     OSStatus                    err;
00921     AudioValueRange             *list;
00922     int                         *finallist;
00923     UInt32                      listSize;
00924     UInt32                      nbitems = 0;
00925 
00926     // retrieve size of rate list
00927     err = AudioDeviceGetPropertyInfo(d, 0, 0,
00928                                      kAudioDevicePropertyAvailableNominalSampleRates,
00929                                      &listSize, NULL);
00930     if (err != noErr)
00931     {
00932         Warn(QString("RatesList(): couldn't get data rate list size: [%1]")
00933              .arg(err));
00934         return NULL;
00935     }
00936 
00937     list      = (AudioValueRange *)malloc(listSize);
00938     if (list == NULL)
00939     {
00940         Error("RatesList(): out of memory?");
00941         return NULL;
00942     }
00943 
00944     err = AudioDeviceGetProperty(
00945         d, 0, 0, kAudioDevicePropertyAvailableNominalSampleRates,
00946         &listSize, list);
00947     if (err != noErr)
00948     {
00949         Warn(QString("RatesList(): couldn't get list: [%1]")
00950              .arg(err));
00951         free(list);
00952         return NULL;
00953     }
00954 
00955     finallist = (int *)malloc(((listSize / sizeof(AudioValueRange)) + 1)
00956                               * sizeof(int));
00957     if (finallist == NULL)
00958     {
00959         Error("RatesList(): out of memory?");
00960         free(list);
00961         return NULL;
00962     }
00963 
00964     // iterate through the ranges and add the minimum, maximum, and common rates in between
00965     UInt32 theFirstIndex = 0, theLastIndex = 0;
00966     for(UInt32 i = 0; i < listSize / sizeof(AudioValueRange); i++)
00967     {
00968         theFirstIndex = theLastIndex;
00969         // find the index of the first common rate greater than or equal to the minimum
00970         while((theFirstIndex < sNumberCommonSampleRates) &&  (sCommonSampleRates[theFirstIndex] < list[i].mMinimum))
00971             theFirstIndex++;
00972 
00973         if (theFirstIndex >= sNumberCommonSampleRates)
00974             break;
00975 
00976         theLastIndex = theFirstIndex;
00977         // find the index of the first common rate greater than or equal to the maximum
00978         while((theLastIndex < sNumberCommonSampleRates) && (sCommonSampleRates[theLastIndex] < list[i].mMaximum))
00979         {
00980             finallist[nbitems++] = sCommonSampleRates[theLastIndex];
00981             theLastIndex++;
00982         }
00983         if (IsRateCommon(list[i].mMinimum))
00984             finallist[nbitems++] = list[i].mMinimum;
00985         else if (IsRateCommon(list[i].mMaximum))
00986             finallist[nbitems++] = list[i].mMaximum;
00987     }
00988     free(list);
00989 
00990     // Add a terminating ID
00991     finallist[nbitems] = -1;
00992 
00993     return finallist;
00994 }
00995 
00996 bool *CoreAudioData::ChannelsList(AudioDeviceID d, bool passthru)
00997 {
00998     AudioStreamID               *streams;
00999     AudioStreamBasicDescription *formats;
01000     bool                        founddigital = false;
01001     bool                        *list;
01002 
01003     if ((list = (bool *)malloc((CHANNELS_MAX+1) * sizeof(bool))) == NULL)
01004         return NULL;
01005 
01006     memset(list, 0, (CHANNELS_MAX+1) * sizeof(bool));
01007 
01008     streams = StreamsList(mDeviceID);
01009     if (!streams)
01010     {
01011         free(list);
01012         return NULL;
01013     }
01014 
01015     if (passthru)
01016     {
01017         for (int i = 0; streams[i] != kAudioHardwareBadStreamError; i++)
01018         {
01019             formats = FormatsList(streams[i]);
01020             if (!formats)
01021                 continue;
01022 
01023             // Find a stream with a cac3 stream
01024             for (int j = 0; formats[j].mFormatID != 0; j++)
01025             {
01026                 if (formats[j].mFormatID == 'IAC3' ||
01027                     formats[j].mFormatID == kAudioFormat60958AC3)
01028                 {
01029                     list[formats[j].mChannelsPerFrame] = true;
01030                     founddigital = true;
01031                 }
01032             }
01033             free(formats);
01034         }
01035     }
01036 
01037     if (!founddigital)
01038     {
01039         for (int i = 0; streams[i] != kAudioHardwareBadStreamError; i++)
01040         {
01041             formats = FormatsList(streams[i]);
01042             if (!formats)
01043                 continue;
01044             for (int j = 0; formats[j].mFormatID != 0; j++)
01045                 if (formats[j].mChannelsPerFrame <= CHANNELS_MAX)
01046                     list[formats[j].mChannelsPerFrame] = true;
01047             free(formats);
01048         }
01049     }
01050     return list;
01051 }
01052 
01053 int CoreAudioData::OpenAnalog()
01054 {
01055     ComponentDescription         desc;
01056     AudioStreamBasicDescription  DeviceFormat;
01057     AudioChannelLayout          *layout;
01058     AudioChannelLayout           new_layout;
01059     AudioDeviceID                defaultDevice = GetDefaultOutputDevice();
01060 
01061     Debug("OpenAnalog: Entering");
01062 
01063     desc.componentType = kAudioUnitType_Output;
01064     if (defaultDevice == mDeviceID)
01065     {
01066         desc.componentSubType = kAudioUnitSubType_DefaultOutput;
01067     }
01068     else
01069     {
01070         desc.componentSubType = kAudioUnitSubType_HALOutput;
01071     }
01072     desc.componentManufacturer = kAudioUnitManufacturer_Apple;
01073     desc.componentFlags = 0;
01074     desc.componentFlagsMask = 0;
01075     mDigitalInUse = false;
01076 
01077     Component comp = FindNextComponent(NULL, &desc);
01078     if (comp == NULL)
01079     {
01080         Error("OpenAnalog: AudioComponentFindNext failed");
01081         return false;
01082     }
01083 
01084     OSErr err = OpenAComponent(comp, &mOutputUnit);
01085     if (err)
01086     {
01087         Error(QString("OpenAnalog: AudioComponentInstanceNew returned %1")
01088               .arg(err));
01089         return false;
01090     }
01091 
01092     // Check if we have IO
01093     UInt32 hasIO      = 0;
01094     UInt32 size_hasIO = sizeof(hasIO);
01095     err = AudioUnitGetProperty(mOutputUnit,
01096                                kAudioOutputUnitProperty_HasIO,
01097                                kAudioUnitScope_Output,
01098                                0,
01099                                &hasIO, &size_hasIO);
01100     Debug(QString("OpenAnalog: HasIO (output) = %1").arg(hasIO));
01101     if (!hasIO)
01102     {
01103         UInt32 enableIO = 1;
01104         err = AudioUnitSetProperty(mOutputUnit,
01105                                    kAudioOutputUnitProperty_EnableIO,
01106                                    kAudioUnitScope_Global,
01107                                    0,
01108                                    &enableIO, sizeof(enableIO));
01109         if (err)
01110         {
01111             Warn(QString("OpenAnalog: failed enabling IO: %1")
01112                  .arg(err));
01113         }
01114         hasIO = 0;
01115         err = AudioUnitGetProperty(mOutputUnit,
01116                                    kAudioOutputUnitProperty_HasIO,
01117                                    kAudioUnitScope_Output,
01118                                    0,
01119                                    &hasIO, &size_hasIO);
01120         Debug(QString("HasIO = %1").arg(hasIO));
01121     }
01122 
01123     /*
01124      * We shouldn't have to do this distinction, however for some unknown reasons
01125      * assigning device to AudioUnit fail when switching from SPDIF mode
01126      */
01127     if (defaultDevice != mDeviceID)
01128     {
01129         err = AudioUnitSetProperty(mOutputUnit,
01130                                    kAudioOutputUnitProperty_CurrentDevice,
01131                                    kAudioUnitScope_Global,
01132                                    0,
01133                                    &mDeviceID, sizeof(mDeviceID));
01134         if (err)
01135         { 
01136             Error(QString("OpenAnalog: Unable to set current device to %1. Error = %2")
01137                   .arg(mDeviceID)
01138                   .arg(err));
01139             return -1;
01140         }  
01141     }
01142     /* Get the current format */
01143     UInt32 param_size = sizeof(AudioStreamBasicDescription);
01144 
01145     err = AudioUnitGetProperty(mOutputUnit,
01146                                kAudioUnitProperty_StreamFormat,
01147                                kAudioUnitScope_Input,
01148                                0,
01149                                &DeviceFormat,
01150                                &param_size );
01151     if (err)
01152     {
01153         Warn(QString("OpenAnalog: Unable to retrieve current stream format: [%1]")
01154               .arg(err));
01155     }
01156     else
01157     {
01158         Debug(QString("OpenAnalog: current format is: %1")
01159               .arg(StreamDescriptionToString(DeviceFormat)));
01160     }
01161     /* Get the channel layout of the device side of the unit */
01162     err = AudioUnitGetPropertyInfo(mOutputUnit,
01163                                    kAudioDevicePropertyPreferredChannelLayout,
01164                                    kAudioUnitScope_Output,
01165                                    0,
01166                                    &param_size,
01167                                    NULL);
01168 
01169     if(!err)
01170     {
01171         layout = (AudioChannelLayout *) malloc(param_size);
01172 
01173         err = AudioUnitGetProperty(mOutputUnit,
01174                                    kAudioDevicePropertyPreferredChannelLayout,
01175                                    kAudioUnitScope_Output,
01176                                    0,
01177                                    layout,
01178                                    &param_size);
01179 
01180         /* We need to "fill out" the ChannelLayout, because there are multiple ways that it can be set */
01181         if(layout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap)
01182         {
01183             /* bitmap defined channellayout */
01184             err = AudioFormatGetProperty(kAudioFormatProperty_ChannelLayoutForBitmap,
01185                                          sizeof(UInt32), &layout->mChannelBitmap,
01186                                          &param_size,
01187                                          layout);
01188             if (err)
01189                 Warn("OpenAnalog: Can't retrieve current channel layout");
01190         }
01191         else if(layout->mChannelLayoutTag != kAudioChannelLayoutTag_UseChannelDescriptions )
01192         {
01193             /* layouttags defined channellayout */
01194             err = AudioFormatGetProperty(kAudioFormatProperty_ChannelLayoutForTag,
01195                                          sizeof(AudioChannelLayoutTag),
01196                                          &layout->mChannelLayoutTag,
01197                                          &param_size,
01198                                          layout);
01199             if (err)
01200                 Warn("OpenAnalog: Can't retrieve current channel layout");
01201         }
01202 
01203         Debug(QString("OpenAnalog: Layout of AUHAL has %1 channels")
01204               .arg(layout->mNumberChannelDescriptions));
01205 
01206         int channels_found = 0;
01207         for(UInt32 i = 0; i < layout->mNumberChannelDescriptions; i++)
01208         {
01209             Debug(QString("OpenAnalog: this is channel: %1")
01210                   .arg(layout->mChannelDescriptions[i].mChannelLabel));
01211 
01212             switch( layout->mChannelDescriptions[i].mChannelLabel)
01213             {
01214                 case kAudioChannelLabel_Left:
01215                 case kAudioChannelLabel_Right:
01216                 case kAudioChannelLabel_Center:
01217                 case kAudioChannelLabel_LFEScreen:
01218                 case kAudioChannelLabel_LeftSurround:
01219                 case kAudioChannelLabel_RightSurround:
01220                 case kAudioChannelLabel_RearSurroundLeft:
01221                 case kAudioChannelLabel_RearSurroundRight:
01222                 case kAudioChannelLabel_CenterSurround:
01223                     channels_found++;
01224                     break;
01225                 default:
01226                     Debug(QString("unrecognized channel form provided by driver: %1")
01227                           .arg(layout->mChannelDescriptions[i].mChannelLabel));
01228             }
01229         }
01230         if(channels_found == 0)
01231         {
01232             Warn("Audio device is not configured. "
01233                  "You should configure your speaker layout with "
01234                  "the \"Audio Midi Setup\" utility in /Applications/"
01235                  "Utilities.");
01236         }
01237         free(layout);
01238     }
01239     else
01240     {
01241         Warn("this driver does not support kAudioDevicePropertyPreferredChannelLayout.");
01242     }
01243 
01244     memset (&new_layout, 0, sizeof(new_layout));
01245     switch(mCA->channels)
01246     {
01247         case 1:
01248             new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_Mono;
01249             break;
01250         case 2:
01251             new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo;
01252             break;
01253         case 6:
01254             //  3F2-LFE        L   R   C    LFE  LS   RS
01255             new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_AudioUnit_5_1;
01256         case 8:
01257             // We need
01258             // 3F4-LFE        L   R   C    LFE  Rls  Rrs  LS   RS
01259             // but doesn't exist, so we'll swap channels later
01260             new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_MPEG_7_1_A; // L R C LFE Ls Rs Lc Rc
01261             break;
01262     }
01263     /* Set new_layout as the layout */
01264     err = AudioUnitSetProperty(mOutputUnit,
01265                                kAudioUnitProperty_AudioChannelLayout,
01266                                kAudioUnitScope_Input,
01267                                0,
01268                                &new_layout, sizeof(new_layout));
01269     if (err)
01270     {
01271         Warn(QString("OpenAnalog: couldn't set channels layout [%1]")
01272              .arg(err));
01273     }
01274 
01275     if(new_layout.mNumberChannelDescriptions > 0)
01276         free(new_layout.mChannelDescriptions);
01277 
01278     // Set up the audio output unit
01279     int formatFlags;
01280     switch (mCA->output_format)
01281     {
01282         case FORMAT_S16:
01283             formatFlags = kLinearPCMFormatFlagIsSignedInteger;
01284             break;
01285         case FORMAT_FLT:
01286             formatFlags = kLinearPCMFormatFlagIsFloat;
01287             break;
01288         default:
01289             formatFlags = kLinearPCMFormatFlagIsSignedInteger;
01290             break;
01291     }
01292 
01293     AudioStreamBasicDescription conv_in_desc;
01294     memset(&conv_in_desc, 0, sizeof(AudioStreamBasicDescription));
01295     conv_in_desc.mSampleRate       = mCA->samplerate;
01296     conv_in_desc.mFormatID         = kAudioFormatLinearPCM;
01297     conv_in_desc.mFormatFlags      = formatFlags |
01298         kAudioFormatFlagsNativeEndian |
01299         kLinearPCMFormatFlagIsPacked;
01300     conv_in_desc.mBytesPerPacket   = mCA->output_bytes_per_frame;
01301     // This seems inefficient, does it hurt if we increase this?
01302     conv_in_desc.mFramesPerPacket  = 1;
01303     conv_in_desc.mBytesPerFrame    = mCA->output_bytes_per_frame;
01304     conv_in_desc.mChannelsPerFrame = mCA->channels;
01305     conv_in_desc.mBitsPerChannel   =
01306         AudioOutputSettings::FormatToBits(mCA->output_format);
01307 
01308     /* Set AudioUnit input format */
01309     err = AudioUnitSetProperty(mOutputUnit,
01310                                kAudioUnitProperty_StreamFormat,
01311                                kAudioUnitScope_Input,
01312                                0,
01313                                &conv_in_desc,
01314                                sizeof(AudioStreamBasicDescription));
01315     if (err)
01316     {
01317         Error(QString("OpenAnalog: AudioUnitSetProperty returned [%1]")
01318               .arg(err));
01319         return false;
01320     }
01321     Debug(QString("OpenAnalog: set format as %1")
01322           .arg(StreamDescriptionToString(conv_in_desc)));
01323     /* Retrieve actual format */
01324     err = AudioUnitGetProperty(mOutputUnit,
01325                                kAudioUnitProperty_StreamFormat,
01326                                kAudioUnitScope_Input,
01327                                0,
01328                                &DeviceFormat,
01329                                &param_size);
01330 
01331     Debug(QString("OpenAnalog: the actual set AU format is %1")
01332           .arg(StreamDescriptionToString(DeviceFormat)));
01333 
01334     // Attach callback to default output
01335     AURenderCallbackStruct input;
01336     input.inputProc = RenderCallbackAnalog;
01337     input.inputProcRefCon = this;
01338 
01339     err = AudioUnitSetProperty(mOutputUnit,
01340                                kAudioUnitProperty_SetRenderCallback,
01341                                kAudioUnitScope_Input,
01342                                0, &input, sizeof(input));
01343     if (err)
01344     {
01345         Error(QString("OpenAnalog: AudioUnitSetProperty (callback) returned [%1]")
01346               .arg(err));
01347         return false;
01348     }
01349     mIoProc = true;
01350 
01351     // We're all set up - start the audio output unit
01352     ComponentResult res = AudioUnitInitialize(mOutputUnit);
01353     if (res)
01354     {
01355         Error(QString("OpenAnalog: AudioUnitInitialize error: [%1]")
01356               .arg(res));
01357         return false;
01358     }
01359     mInitialized = true;
01360 
01361     err = AudioOutputUnitStart(mOutputUnit);
01362     if (err)
01363     {
01364         Error(QString("OpenAnalog: AudioOutputUnitStart error: [%1]")
01365               .arg(err));
01366         return false;
01367     }
01368     mStarted = true;
01369     return true;
01370 }
01371 
01372 void CoreAudioData::CloseAnalog()
01373 {
01374     OSStatus err;
01375 
01376     Debug(QString("CloseAnalog: Entering: %1")
01377           .arg((long)mOutputUnit));
01378     if (mOutputUnit)
01379     {
01380         if (mStarted)
01381         {
01382             err = AudioOutputUnitStop(mOutputUnit);
01383             Debug(QString("CloseAnalog: AudioOutputUnitStop %1")
01384                   .arg(err));
01385         }
01386         if (mInitialized)
01387         {
01388             err = AudioUnitUninitialize(mOutputUnit);
01389             Debug(QString("CloseAnalog: AudioUnitUninitialize %1")
01390                   .arg(err));
01391         }
01392         err = CloseComponent(mOutputUnit);
01393         Debug(QString("CloseAnalog: CloseComponent %1")
01394               .arg(err));
01395         mOutputUnit = NULL;
01396     }
01397     mIoProc = false;
01398     mInitialized = false;
01399     mStarted = false;
01400     mWasDigital = false;
01401 }
01402 
01403 bool CoreAudioData::OpenSPDIF()
01404 {
01405     OSStatus       err;
01406     AudioStreamID  *streams;
01407     AudioStreamBasicDescription outputFormat = {0};
01408 
01409     Debug("OpenSPDIF: Entering");
01410 
01411     streams = StreamsList(mDeviceID);
01412     if (!streams)
01413     {
01414         Warn("OpenSPDIF: Couldn't retrieve list of streams");
01415         return false;
01416     }
01417 
01418     for (int i = 0; streams[i] != kAudioHardwareBadStreamError; ++i)
01419     {
01420         AudioStreamBasicDescription *formats = FormatsList(streams[i]);
01421         if (!formats)
01422             continue;
01423 
01424         // Find a stream with a cac3 stream
01425         for (int j = 0; formats[j].mFormatID != 0; j++)
01426         {
01427             Debug(QString("OpenSPDIF: Considering Physical Format: %1")
01428                   .arg(StreamDescriptionToString(formats[j])));
01429             if ((formats[j].mFormatID == 'IAC3' ||
01430                  formats[j].mFormatID == kAudioFormat60958AC3) &&
01431                 formats[j].mSampleRate == mCA->samplerate)
01432             {
01433                 Debug("OpenSPDIF: Found digital format");
01434                 mStreamIndex  = i;
01435                 mStreamID     = streams[i];
01436                 outputFormat  = formats[j];
01437                 break;
01438             }
01439         }
01440         free(formats);
01441 
01442         if (outputFormat.mFormatID)
01443             break;
01444     }
01445     free(streams);
01446 
01447     if (!outputFormat.mFormatID)
01448     {
01449         Error(QString("OpenSPDIF: Couldn't find suitable output"));
01450         return false;
01451     }
01452 
01453     if (mRevertFormat == false)
01454     {
01455         // Retrieve the original format of this stream first
01456         // if not done so already
01457         UInt32 paramSize = sizeof(mFormatOrig);
01458         err = AudioStreamGetProperty(mStreamID, 0,
01459                                      kAudioStreamPropertyPhysicalFormat,
01460                                      &paramSize, &mFormatOrig);
01461         if (err != noErr)
01462         {
01463             Warn(QString("OpenSPDIF - could not retrieve the original streamformat: [%1]")
01464                  .arg(OSS_STATUS(err)));
01465         }
01466         else
01467         {
01468             mRevertFormat = true;
01469         }
01470     }
01471 
01472     mDigitalInUse = true;
01473 
01474     SetAutoHogMode(false);
01475     bool autoHog = GetAutoHogMode();
01476     if (!autoHog)
01477     {
01478         // Hog the device
01479         SetHogStatus(true);
01480         // Set mixable to false if we are allowed to
01481         SetMixingSupport(false);
01482     }
01483 
01484     mFormatNew = outputFormat;
01485     if (!AudioStreamChangeFormat(mStreamID, mFormatNew))
01486     {
01487         return false;
01488     }
01489     mBytesPerPacket = mFormatNew.mBytesPerPacket;
01490 
01491     // Add IOProc callback
01492     err = AudioDeviceAddIOProc(mDeviceID,
01493                                (AudioDeviceIOProc)RenderCallbackSPDIF,
01494                                (void *)this);
01495     if (err != noErr)
01496     {
01497         Error(QString("OpenSPDIF: AudioDeviceAddIOProc failed: [%1]")
01498               .arg(OSS_STATUS(err)));
01499         return false;
01500     }
01501     mIoProc = true;
01502 
01503     // Start device
01504     err = AudioDeviceStart(mDeviceID, (AudioDeviceIOProc)RenderCallbackSPDIF);
01505     if (err != noErr)
01506     {
01507         Error(QString("OpenSPDIF: AudioDeviceStart failed: [%1]")
01508               .arg(OSS_STATUS(err)));
01509         return false;
01510     }
01511     mStarted = true;
01512     return true;
01513 }
01514 
01515 void CoreAudioData::CloseSPDIF()
01516 {
01517     OSStatus  err;
01518 
01519     Debug(QString("CloseSPDIF: Entering [%1]").arg(mDigitalInUse));;
01520     if (!mDigitalInUse)
01521         return;
01522 
01523     // Stop device
01524     if (mStarted)
01525     {
01526         err = AudioDeviceStop(mDeviceID, (AudioDeviceIOProc)RenderCallbackSPDIF);
01527         if (err != noErr)
01528             Error(QString("CloseSPDIF: AudioDeviceStop failed: [%1]")
01529                   .arg(OSS_STATUS(err)));
01530         mStarted = false;
01531     }
01532 
01533     // Remove IOProc callback
01534     if (mIoProc)
01535     {
01536         err = AudioDeviceRemoveIOProc(mDeviceID,
01537                                       (AudioDeviceIOProc)RenderCallbackSPDIF);
01538         if (err != noErr)
01539             Error(QString("CloseSPDIF: AudioDeviceRemoveIOProc failed: [%1]")
01540                   .arg(OSS_STATUS(err)));
01541         mIoProc = false;
01542     }
01543 
01544     if (mRevertFormat)
01545     {
01546         AudioStreamChangeFormat(mStreamID, mFormatOrig);
01547         mRevertFormat = false;
01548     }
01549 
01550     SetHogStatus(false);
01551     if (mMixerRestore > -1) // We changed the mixer status
01552         SetMixingSupport((mMixerRestore ? true : false));
01553     AudioHardwareUnload();
01554     mMixerRestore = -1;
01555     mBytesPerPacket = -1;
01556     mStreamIndex = -1;
01557     mWasDigital = true;
01558 }
01559 
01560 int CoreAudioData::AudioStreamChangeFormat(AudioStreamID               s,
01561                                            AudioStreamBasicDescription format)
01562 {
01563     Debug(QString("AudioStreamChangeFormat: %1 -> %2")
01564           .arg(s)
01565           .arg(StreamDescriptionToString(format)));
01566 
01567     OSStatus err = AudioStreamSetProperty(s, 0, 0,
01568                                           kAudioStreamPropertyPhysicalFormat,
01569                                           sizeof(format), &format);
01570     if (err != noErr)
01571     {
01572         Error(QString("AudioStreamChangeFormat couldn't set stream format: [%1]")
01573               .arg(OSS_STATUS(err)));
01574         return false;
01575     }
01576     return true;
01577 }
01578 
01579 bool CoreAudioData::FindAC3Stream()
01580 {
01581     bool           foundAC3Stream = false;
01582     AudioStreamID  *streams;
01583 
01584 
01585     // Get a list of all the streams on this device
01586     streams = StreamsList(mDeviceID);
01587     if (!streams)
01588         return false;
01589 
01590     for (int i = 0; !foundAC3Stream &&
01591          streams[i] != kAudioHardwareBadStreamError; ++i)
01592     {
01593         AudioStreamBasicDescription *formats = FormatsList(streams[i]);
01594         if (!formats)
01595             continue;
01596 
01597         // Find a stream with a cac3 stream
01598         for (int j = 0; formats[j].mFormatID != 0; j++)
01599             if (formats[j].mFormatID == 'IAC3' ||
01600                 formats[j].mFormatID == kAudioFormat60958AC3)
01601             {
01602                 Debug("FindAC3Stream: found digital format");
01603                 foundAC3Stream = true;
01604                 break;
01605             }
01606 
01607         free(formats);
01608     }
01609     free(streams);
01610 
01611     return foundAC3Stream;
01612 }
01613 
01618 void CoreAudioData::ResetAudioDevices()
01619 {
01620     AudioDeviceID  *devices;
01621     int            numDevices;
01622     UInt32         size;
01623 
01624 
01625     AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &size, NULL);
01626     devices    = (AudioDeviceID*)malloc(size);
01627     if (!devices)
01628     {
01629         Error("ResetAudioDevices: out of memory?");
01630         return;
01631     }
01632     numDevices = size / sizeof(AudioDeviceID);
01633     AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &size, devices);
01634 
01635     for (int i = 0; i < numDevices; i++)
01636     {
01637         AudioStreamID  *streams;
01638 
01639         streams = StreamsList(devices[i]);
01640         if (!streams)
01641             continue;
01642         for (int j = 0; streams[j] != kAudioHardwareBadStreamError; j++)
01643             ResetStream(streams[j]);
01644 
01645         free(streams);
01646     }
01647     free(devices);
01648 }
01649 
01650 void CoreAudioData::ResetStream(AudioStreamID s)
01651 {
01652     AudioStreamBasicDescription  currentFormat;
01653     OSStatus                     err;
01654     UInt32                       paramSize;
01655 
01656     // Find the streams current physical format
01657     paramSize = sizeof(currentFormat);
01658     AudioStreamGetProperty(s, 0, kAudioStreamPropertyPhysicalFormat,
01659                            &paramSize, &currentFormat);
01660 
01661     // If it's currently AC-3/SPDIF then reset it to some mixable format
01662     if (currentFormat.mFormatID == 'IAC3' ||
01663         currentFormat.mFormatID == kAudioFormat60958AC3)
01664     {
01665         AudioStreamBasicDescription *formats    = FormatsList(s);
01666         bool                        streamReset = false;
01667 
01668 
01669         if (!formats)
01670             return;
01671 
01672         for (int i = 0; !streamReset && formats[i].mFormatID != 0; i++)
01673             if (formats[i].mFormatID == kAudioFormatLinearPCM)
01674             {
01675                 err = AudioStreamSetProperty(s, NULL, 0,
01676                                              kAudioStreamPropertyPhysicalFormat,
01677                                              sizeof(formats[i]), &(formats[i]));
01678                 if (err != noErr)
01679                 {
01680                     Warn(QString("ResetStream: could not set physical format: [%1]")
01681                          .arg(OSS_STATUS(err)));
01682                     continue;
01683                 }
01684                 else
01685                 {
01686                     streamReset = true;
01687                     sleep(1);   // For the change to take effect
01688                 }
01689             }
01690 
01691         free(formats);
01692     }
01693 }
01694 
01695 QMap<QString, QString> *AudioOutputCA::GetDevices(const char *type)
01696 {
01697     QMap<QString, QString> *devs = new QMap<QString, QString>();
01698 
01699     // Obtain a list of all available audio devices
01700     UInt32 size = 0;
01701     AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &size, NULL);
01702     UInt32 deviceCount = size / sizeof(AudioDeviceID);
01703     AudioDeviceID* pDevices = new AudioDeviceID[deviceCount];
01704     OSStatus err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices,
01705                                             &size, pDevices);
01706     if (err)
01707         VBAUDIO(QString("AudioOutputCA::GetDevices: Unable to retrieve the list of "
01708                         "available devices. Error [%1]")
01709                 .arg(err));
01710     else
01711     {
01712         VBAUDIO(QString("GetDevices: Number of devices: %1").arg(deviceCount));
01713 
01714         for (UInt32 dev = 0; dev < deviceCount; dev++)
01715         {
01716             CoreAudioData device(NULL, pDevices[dev]);
01717             if (device.GetTotalOutputChannels() == 0)
01718                 continue;
01719             QString *name = device.GetName();
01720             if (name)
01721             {
01722                 devs->insert(*name, QString());
01723                 delete name;
01724             }
01725         }
01726     }
01727     return devs;
01728 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends