00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <CoreServices/CoreServices.h>
00024 #include <CoreAudio/CoreAudio.h>
00025 #include <AudioUnit/AudioUnit.h>
00026
00027 using namespace std;
00028
00029 #include "mythcontext.h"
00030 #include "audiooutputca.h"
00031 #include "config.h"
00032 #include "SoundTouch.h"
00033
00038 class CoreAudioData {
00039 public:
00040 CoreAudioData(AudioOutputCA *parent);
00041
00042
00043 bool OpenDevice();
00044 bool OpenAnalog();
00045 bool OpenSPDIF ();
00046 void CloseSPDIF();
00047
00048 pid_t GetHogPID();
00049 bool SetHogPID(pid_t pid);
00050 bool SetHogMode();
00051 void ReleaseHogMode() { SetHogPID(-1); }
00052
00053 bool SetUnMixable();
00054
00055 bool FindAC3Stream();
00056 void ResetAudioDevices();
00057 void ResetStream(AudioStreamID s);
00058
00059
00060 AudioStreamID *StreamsList(AudioDeviceID d);
00061 AudioStreamBasicDescription *FormatsList(AudioStreamID s);
00062
00063 int AudioStreamChangeFormat(AudioStreamID s,
00064 AudioStreamBasicDescription format);
00065
00066 void Debug(QString msg)
00067 { VERBOSE(VB_AUDIO, "CoreAudioData::" + msg); }
00068
00069 void Error(QString msg)
00070 { VERBOSE(VB_IMPORTANT, "AudioOutputCA Error: " + msg); }
00071
00072 void Warn (QString msg)
00073 { VERBOSE(VB_IMPORTANT, "AudioOutputCA Warning: " + msg); }
00074
00075
00076
00077 AudioOutputCA *mCA;
00078
00079
00080 AudioUnit mOutputUnit;
00081
00082
00083 bool mDigitalInUse;
00084 AudioDeviceID mDeviceID;
00085 AudioStreamID mStreamID;
00086 int mStreamIndex;
00087 AudioStreamBasicDescription
00088 mFormatOrig,
00089 mFormatNew;
00090 bool mRevertFormat;
00091 bool mChangedMixing;
00092 };
00093
00094
00095 static OSStatus RenderCallbackAnalog(void *inRefCon,
00096 AudioUnitRenderActionFlags *ioActionFlags,
00097 const AudioTimeStamp *inTimeStamp,
00098 UInt32 inBusNumber,
00099 UInt32 inNumberFrames,
00100 AudioBufferList *ioData);
00101 static OSStatus RenderCallbackSPDIF(AudioDeviceID inDevice,
00102 const AudioTimeStamp *inNow,
00103 const void *inInputData,
00104 const AudioTimeStamp *inInputTime,
00105 AudioBufferList *outOutputData,
00106 const AudioTimeStamp *inOutputTime,
00107 void *threadGlobals);
00108
00109
00114 AudioOutputCA::AudioOutputCA(QString laudio_main_device,
00115 QString laudio_passthru_device,
00116 int laudio_bits, int laudio_channels,
00117 int laudio_samplerate,
00118 AudioOutputSource lsource,
00119 bool lset_initial_vol, bool laudio_passthru)
00120 : AudioOutputBase(laudio_main_device, laudio_passthru_device,
00121 laudio_bits, laudio_channels,
00122 laudio_samplerate, lsource,
00123 lset_initial_vol, laudio_passthru),
00124 d(new CoreAudioData(this))
00125 {
00126 Reconfigure(laudio_bits, laudio_channels,
00127 laudio_samplerate, laudio_passthru);
00128 }
00129
00130 AudioOutputCA::~AudioOutputCA()
00131 {
00132 KillAudio();
00133
00134 delete d;
00135 }
00136
00137
00138
00139 bool CoreAudioData::OpenAnalog()
00140 {
00141
00142 ComponentDescription desc;
00143 desc.componentType = kAudioUnitType_Output;
00144 desc.componentSubType = kAudioUnitSubType_DefaultOutput;
00145 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
00146 desc.componentFlags = 0;
00147 desc.componentFlagsMask = 0;
00148
00149 Component comp = FindNextComponent(NULL, &desc);
00150 if (comp == NULL)
00151 {
00152 Error("FindNextComponent failed");
00153 return false;
00154 }
00155
00156 OSStatus err = OpenAComponent(comp, &mOutputUnit);
00157 if (err)
00158 {
00159 Error(QString("OpenAComponent returned %1").arg((long)err));
00160 return false;
00161 }
00162
00163
00164 AURenderCallbackStruct input;
00165 input.inputProc = RenderCallbackAnalog;
00166 input.inputProcRefCon = this;
00167
00168 err = AudioUnitSetProperty(mOutputUnit,
00169 kAudioUnitProperty_SetRenderCallback,
00170 kAudioUnitScope_Input,
00171 0, &input, sizeof(input));
00172 if (err)
00173 {
00174 Error(QString("AudioUnitSetProperty (callback) returned %1")
00175 .arg((long)err));
00176 return false;
00177 }
00178
00179
00180 mCA->audio_bytes_per_sample = mCA->audio_channels * mCA->audio_bits / 8;
00181
00182
00183 AudioStreamBasicDescription conv_in_desc;
00184 bzero(&conv_in_desc, sizeof(AudioStreamBasicDescription));
00185 conv_in_desc.mSampleRate = mCA->audio_samplerate;
00186 conv_in_desc.mFormatID = kAudioFormatLinearPCM;
00187 conv_in_desc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
00188 #ifdef WORDS_BIGENDIAN
00189 conv_in_desc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
00190 #endif
00191 conv_in_desc.mBytesPerPacket = mCA->audio_bytes_per_sample;
00192 conv_in_desc.mFramesPerPacket = 1;
00193 conv_in_desc.mBytesPerFrame = mCA->audio_bytes_per_sample;
00194 conv_in_desc.mChannelsPerFrame = mCA->audio_channels;
00195 conv_in_desc.mBitsPerChannel = mCA->audio_bits;
00196
00197 err = AudioUnitSetProperty(mOutputUnit,
00198 kAudioUnitProperty_StreamFormat,
00199 kAudioUnitScope_Input,
00200 0, &conv_in_desc,
00201 sizeof(AudioStreamBasicDescription));
00202 if (err)
00203 {
00204 Error(QString("AudioUnitSetProperty returned %1").arg((long)err));
00205 return false;
00206 }
00207
00208
00209 ComponentResult res = AudioUnitInitialize(mOutputUnit);
00210 if (res)
00211 {
00212 Error(QString("AudioUnitInitialize returned %1").arg((long)res));
00213 return false;
00214 }
00215
00216 err = AudioOutputUnitStart(mOutputUnit);
00217 if (err)
00218 {
00219 Error(QString("AudioOutputUnitStart returned %1").arg((long)err));
00220 return false;
00221 }
00222
00223 return true;
00224 }
00225
00226 bool AudioOutputCA::OpenDevice()
00227 {
00228 bool deviceOpened = false;
00229
00230
00231 if (audio_passthru)
00232 {
00233 if (!d->FindAC3Stream())
00234 {
00235 Error("Configured for AC3 passthru but can't find an AC3"
00236 " output stream. Disabling audio to prevent static");
00237 return false;
00238 }
00239
00240 Debug("OpenDevice() Trying Digital.");
00241 deviceOpened = d->OpenSPDIF();
00242 }
00243
00244 if (!deviceOpened)
00245 {
00246 Debug("OpenDevice() Trying Analogue.");
00247 deviceOpened = d->OpenAnalog();
00248 }
00249
00250 if (!deviceOpened)
00251 {
00252 Error("Couldn't open any audio device!");
00253 return false;
00254 }
00255
00256 if (internal_vol && set_initial_vol)
00257 {
00258 QString controlLabel = gContext->GetSetting("MixerControl", "PCM");
00259 controlLabel += "MixerVolume";
00260 SetCurrentVolume(gContext->GetNumSetting(controlLabel, 80));
00261 }
00262
00263 return true;
00264 }
00265
00266 void AudioOutputCA::CloseDevice()
00267 {
00268 if (d->mOutputUnit)
00269 {
00270 AudioOutputUnitStop(d->mOutputUnit);
00271 AudioUnitUninitialize(d->mOutputUnit);
00272 AudioUnitReset(d->mOutputUnit, kAudioUnitScope_Input, NULL);
00273 CloseComponent(d->mOutputUnit);
00274 d->mOutputUnit = NULL;
00275 }
00276
00277 if (d->mDigitalInUse)
00278 d->CloseSPDIF();
00279 }
00280
00282 bool AudioOutputCA::RenderAudio(unsigned char *aubuf,
00283 int size, unsigned long long timestamp)
00284 {
00285 if (pauseaudio || killaudio)
00286 {
00287 audio_actually_paused = true;
00288 return false;
00289 }
00290
00291
00292
00293
00294
00295
00296
00297
00298 int written_size = GetAudioData(aubuf, size, false);
00299 if (written_size && (size > written_size))
00300 {
00301
00302 bzero(aubuf + written_size, size - written_size);
00303 }
00304
00305
00306 UInt64 nanos = AudioConvertHostTimeToNanos(
00307 timestamp - AudioGetCurrentHostTime());
00308 bufferedBytes = (int)((nanos / 1000000000.0) *
00309 (effdsp / 100.0) *
00310 audio_bytes_per_sample);
00311 SetAudiotime();
00312
00313 return (written_size > 0);
00314 }
00315
00316 void AudioOutputCA::WriteAudio(unsigned char *aubuf, int size)
00317 {
00318 (void)aubuf;
00319 (void)size;
00320 return;
00321 }
00322
00323 int AudioOutputCA::getSpaceOnSoundcard(void)
00324 {
00325 return 0;
00326 }
00327
00328 int AudioOutputCA::getBufferedOnSoundcard(void)
00329 {
00330 return bufferedBytes;
00331 }
00332
00336 int AudioOutputCA::GetAudiotime(void)
00337 {
00338 int ret;
00339
00340 if (GetBaseAudioTime() == 0)
00341 return 0;
00342
00343 UInt64 hostNanos = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime());
00344 ret = (hostNanos / 1000000) - CA_audiotime_updated;
00345
00346 ret += GetBaseAudioTime();
00347
00348 return ret;
00349 }
00350
00354 void AudioOutputCA::SetAudiotime(void)
00355 {
00356 if (GetBaseAudBufTimeCode() == 0)
00357 return;
00358
00359 int soundcard_buffer = 0;
00360 int totalbuffer;
00361
00362
00363 soundcard_buffer = getBufferedOnSoundcard();
00364 totalbuffer = audiolen(false) + soundcard_buffer;
00365
00366 if (GetSoundStretch())
00367 totalbuffer += (int)((GetSoundStretch()->numUnprocessedSamples() *
00368 audio_bytes_per_sample) / audio_stretchfactor);
00369
00370 SetBaseAudioTime(GetBaseAudBufTimeCode() - (int)(totalbuffer * 100000.0 /
00371 (audio_bytes_per_sample * effdspstretched)));
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383 UInt64 hostNanos = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime());
00384 CA_audiotime_updated = hostNanos / 1000000;
00385 }
00386
00387
00388 OSStatus RenderCallbackAnalog(void *inRefCon,
00389 AudioUnitRenderActionFlags *ioActionFlags,
00390 const AudioTimeStamp *inTimeStamp,
00391 UInt32 inBusNumber,
00392 UInt32 inNumberFrames,
00393 AudioBufferList *ioData)
00394 {
00395 (void)inBusNumber;
00396 (void)inNumberFrames;
00397
00398 AudioOutputCA *inst = ((CoreAudioData *)inRefCon)->mCA;
00399
00400 if (!inst->RenderAudio((unsigned char *)(ioData->mBuffers[0].mData),
00401 ioData->mBuffers[0].mDataByteSize,
00402 inTimeStamp->mHostTime))
00403 {
00404
00405 bzero(ioData->mBuffers[0].mData, ioData->mBuffers[0].mDataByteSize);
00406 *ioActionFlags = kAudioUnitRenderAction_OutputIsSilence;
00407 }
00408 return noErr;
00409 }
00410
00411 int AudioOutputCA::GetVolumeChannel(int channel)
00412 {
00413
00414 (void)channel;
00415 Float32 volume;
00416
00417 if (!AudioUnitGetParameter(d->mOutputUnit,
00418 kHALOutputParam_Volume,
00419 kAudioUnitScope_Global, 0, &volume))
00420 return (int)lroundf(volume * 100.0);
00421
00422 return 0;
00423 }
00424
00425 void AudioOutputCA::SetVolumeChannel(int channel, int volume)
00426 {
00427
00428 (void)channel;
00429 AudioUnitSetParameter(d->mOutputUnit, kHALOutputParam_Volume,
00430 kAudioUnitScope_Global, 0, (volume * 0.01), 0);
00431 }
00432
00433
00434 static OSStatus RenderCallbackSPDIF(AudioDeviceID inDevice,
00435 const AudioTimeStamp *inNow,
00436 const void *inInputData,
00437 const AudioTimeStamp *inInputTime,
00438 AudioBufferList *outOutputData,
00439 const AudioTimeStamp *inOutputTime,
00440 void *inRefCon)
00441 {
00442 CoreAudioData *d = (CoreAudioData *)inRefCon;
00443 AudioOutputCA *a = d->mCA;
00444 int index = d->mStreamIndex;
00445
00446 (void)inDevice;
00447 (void)inNow;
00448 (void)inInputData;
00449 (void)inInputTime;
00450
00451 if (!a->RenderAudio((unsigned char *)(outOutputData->mBuffers[index].mData),
00452 outOutputData->mBuffers[index].mDataByteSize,
00453 inOutputTime->mHostTime))
00454
00455 bzero(outOutputData->mBuffers[index].mData,
00456 outOutputData->mBuffers[index].mDataByteSize);
00457
00458 return noErr;
00459 }
00460
00461
00462 CoreAudioData::CoreAudioData(AudioOutputCA *parent) : mCA(parent)
00463 {
00464 UInt32 paramSize;
00465 OSStatus err;
00466
00467
00468
00469 mOutputUnit = NULL;
00470 mDeviceID = 0;
00471 mDigitalInUse = false;
00472 mRevertFormat = false;
00473 mStreamIndex = -1;
00474
00475
00476
00477
00478
00479 ResetAudioDevices();
00480
00481
00482 paramSize = sizeof(mDeviceID);
00483 err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice,
00484 ¶mSize, &mDeviceID);
00485 if (err == noErr)
00486 Debug(QString("CoreAudioData - default device ID = %1").arg(mDeviceID));
00487 else
00488 {
00489 Warn(QString("CoreAudioData - could not get default audio device: %1")
00490 .arg(err));
00491 mDeviceID = 0;
00492 }
00493 }
00494
00495 pid_t CoreAudioData::GetHogPID()
00496 {
00497 OSStatus err;
00498 pid_t PID;
00499 UInt32 PIDsize = sizeof(PID);
00500
00501 err = AudioDeviceGetProperty(mDeviceID, 0, FALSE,
00502 kAudioDevicePropertyHogMode, &PIDsize, &PID);
00503 if (err != noErr)
00504 {
00505
00506
00507 Debug(QString("GetHogPID - unable to check: %1").arg(err));
00508 return -1;
00509 }
00510
00511 return PID;
00512 }
00513
00514 bool CoreAudioData::SetHogPID(pid_t PID)
00515 {
00516 OSStatus err;
00517
00518
00519 err = AudioDeviceSetProperty(mDeviceID, 0, 0, FALSE,
00520 kAudioDevicePropertyHogMode,
00521 sizeof(PID), &PID);
00522 if (err != noErr)
00523 {
00524 Error(QString("SetHogPID(%1) failed: %2").arg(PID).arg(err));
00525 return false;
00526 }
00527
00528 return true;
00529 }
00530
00531 bool CoreAudioData::SetHogMode()
00532 {
00533 pid_t myPID = getpid();
00534 pid_t hogPID = GetHogPID();
00535
00536 if (hogPID != -1 && hogPID != myPID)
00537 {
00538 Warn(QString("SetHogMode - Selected audio device is exclusively in use by another program (PID %1)").arg(hogPID));
00539 return false;
00540 }
00541
00542 return SetHogPID(myPID);
00543 }
00544
00548 bool CoreAudioData::SetUnMixable()
00549 {
00550 UInt32 b_mix = 0;
00551 Boolean b_writeable = false;
00552 OSStatus err;
00553 UInt32 paramSize;
00554
00555 paramSize = sizeof(b_writeable);
00556 err = AudioDeviceGetPropertyInfo(mDeviceID, 0, FALSE,
00557 kAudioDevicePropertySupportsMixing,
00558 ¶mSize, &b_writeable);
00559
00560 if (err != noErr)
00561 {
00562 Warn(QString("SetUnMixable - Can't GetPropertyInfo?").arg(err));
00563 return false;
00564 }
00565
00566 paramSize = sizeof(b_mix);
00567 err = AudioDeviceGetProperty(mDeviceID, 0, FALSE,
00568 kAudioDevicePropertySupportsMixing,
00569 ¶mSize, &b_mix);
00570 if (err == noErr && b_writeable)
00571 {
00572 b_mix = 0;
00573 err = AudioDeviceSetProperty(mDeviceID, 0, 0, FALSE,
00574 kAudioDevicePropertySupportsMixing,
00575 paramSize, &b_mix);
00576 mChangedMixing = true;
00577 }
00578
00579 if (err != noErr)
00580 {
00581 Warn(QString("SetUnMixable - failed to set mixmode: %1").arg(err));
00582 ReleaseHogMode();
00583 return false;
00584 }
00585
00586 return true;
00587 }
00588
00592 AudioStreamID *CoreAudioData::StreamsList(AudioDeviceID d)
00593 {
00594 OSStatus err;
00595 UInt32 listSize;
00596 AudioStreamID *list;
00597
00598
00599 err = AudioDeviceGetPropertyInfo(d, 0, FALSE,
00600 kAudioDevicePropertyStreams,
00601 &listSize, NULL);
00602 if (err != noErr)
00603 {
00604 Error(QString("StreamsList() - could not get list size: %1").arg(err));
00605 return NULL;
00606 }
00607
00608
00609 listSize += sizeof(AudioStreamID);
00610 list = (AudioStreamID *)malloc(listSize);
00611
00612 if (list == NULL)
00613 {
00614 Error("StreamsList() - out of memory?");
00615 return NULL;
00616 }
00617
00618 err = AudioDeviceGetProperty(d, 0, FALSE,
00619 kAudioDevicePropertyStreams,
00620 &listSize, list);
00621 if (err != noErr)
00622 {
00623 Error(QString("StreamsList() - could not get list: %1").arg(err));
00624 return NULL;
00625 }
00626
00627
00628 list[listSize/sizeof(AudioStreamID)] = kAudioHardwareBadStreamError;
00629
00630 return list;
00631 }
00632
00633 AudioStreamBasicDescription *CoreAudioData::FormatsList(AudioStreamID s)
00634 {
00635 OSStatus err;
00636 AudioStreamBasicDescription *list;
00637 UInt32 listSize;
00638 AudioDevicePropertyID p;
00639
00640
00641
00642
00643 p = kAudioStreamPropertyPhysicalFormats,
00644
00645
00646 err = AudioStreamGetPropertyInfo(s, 0, p, &listSize, NULL);
00647 if (err != noErr)
00648 {
00649 Warn(QString("FormatsList() couldn't get list size: %1").arg(err));
00650 return NULL;
00651 }
00652
00653
00654 listSize += sizeof(AudioStreamBasicDescription);
00655 list = (AudioStreamBasicDescription *)malloc(listSize);
00656
00657 if (list == NULL)
00658 {
00659 Error("FormatsList() - out of memory?");
00660 return NULL;
00661 }
00662
00663 err = AudioStreamGetProperty(s, 0, p, &listSize, list);
00664 if (err != noErr)
00665 {
00666 Warn(QString("FormatsList() couldn't get list: %1").arg(err));
00667 free(list);
00668 return NULL;
00669 }
00670
00671
00672 list[listSize/sizeof(AudioStreamID)].mFormatID = 0;
00673
00674 return list;
00675 }
00676
00677 bool CoreAudioData::OpenSPDIF()
00678 {
00679 OSStatus err;
00680 AudioStreamID *streams;
00681 UInt32 paramSize = 0;
00682
00683
00684 if (!SetHogMode())
00685 return false;
00686
00687
00688 if (!SetUnMixable())
00689 return false;
00690
00691 streams = StreamsList(mDeviceID);
00692 if (!streams)
00693 return false;
00694
00695 for (int i = 0; mStreamIndex < 0 &&
00696 streams[i] != kAudioHardwareBadStreamError; ++i)
00697 {
00698 AudioStreamBasicDescription *formats = FormatsList(streams[i]);
00699 if (!formats)
00700 continue;
00701
00702
00703 for (int j = 0; formats[j].mFormatID != 0; j++)
00704 {
00705 if (formats[j].mFormatID == 'IAC3' ||
00706 formats[j].mFormatID == kAudioFormat60958AC3)
00707 {
00708 Debug("OpenSPDIF - found digital format");
00709 mDigitalInUse = true;
00710 break;
00711 }
00712 }
00713
00714 if (!mDigitalInUse)
00715 {
00716
00717 ReleaseHogMode();
00718 return false;
00719 }
00720
00721 if (mDigitalInUse)
00722 {
00723
00724 int requestedFmt = -1;
00725 int currentFmt = -1;
00726 int backupFmt = -1;
00727
00728 mStreamID = streams[i];
00729 mStreamIndex = i;
00730
00731 if (mRevertFormat == false)
00732 {
00733
00734
00735 paramSize = sizeof(mFormatOrig);
00736 err = AudioStreamGetProperty(mStreamID, 0,
00737 kAudioStreamPropertyPhysicalFormat,
00738 ¶mSize, &mFormatOrig);
00739 if (err != noErr)
00740 {
00741 Warn(QString("OpenSPDIF - could not retrieve the original streamformat: %1").arg(err));
00742 continue;
00743 }
00744 mRevertFormat = true;
00745 }
00746
00747 for (int j = 0; formats[j].mFormatID != 0; j++)
00748 {
00749 if (formats[j].mFormatID == 'IAC3' ||
00750 formats[j].mFormatID == kAudioFormat60958AC3)
00751 {
00752 if (formats[j].mSampleRate == mCA->audio_samplerate)
00753 {
00754 requestedFmt = j;
00755 break;
00756 }
00757 else if (formats[j].mSampleRate == mFormatOrig.mSampleRate)
00758 currentFmt = j;
00759 else if (backupFmt < 0 || formats[j].mSampleRate >
00760 formats[backupFmt].mSampleRate)
00761 backupFmt = j;
00762 }
00763 }
00764
00765
00766 if (requestedFmt >= 0)
00767 mFormatNew = formats[requestedFmt];
00768
00769
00770 else if (currentFmt >= 0)
00771 mFormatNew = formats[currentFmt];
00772
00773
00774
00775 else
00776 mFormatNew = formats[backupFmt];
00777 }
00778 free(formats);
00779 }
00780 free(streams);
00781
00782 if (!AudioStreamChangeFormat(mStreamID, mFormatNew))
00783 {
00784 ReleaseHogMode();
00785 return false;
00786 }
00787
00788
00789 err = AudioDeviceAddIOProc(mDeviceID,
00790 (AudioDeviceIOProc)RenderCallbackSPDIF,
00791 (void *)this);
00792 if (err != noErr)
00793 {
00794 Warn(QString("OpenSPDIF - AudioDeviceAddIOProc failed: %1").arg(err));
00795 ReleaseHogMode();
00796 return false;
00797 }
00798
00799
00800 err = AudioDeviceStart(mDeviceID, (AudioDeviceIOProc)RenderCallbackSPDIF);
00801 if (err != noErr)
00802 {
00803 Warn(QString("OpenSPDIF - AudioDeviceStart failed: %1").arg(err));
00804
00805 err = AudioDeviceRemoveIOProc(mDeviceID,
00806 (AudioDeviceIOProc)RenderCallbackSPDIF);
00807 if (err != noErr)
00808 Warn(QString("OpenSPDIF - AudioDeviceRemoveIOProc failed: %1")
00809 .arg(err));
00810 ReleaseHogMode();
00811 return false;
00812 }
00813
00814 return true;
00815 }
00816
00817 void CoreAudioData::CloseSPDIF()
00818 {
00819 OSStatus err;
00820 UInt32 paramSize;
00821
00822
00823 err = AudioDeviceStop(mDeviceID, (AudioDeviceIOProc)RenderCallbackSPDIF);
00824 if (err != noErr)
00825 Debug(QString("CloseSPDIF - AudioDeviceStop failed: %1").arg(err));
00826
00827
00828 err = AudioDeviceRemoveIOProc(mDeviceID,
00829 (AudioDeviceIOProc)RenderCallbackSPDIF);
00830 if (err != noErr)
00831 Debug(QString("CloseSPDIF - AudioDeviceRemoveIOProc failed: %1")
00832 .arg(err));
00833
00834 if (mRevertFormat)
00835 AudioStreamChangeFormat(mStreamID, mFormatOrig);
00836
00837 if (mChangedMixing && mFormatOrig.mFormatID != kAudioFormat60958AC3)
00838 {
00839 int b_mix;
00840 Boolean b_writeable;
00841
00842
00843 err = AudioDeviceGetPropertyInfo(mDeviceID, 0, FALSE,
00844 kAudioDevicePropertySupportsMixing,
00845 ¶mSize, &b_writeable);
00846
00847 err = AudioDeviceGetProperty(mDeviceID, 0, FALSE,
00848 kAudioDevicePropertySupportsMixing,
00849 ¶mSize, &b_mix);
00850
00851 if (!err && b_writeable)
00852 {
00853 Debug(QString("CloseSPDIF - mixable is: %1").arg(b_mix));
00854 b_mix = 1;
00855 err = AudioDeviceSetProperty(mDeviceID, 0, 0, FALSE,
00856 kAudioDevicePropertySupportsMixing,
00857 paramSize, &b_mix);
00858 }
00859
00860 if (err != noErr)
00861 Debug(QString("CloseSPDIF - failed to set mixmode: %d").arg(err));
00862 }
00863
00864 if (GetHogPID() == getpid())
00865 ReleaseHogMode();
00866 }
00867
00868 int CoreAudioData::AudioStreamChangeFormat(AudioStreamID s,
00869 AudioStreamBasicDescription format)
00870 {
00871 Debug(QString("AudioStreamChangeFormat(%1)").arg(s));
00872
00873 OSStatus err = AudioStreamSetProperty(s, 0, 0,
00874 kAudioStreamPropertyPhysicalFormat,
00875 sizeof(format), &format);
00876 if (err != noErr)
00877 {
00878 Error(QString("AudioStreamChangeFormat couldn't set stream format: %1")
00879 .arg(err));
00880 return false;
00881 }
00882
00883 return true;
00884 }
00885
00886 bool CoreAudioData::FindAC3Stream()
00887 {
00888 bool foundAC3Stream = false;
00889 AudioStreamID *streams;
00890
00891
00892
00893 streams = StreamsList(mDeviceID);
00894 if (!streams)
00895 return false;
00896
00897 for (int i = 0; !foundAC3Stream &&
00898 streams[i] != kAudioHardwareBadStreamError; ++i)
00899 {
00900 AudioStreamBasicDescription *formats = FormatsList(streams[i]);
00901 if (!formats)
00902 continue;
00903
00904
00905 for (int j = 0; formats[j].mFormatID != 0; j++)
00906 if (formats[j].mFormatID == 'IAC3' ||
00907 formats[j].mFormatID == kAudioFormat60958AC3)
00908 {
00909 Debug("FindAC3Stream - found digital format");
00910 foundAC3Stream = true;
00911 break;
00912 }
00913
00914 free(formats);
00915 }
00916 free(streams);
00917
00918 return foundAC3Stream;
00919 }
00920
00925 void CoreAudioData::ResetAudioDevices()
00926 {
00927 AudioDeviceID *devices;
00928 int numDevices;
00929 UInt32 size;
00930
00931
00932 AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &size, NULL);
00933 devices = (AudioDeviceID*)malloc(size);
00934 if (!devices)
00935 {
00936 Error("ResetAudioDevices - out of memory?");
00937 return;
00938 }
00939 numDevices = size / sizeof(AudioDeviceID);
00940 AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &size, devices);
00941
00942 for (int i = 0; i < numDevices; i++)
00943 {
00944 AudioStreamID *streams;
00945
00946 streams = StreamsList(devices[i]);
00947 for (int j = 0; streams[j] != kAudioHardwareBadStreamError; j++)
00948 ResetStream(streams[j]);
00949
00950 free(streams);
00951 }
00952 free(devices);
00953 }
00954
00955 void CoreAudioData::ResetStream(AudioStreamID s)
00956 {
00957 AudioStreamBasicDescription currentFormat;
00958 OSStatus err;
00959 UInt32 paramSize;
00960
00961
00962
00963 paramSize = sizeof(currentFormat);
00964 AudioStreamGetProperty(s, 0, kAudioStreamPropertyPhysicalFormat,
00965 ¶mSize, ¤tFormat);
00966
00967
00968 if (currentFormat.mFormatID == 'IAC3' ||
00969 currentFormat.mFormatID == kAudioFormat60958AC3)
00970 {
00971 AudioStreamBasicDescription *formats = FormatsList(s);
00972 bool streamReset = false;
00973
00974
00975 if (!formats)
00976 return;
00977
00978 for (int i = 0; !streamReset && formats[i].mFormatID != 0; i++)
00979 if (formats[i].mFormatID == kAudioFormatLinearPCM)
00980 {
00981 err = AudioStreamSetProperty(s, NULL, 0, kAudioStreamPropertyPhysicalFormat, sizeof(formats[i]), &(formats[i]));
00982 if (err != noErr)
00983 {
00984 Warn(QString("ResetStream - could not set physical format: %1").arg(err));
00985 continue;
00986 }
00987 else
00988 {
00989 streamReset = true;
00990 sleep(1);
00991 }
00992 }
00993
00994 free(formats);
00995 }
00996 }