|
MythTV
0.26-pre
|
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 ¶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 // 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 ¶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 /* Get the channel layout of the device side of the unit */ 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 /* 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 ¶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 /* layouttags defined channellayout */ 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 // 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 ¶m_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 ¶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 // 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 ¶mSize, ¤tFormat); 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 }
1.7.6.1