00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
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
00119 AudioStreamID *StreamsList(AudioDeviceID d);
00120 AudioStreamBasicDescription *FormatsList(AudioStreamID s);
00121
00122 int AudioStreamChangeFormat(AudioStreamID s,
00123 AudioStreamBasicDescription format);
00124
00125
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;
00136
00137
00138 AudioUnit mOutputUnit;
00139
00140
00141 bool mDigitalInUse;
00142 pid_t mHog;
00143 int mMixerRestore;
00144 AudioDeviceID mDeviceID;
00145 AudioStreamID mStreamID;
00146 int mStreamIndex;
00147 UInt32 mBytesPerPacket;
00148 AudioStreamBasicDescription
00149 mFormatOrig,
00150 mFormatNew;
00151 bool mRevertFormat;
00152 bool mIoProc;
00153 bool mInitialized;
00154 bool mStarted;
00155 bool mWasDigital;
00156 };
00157
00158
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
00201 int rate;
00202 int *rates = d->RatesList(d->mDeviceID);
00203
00204 if (rates == NULL)
00205 {
00206
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
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
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
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);
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
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
00358
00359
00360
00361
00362
00363
00364 int written_size = GetAudioData(aubuf, size, false);
00365 if (written_size && (size > written_size))
00366 {
00367
00368 memset(aubuf + written_size, 0, size - written_size);
00369 }
00370
00371
00372 if (!passthru && channels == 8)
00373 {
00374 ReorderSmpteToCA(aubuf, size / output_bytes_per_frame, output_format);
00375 }
00376
00377
00378 UInt64 nanos = AudioConvertHostTimeToNanos(timestamp -
00379 AudioGetCurrentHostTime());
00380 bufferedBytes = (int)((nanos / 1000000000.0) *
00381 (effdsp / 100.0) *
00382 output_bytes_per_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;
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
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
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
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;
00452 }
00453
00454 void AudioOutputCA::SetVolumeChannel(int channel, int volume)
00455 {
00456
00457 (void)channel;
00458 AudioUnitSetParameter(d->mOutputUnit, kHALOutputParam_Volume,
00459 kAudioUnitScope_Global, 0, (volume * 0.01f), 0);
00460 }
00461
00462
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;
00476 (void)inNow;
00477 (void)inInputData;
00478 (void)inInputTime;
00479
00480
00481
00482
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
00494 memset(outOutputData->mBuffers[index].mData, 0,
00495 outOutputData->mBuffers[index].mDataByteSize);
00496 }
00497 return noErr;
00498 }
00499
00500 void CoreAudioData::Initialise()
00501 {
00502
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
00521
00522
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
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
00601 paramSize = sizeof(deviceId);
00602 err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice,
00603 ¶mSize, &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
00712
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
00723
00724
00725 if (!mDeviceID)
00726 return false;
00727
00728 if (hog)
00729 {
00730 if (mHog == -1)
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)
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;
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)
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
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
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
00863
00864 p = kAudioStreamPropertyPhysicalFormats;
00865
00866
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
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
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
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
00965 UInt32 theFirstIndex = 0, theLastIndex = 0;
00966 for(UInt32 i = 0; i < listSize / sizeof(AudioValueRange); i++)
00967 {
00968 theFirstIndex = theLastIndex;
00969
00970 while((theFirstIndex < sNumberCommonSampleRates) && (sCommonSampleRates[theFirstIndex] < list[i].mMinimum))
00971 theFirstIndex++;
00972
00973 if (theFirstIndex >= sNumberCommonSampleRates)
00974 break;
00975
00976 theLastIndex = theFirstIndex;
00977
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
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
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
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
01125
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
01143 UInt32 param_size = sizeof(AudioStreamBasicDescription);
01144
01145 err = AudioUnitGetProperty(mOutputUnit,
01146 kAudioUnitProperty_StreamFormat,
01147 kAudioUnitScope_Input,
01148 0,
01149 &DeviceFormat,
01150 ¶m_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
01162 err = AudioUnitGetPropertyInfo(mOutputUnit,
01163 kAudioDevicePropertyPreferredChannelLayout,
01164 kAudioUnitScope_Output,
01165 0,
01166 ¶m_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 ¶m_size);
01179
01180
01181 if(layout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap)
01182 {
01183
01184 err = AudioFormatGetProperty(kAudioFormatProperty_ChannelLayoutForBitmap,
01185 sizeof(UInt32), &layout->mChannelBitmap,
01186 ¶m_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
01194 err = AudioFormatGetProperty(kAudioFormatProperty_ChannelLayoutForTag,
01195 sizeof(AudioChannelLayoutTag),
01196 &layout->mChannelLayoutTag,
01197 ¶m_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
01255 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_AudioUnit_5_1;
01256 case 8:
01257
01258
01259
01260 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_MPEG_7_1_A;
01261 break;
01262 }
01263
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
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
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
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
01324 err = AudioUnitGetProperty(mOutputUnit,
01325 kAudioUnitProperty_StreamFormat,
01326 kAudioUnitScope_Input,
01327 0,
01328 &DeviceFormat,
01329 ¶m_size);
01330
01331 Debug(QString("OpenAnalog: the actual set AU format is %1")
01332 .arg(StreamDescriptionToString(DeviceFormat)));
01333
01334
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
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
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
01456
01457 UInt32 paramSize = sizeof(mFormatOrig);
01458 err = AudioStreamGetProperty(mStreamID, 0,
01459 kAudioStreamPropertyPhysicalFormat,
01460 ¶mSize, &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
01479 SetHogStatus(true);
01480
01481 SetMixingSupport(false);
01482 }
01483
01484 mFormatNew = outputFormat;
01485 if (!AudioStreamChangeFormat(mStreamID, mFormatNew))
01486 {
01487 return false;
01488 }
01489 mBytesPerPacket = mFormatNew.mBytesPerPacket;
01490
01491
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
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
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
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)
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
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
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
01657 paramSize = sizeof(currentFormat);
01658 AudioStreamGetProperty(s, 0, kAudioStreamPropertyPhysicalFormat,
01659 ¶mSize, ¤tFormat);
01660
01661
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);
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
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 }