20#include <CoreServices/CoreServices.h>
21#include <CoreAudio/CoreAudio.h>
22#include <AudioUnit/AudioUnit.h>
23#include <AudioToolbox/AudioFormat.h>
24#include <AvailabilityMacros.h>
34#define LOC QString("CoreAudio: ")
45#define OSS_STATUS(x) UInt32ToFourCC((UInt32*)&(x))
49 char* pIn = (
char*)&inVal;
50 static std::array<char,5> fourCC;
61 UInt32 formatId = desc.mFormatID;
65 switch (desc.mFormatID)
67 case kAudioFormatLinearPCM:
68 str = QString(
"[%1] %2%3 Channel %4-bit %5 %6 (%7Hz) %8 Channels")
70 .arg((desc.mFormatFlags & kAudioFormatFlagIsNonMixable) ?
"" :
"Mixable ")
71 .arg(desc.mChannelsPerFrame)
72 .arg(desc.mBitsPerChannel)
73 .arg((desc.mFormatFlags & kAudioFormatFlagIsFloat) ?
"Floating Point" :
"Signed Integer")
74 .arg((desc.mFormatFlags & kAudioFormatFlagIsBigEndian) ?
"BE" :
"LE")
75 .arg((UInt32)desc.mSampleRate)
76 .arg(desc.mChannelsPerFrame);
79 str = QString(
"[%1] AC-3/DTS (%2Hz) %3 Channels")
81 .arg((UInt32)desc.mSampleRate)
82 .arg(desc.mChannelsPerFrame);
84 case kAudioFormat60958AC3:
85 str = QString(
"[%1] AC-3/DTS for S/PDIF %2 (%3Hz) %4 Channels")
87 .arg((desc.mFormatFlags & kAudioFormatFlagIsBigEndian) ?
"BE" :
"LE")
88 .arg((UInt32)desc.mSampleRate)
89 .arg(desc.mChannelsPerFrame);
92 str = QString(
"[%1]").arg(fourCC);
136 AudioStreamBasicDescription format);
163 AudioUnitRenderActionFlags *ioActionFlags,
164 const AudioTimeStamp *inTimeStamp,
166 UInt32 inNumberFrames,
167 AudioBufferList *ioData);
169 const AudioTimeStamp *inNow,
170 const void *inInputData,
171 const AudioTimeStamp *inInputTime,
172 AudioBufferList *outOutputData,
173 const AudioTimeStamp *inOutputTime,
184 LOG(VB_AUDIO, LOG_INFO,
LOC + QString(
"AudioOutputCA::AudioOutputCA searching %1").arg(
m_mainDevice));
209 settings->AddSupportedRate(48000);
213 while (
int rate = settings->GetNextRate())
215 for (
auto entry : rates)
219 settings->AddSupportedRate(entry);
232 settings->AddSupportedChannels(2);
240 LOG(VB_AUDIO, LOG_INFO, QString(
"AudioOutputCA::Support %1 channels").arg(i));
243 settings->AddSupportedChannels(6);
244 settings->AddSupportedChannels(i);
251 settings->setPassthrough(1);
258 bool deviceOpened =
false;
263 LOG(VB_AUDIO, LOG_INFO,
"AudioOutputCA::OpenDevice: Entering");
266 LOG(VB_AUDIO, LOG_INFO,
"AudioOutputCA::OpenDevice() Trying Digital.");
274 LOG(VB_AUDIO, LOG_INFO,
"AudioOutputCA::OpenDevice() Trying Analog.");
279 LOG(VB_AUDIO, LOG_INFO, QString(
"AudioOutputCA::OpenDevice: OpenAnalog = %1").arg(result));
283 std::this_thread::sleep_for(1s);
286 deviceOpened = (result > 0);
291 LOG(VB_GENERAL, LOG_ERR,
"AudioOutputCA Error: Couldn't open any audio device!");
299 controlLabel +=
"MixerVolume";
308 LOG(VB_AUDIO, LOG_INFO,
LOC + QString(
"CloseDevice [%1]: Entering")
316template <
class AudioDataType>
321 AudioDataType tmpRLs;
322 AudioDataType tmpRRs;
323 AudioDataType *buf2 =
nullptr;
324 for (
uint i = 0; i < frames; i++)
326 buf = buf2 = buf + 4;
351 int size,
unsigned long long timestamp)
367 if (written_size && (size > written_size))
370 memset(aubuf + written_size, 0, size - written_size);
380 UInt64 nanos = AudioConvertHostTimeToNanos(timestamp -
381 AudioGetCurrentHostTime());
386 return (written_size > 0);
391 [[maybe_unused]]
int size)
407 if (audbuf_timecode == 0ms)
419 AudioUnitRenderActionFlags *ioActionFlags,
420 const AudioTimeStamp *inTimeStamp,
421 [[maybe_unused]] UInt32 inBusNumber,
422 [[maybe_unused]] UInt32 inNumberFrames,
423 AudioBufferList *ioData)
427 if (!inst->
RenderAudio((
unsigned char *)(ioData->mBuffers[0].mData),
428 ioData->mBuffers[0].mDataByteSize,
429 inTimeStamp->mHostTime))
432 memset(ioData->mBuffers[0].mData, 0, ioData->mBuffers[0].mDataByteSize);
433 *ioActionFlags = kAudioUnitRenderAction_OutputIsSilence;
441 Float32 volume = NAN;
444 kHALOutputParam_Volume,
445 kAudioUnitScope_Global, 0, &volume))
446 return (
int)lroundf(volume * 100.0F);
454 AudioUnitSetParameter(
d->
mOutputUnit, kHALOutputParam_Volume,
455 kAudioUnitScope_Global, 0, (volume * 0.01F), 0);
460 [[maybe_unused]]
const AudioTimeStamp *inNow,
461 [[maybe_unused]]
const void *inInputData,
462 [[maybe_unused]]
const AudioTimeStamp *inInputTime,
463 AudioBufferList *outOutputData,
464 const AudioTimeStamp *inOutputTime,
469 int index =
d->mStreamIndex;
475 if (
d->mBytesPerPacket > 0 &&
476 outOutputData->mBuffers[index].mDataByteSize >
d->mBytesPerPacket)
478 outOutputData->mBuffers[index].mDataByteSize =
d->mBytesPerPacket;
480 if (!a->
RenderAudio((
unsigned char *)(outOutputData->mBuffers[index].mData),
481 outOutputData->mBuffers[index].mDataByteSize,
482 inOutputTime->mHostTime))
485 memset(outOutputData->mBuffers[index].mData, 0,
486 outOutputData->mBuffers[index].mDataByteSize);
492 mCA(parent), mDeviceID(GetDefaultOutputDevice())
501 mCA(parent), mDeviceID(deviceID)
507 mCA(parent), mDeviceID(GetDeviceWithName(deviceName))
514 if (deviceName !=
"Default Output Device")
516 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:CoreAudioData: \"%1\" not found, using default device %2.")
520 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::CoreAudioData: device number is %1")
527 AudioDeviceID deviceID = 0;
528 AudioObjectPropertyAddress pa
530 kAudioHardwarePropertyDevices,
531 kAudioObjectPropertyScopeGlobal,
535 OSStatus err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &pa,
539 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:GetPropertyDataSize: Unable to retrieve the property sizes. "
545 UInt32 deviceCount = size /
sizeof(AudioDeviceID);
546 std::vector<AudioDeviceID> devices = {};
547 devices.resize(deviceCount);
549 err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &pa,
550 0,
nullptr, &size, devices.data());
553 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:GetDeviceWithName: Unable to retrieve the list of available devices. "
559 for (
const auto & dev : devices)
564 QString *name = device.
GetName();
565 if (name && *name == deviceName)
567 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::GetDeviceWithName: Found: %1").arg(*name));
580 UInt32 paramSize = 0;
581 AudioDeviceID deviceId = 0;
582 AudioObjectPropertyAddress pa
584 kAudioHardwarePropertyDefaultOutputDevice,
585 kAudioObjectPropertyScopeGlobal,
590 paramSize =
sizeof(deviceId);
591 OSStatus err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &pa,
592 0,
nullptr, ¶mSize, &deviceId);
594 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::GetDefaultOutputDevice: default device ID = %1").arg(deviceId));
597 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:GetDefaultOutputDevice: could not get default audio device: [%1]")
610 AudioObjectPropertyAddress pa
612 kAudioDevicePropertyStreamConfiguration,
613 kAudioDevicePropertyScopeOutput,
617 OSStatus err = AudioObjectGetPropertyDataSize(
mDeviceID, &pa,
621 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:GetTotalOutputChannels: Unable to get "
622 "size of device output channels - id: %1 Error = [%2]")
628 std::vector<char> plBuffer (size);
629 auto *pList = (AudioBufferList *)plBuffer.data();
630 err = AudioObjectGetPropertyData(
mDeviceID, &pa,
631 0,
nullptr, &size, pList);
634 for (UInt32 buffer = 0; buffer < pList->mNumberBuffers; buffer++)
635 channels += pList->mBuffers[buffer].mNumberChannels;
639 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:GetTotalOutputChannels: Unable to get "
640 "total device output channels - id: %1 Error = [%2]")
644 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::GetTotalOutputChannels: Found %1 channels in %2 buffers")
645 .arg(channels).arg(pList->mNumberBuffers));
654 AudioObjectPropertyAddress pa
656 kAudioObjectPropertyName,
657 kAudioObjectPropertyScopeGlobal,
661 CFStringRef name =
nullptr;
662 UInt32 propertySize =
sizeof(CFStringRef);
663 OSStatus err = AudioObjectGetPropertyData(
mDeviceID, &pa,
664 0,
nullptr, &propertySize, (
void*)&name);
667 LOG(VB_GENERAL, LOG_ERR, QString(
"CoreAudioData Error:AudioObjectGetPropertyData for kAudioObjectPropertyName error: [%1]")
671 char *cname =
new char[CFStringGetLength(name) + 1];
672 CFStringGetCString(name, cname, CFStringGetLength(name) + 1, kCFStringEncodingUTF8);
673 auto *qname =
new QString(cname);
681 UInt32 size =
sizeof(val);
682 AudioObjectPropertyAddress pa
684 kAudioHardwarePropertyHogModeIsAllowed,
685 kAudioObjectPropertyScopeGlobal,
689 OSStatus err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &pa, 0,
nullptr, &size, &val);
692 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:GetAutoHogMode: Unable to get auto 'hog' mode. Error = [%1]")
701 UInt32 val = enable ? 1 : 0;
702 AudioObjectPropertyAddress pa
704 kAudioHardwarePropertyHogModeIsAllowed,
705 kAudioObjectPropertyScopeGlobal,
709 OSStatus err = AudioObjectSetPropertyData(kAudioObjectSystemObject, &pa, 0,
nullptr,
713 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:SetAutoHogMode: Unable to set auto 'hog' mode. Error = [%1]")
721 UInt32 PIDsize =
sizeof(
PID);
722 AudioObjectPropertyAddress pa
724 kAudioDevicePropertyHogMode,
725 kAudioObjectPropertyScopeGlobal,
729 OSStatus err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &pa, 0,
nullptr,
735 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::GetHogStatus: unable to check: [%1]")
744 AudioObjectPropertyAddress pa
746 kAudioDevicePropertyHogMode,
747 kAudioObjectPropertyScopeGlobal,
761 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::SetHogStatus: Setting 'hog' status on device %1")
763 OSStatus err = AudioObjectSetPropertyData(
mDeviceID, &pa, 0,
nullptr,
765 if (err ||
mHog != getpid())
767 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:SetHogStatus: Unable to set 'hog' status. Error = [%1]")
771 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::SetHogStatus: Successfully set 'hog' status on device %1")
779 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::SetHogStatus: Releasing 'hog' status on device %1")
782 OSStatus err = AudioObjectSetPropertyData(
mDeviceID, &pa, 0,
nullptr,
783 sizeof(hogPid), &hogPid);
784 if (err || hogPid == getpid())
786 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:SetHogStatus: Unable to release 'hog' status. Error = [%1]")
803 UInt32 mixEnable = mix ? 1 : 0;
804 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::SetMixingSupport: %1abling mixing for device %2")
805 .arg(mix ?
"En" :
"Dis")
808 AudioObjectPropertyAddress pa
810 kAudioDevicePropertySupportsMixing,
811 kAudioObjectPropertyScopeGlobal,
814 OSStatus err = AudioObjectSetPropertyData(
mDeviceID, &pa, 0,
nullptr,
815 sizeof(mixEnable), &mixEnable);
818 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:SetMixingSupport: Unable to set MixingSupport to %1. Error = [%2]")
819 .arg(mix ?
"'On'" :
"'Off'")
833 UInt32 size =
sizeof(val);
834 AudioObjectPropertyAddress pa
836 kAudioDevicePropertySupportsMixing,
837 kAudioObjectPropertyScopeGlobal,
840 OSStatus err = AudioObjectGetPropertyData(
mDeviceID, &pa, 0,
nullptr,
856 AudioObjectPropertyAddress pa
858 kAudioDevicePropertyStreams,
859 kAudioObjectPropertyScopeGlobal,
863 err = AudioObjectGetPropertyDataSize(
d, &pa,
864 0,
nullptr, &listSize);
867 LOG(VB_GENERAL, LOG_ERR, QString(
"CoreAudioData Error:StreamsList: could not get list size: [%1]")
875 vec.resize(listSize /
sizeof(AudioStreamID));
879 LOG(VB_GENERAL, LOG_ERR,
"CoreAudioData Error:StreamsList(): out of memory?");
883 err = AudioObjectGetPropertyData(
d, &pa,
884 0,
nullptr, &listSize, vec.data());
887 LOG(VB_GENERAL, LOG_ERR, QString(
"CoreAudioData Error:StreamsList: could not get list: [%1]")
901 AudioObjectPropertyAddress pa
904 kAudioStreamPropertyAvailablePhysicalFormats,
905 kAudioObjectPropertyScopeGlobal,
910 err = AudioObjectGetPropertyDataSize(s, &pa, 0,
nullptr, &listSize);
913 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:FormatsList(): couldn't get list size: [%1]")
920 vec.resize(listSize /
sizeof(AudioStreamRangedDescription));
924 LOG(VB_GENERAL, LOG_ERR,
"CoreAudioData Error:FormatsList(): out of memory?");
928 err = AudioObjectGetPropertyData(s, &pa, 0,
nullptr, &listSize, vec.data());
931 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:FormatsList: couldn't get list: [%1]")
941 8000.0, 11025.0, 12000.0,
942 16000.0, 22050.0, 24000.0,
943 32000.0, 44100.0, 48000.0,
944 64000.0, 88200.0, 96000.0,
945 128000.0, 176400.0, 192000.0 };
949 bool theAnswer =
false;
964 AudioObjectPropertyAddress pa
966 kAudioDevicePropertyAvailableNominalSampleRates,
967 kAudioObjectPropertyScopeGlobal,
972 err = AudioObjectGetPropertyDataSize(
d, &pa, 0,
nullptr, &listSize);
975 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:RatesList(): couldn't get data rate list size: [%1]")
982 ranges.resize(listSize /
sizeof(AudioValueRange));
983 finalvec.reserve(listSize /
sizeof(AudioValueRange));
987 LOG(VB_GENERAL, LOG_ERR,
"CoreAudioData Error:RatesList(): out of memory?");
991 err = AudioObjectGetPropertyData(
d, &pa, 0,
nullptr, &listSize, ranges.data());
994 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:RatesList(): couldn't get list: [%1]")
1000 UInt32 theFirstIndex = 0;
1001 UInt32 theLastIndex = 0;
1002 for(
auto range : ranges)
1004 theFirstIndex = theLastIndex;
1012 theLastIndex = theFirstIndex;
1020 finalvec.push_back(range.mMinimum);
1022 finalvec.push_back(range.mMaximum);
1032 bool founddigital =
false;
1037 if (streams.empty())
1042 for (
auto stream : streams)
1051 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::ChannelsList: (passthru) found format: %1")
1055 chans[format.mFormat.mChannelsPerFrame-1] =
true;
1057 if (format.mFormat.mFormatID ==
'IAC3' ||
1058 format.mFormat.mFormatID == kAudioFormat60958AC3)
1064 founddigital =
true;
1072 for (
auto stream : streams)
1079 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::ChannelsList: (!founddigital) found format: %1")
1082 chans[format.mFormat.mChannelsPerFrame-1] =
true;
1091 AudioComponentDescription desc;
1092 AudioStreamBasicDescription DeviceFormat;
1093 AudioChannelLayout new_layout;
1095 AudioObjectPropertyAddress pa
1097 kAudioHardwarePropertyDevices,
1098 kAudioObjectPropertyScopeGlobal,
1102 LOG(VB_AUDIO, LOG_INFO,
"CoreAudioData::OpenAnalog: Entering");
1104 desc.componentType = kAudioUnitType_Output;
1107 desc.componentSubType = kAudioUnitSubType_DefaultOutput;
1111 desc.componentSubType = kAudioUnitSubType_HALOutput;
1113 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
1114 desc.componentFlags = 0;
1115 desc.componentFlagsMask = 0;
1118 AudioComponent comp = AudioComponentFindNext(
nullptr, &desc);
1119 if (comp ==
nullptr)
1121 LOG(VB_GENERAL, LOG_ERR,
"CoreAudioData Error:OpenAnalog: AudioComponentFindNext failed");
1125 OSErr err = AudioComponentInstanceNew(comp, &
mOutputUnit);
1128 LOG(VB_GENERAL, LOG_ERR, QString(
"CoreAudioData Error:OpenAnalog: AudioComponentInstanceNew returned %1")
1135 UInt32 size_hasIO =
sizeof(hasIO);
1137 kAudioOutputUnitProperty_HasIO,
1138 kAudioUnitScope_Output,
1140 &hasIO, &size_hasIO);
1141 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::OpenAnalog: HasIO (output) = %1").arg(hasIO));
1144 UInt32 enableIO = 1;
1146 kAudioOutputUnitProperty_EnableIO,
1147 kAudioUnitScope_Global,
1149 &enableIO,
sizeof(enableIO));
1152 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:OpenAnalog: failed enabling IO: %1")
1157 kAudioOutputUnitProperty_HasIO,
1158 kAudioUnitScope_Output,
1160 &hasIO, &size_hasIO);
1161 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::HasIO = %1").arg(hasIO));
1171 kAudioOutputUnitProperty_CurrentDevice,
1172 kAudioUnitScope_Global,
1177 LOG(VB_GENERAL, LOG_ERR, QString(
"CoreAudioData Error:OpenAnalog: Unable to set current device to %1. Error = %2")
1184 UInt32 param_size =
sizeof(AudioStreamBasicDescription);
1187 kAudioUnitProperty_StreamFormat,
1188 kAudioUnitScope_Input,
1194 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:OpenAnalog: Unable to retrieve current stream format: [%1]")
1199 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::OpenAnalog: current format is: %1")
1203 pa.mSelector = kAudioDevicePropertyPreferredChannelLayout;
1204 err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &pa,
1205 0,
nullptr, ¶m_size);
1209 std::vector<char> layoutBuffer (param_size);
1210 auto *layout = (AudioChannelLayout *)layoutBuffer.data();
1211 err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &pa,
1212 0,
nullptr, ¶m_size, layout);
1215 if(layout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap)
1218 err = AudioFormatGetProperty(kAudioFormatProperty_ChannelLayoutForBitmap,
1219 sizeof(UInt32), &layout->mChannelBitmap,
1223 LOG(VB_GENERAL, LOG_WARNING,
"CoreAudioData Warning:OpenAnalog: Can't retrieve current channel layout");
1225 else if(layout->mChannelLayoutTag != kAudioChannelLayoutTag_UseChannelDescriptions )
1228 err = AudioFormatGetProperty(kAudioFormatProperty_ChannelLayoutForTag,
1229 sizeof(AudioChannelLayoutTag),
1230 &layout->mChannelLayoutTag,
1234 LOG(VB_GENERAL, LOG_WARNING,
"CoreAudioData Warning:OpenAnalog: Can't retrieve current channel layout");
1237 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::OpenAnalog: Layout of AUHAL has %1 channels")
1238 .arg(layout->mNumberChannelDescriptions));
1240 int channels_found = 0;
1241 for(UInt32 i = 0; i < layout->mNumberChannelDescriptions; i++)
1243 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::OpenAnalog: this is channel: %1")
1244 .arg(layout->mChannelDescriptions[i].mChannelLabel));
1246 switch( layout->mChannelDescriptions[i].mChannelLabel)
1248 case kAudioChannelLabel_Left:
1249 case kAudioChannelLabel_Right:
1250 case kAudioChannelLabel_Center:
1251 case kAudioChannelLabel_LFEScreen:
1252 case kAudioChannelLabel_LeftSurround:
1253 case kAudioChannelLabel_RightSurround:
1254 case kAudioChannelLabel_RearSurroundLeft:
1255 case kAudioChannelLabel_RearSurroundRight:
1256 case kAudioChannelLabel_CenterSurround:
1260 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::unrecognized channel form provided by driver: %1")
1261 .arg(layout->mChannelDescriptions[i].mChannelLabel));
1264 if(channels_found == 0)
1266 LOG(VB_GENERAL, LOG_WARNING,
"CoreAudioData Warning:Audio device is not configured. "
1267 "You should configure your speaker layout with "
1268 "the \"Audio Midi Setup\" utility in /Applications/"
1274 LOG(VB_GENERAL, LOG_WARNING,
"CoreAudioData Warning:this driver does not support kAudioDevicePropertyPreferredChannelLayout.");
1277 memset (&new_layout, 0,
sizeof(new_layout));
1281 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_Mono;
1284 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo;
1288 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_AudioUnit_5_1;
1294 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_MPEG_7_1_A;
1299 kAudioUnitProperty_AudioChannelLayout,
1300 kAudioUnitScope_Input,
1302 &new_layout,
sizeof(new_layout));
1305 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:OpenAnalog: couldn't set channels layout [%1]")
1309 if(new_layout.mNumberChannelDescriptions > 0)
1313 free(new_layout.mChannelDescriptions);
1317 int formatFlags = 0;
1321 formatFlags = kLinearPCMFormatFlagIsSignedInteger;
1324 formatFlags = kLinearPCMFormatFlagIsFloat;
1327 formatFlags = kLinearPCMFormatFlagIsSignedInteger;
1331 AudioStreamBasicDescription conv_in_desc;
1332 memset(&conv_in_desc, 0,
sizeof(AudioStreamBasicDescription));
1334 conv_in_desc.mFormatID = kAudioFormatLinearPCM;
1335 conv_in_desc.mFormatFlags = formatFlags |
1336 kAudioFormatFlagsNativeEndian |
1337 kLinearPCMFormatFlagIsPacked;
1340 conv_in_desc.mFramesPerPacket = 1;
1343 conv_in_desc.mBitsPerChannel =
1348 kAudioUnitProperty_StreamFormat,
1349 kAudioUnitScope_Input,
1352 sizeof(AudioStreamBasicDescription));
1355 LOG(VB_GENERAL, LOG_ERR, QString(
"CoreAudioData Error:OpenAnalog: AudioUnitSetProperty returned [%1]")
1359 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::OpenAnalog: set format as %1")
1363 kAudioUnitProperty_StreamFormat,
1364 kAudioUnitScope_Input,
1369 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::OpenAnalog: the actual set AU format is %1")
1373 AURenderCallbackStruct input;
1375 input.inputProcRefCon =
this;
1378 kAudioUnitProperty_SetRenderCallback,
1379 kAudioUnitScope_Input,
1380 0, &input,
sizeof(input));
1383 LOG(VB_GENERAL, LOG_ERR, QString(
"CoreAudioData Error:OpenAnalog: AudioUnitSetProperty (callback) returned [%1]")
1390 ComponentResult res = AudioUnitInitialize(
mOutputUnit);
1393 LOG(VB_GENERAL, LOG_ERR, QString(
"CoreAudioData Error:OpenAnalog: AudioUnitInitialize error: [%1]")
1402 LOG(VB_GENERAL, LOG_ERR, QString(
"CoreAudioData Error:OpenAnalog: AudioOutputUnitStart error: [%1]")
1414 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::CloseAnalog: Entering: %1")
1421 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::CloseAnalog: AudioOutputUnitStop %1")
1427 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::CloseAnalog: AudioUnitUninitialize %1")
1431 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::CloseAnalog: CloseComponent %1")
1445 AudioStreamBasicDescription outputFormat {};
1447 LOG(VB_AUDIO, LOG_INFO,
"CoreAudioData::OpenSPDIF: Entering");
1450 if (streams.empty())
1452 LOG(VB_GENERAL, LOG_WARNING,
"CoreAudioData Warning:OpenSPDIF: Couldn't retrieve list of streams");
1456 for (
size_t i = 0; i < streams.size(); ++i)
1465 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::OpenSPDIF: Considering Physical Format: %1")
1467 if ((format.mFormat.mFormatID ==
'IAC3' ||
1468 format.mFormat.mFormatID == kAudioFormat60958AC3) &&
1471 LOG(VB_AUDIO, LOG_INFO,
"CoreAudioData::OpenSPDIF: Found digital format");
1474 outputFormat = format.mFormat;
1478 if (outputFormat.mFormatID)
1482 if (!outputFormat.mFormatID)
1484 LOG(VB_GENERAL, LOG_ERR, QString(
"CoreAudioData Error:OpenSPDIF: Couldn't find suitable output"));
1490 AudioObjectPropertyAddress pa
1492 kAudioStreamPropertyPhysicalFormat,
1493 kAudioObjectPropertyScopeGlobal,
1500 err = AudioObjectGetPropertyData(
mStreamID, &pa, 0,
nullptr,
1504 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:OpenSPDIF - could not retrieve the original streamformat: [%1]")
1533 err = AudioDeviceCreateIOProcID(
mDeviceID,
1538 LOG(VB_GENERAL, LOG_ERR, QString(
"CoreAudioData Error:OpenSPDIF: AudioDeviceCreateIOProcID failed: [%1]")
1548 LOG(VB_GENERAL, LOG_ERR, QString(
"CoreAudioData Error:OpenSPDIF: AudioDeviceStart failed: [%1]")
1560 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::CloseSPDIF: Entering [%1]").arg(
mDigitalInUse));;
1569 LOG(VB_GENERAL, LOG_ERR, QString(
"CoreAudioData Error:CloseSPDIF: AudioDeviceStop failed: [%1]")
1579 LOG(VB_GENERAL, LOG_ERR, QString(
"CoreAudioData Error:CloseSPDIF: AudioDeviceDestroyIOProcID failed: [%1]")
1593 AudioHardwareUnload();
1601 AudioStreamBasicDescription format)
1603 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::AudioStreamChangeFormat: %1 -> %2")
1607 AudioObjectPropertyAddress pa
1609 kAudioStreamPropertyPhysicalFormat,
1610 kAudioObjectPropertyScopeGlobal,
1613 OSStatus err = AudioObjectSetPropertyData(s, &pa, 0,
nullptr,
1614 sizeof(format), &format);
1617 LOG(VB_GENERAL, LOG_ERR, QString(
"CoreAudioData Error:AudioStreamChangeFormat couldn't set stream format: [%1]")
1631 if (streams.empty())
1634 for (
auto stream : streams)
1642 if (format.mFormat.mFormatID ==
'IAC3' ||
1643 format.mFormat.mFormatID == kAudioFormat60958AC3)
1645 LOG(VB_AUDIO, LOG_INFO,
"CoreAudioData::FindAC3Stream: found digital format");
1661 AudioObjectPropertyAddress pa
1663 kAudioHardwarePropertyDevices,
1664 kAudioObjectPropertyScopeGlobal,
1668 OSStatus err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &pa,
1672 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:GetPropertyDataSize: Unable to retrieve the property sizes. "
1678 std::vector<AudioDeviceID> devices = {};
1679 devices.resize(size /
sizeof(AudioDeviceID));
1680 err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &pa,
1681 0,
nullptr, &size, devices.data());
1684 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:GetPropertyData: Unable to retrieve the list of available devices. "
1690 for (
const auto & dev : devices)
1695 if (streams.empty())
1697 for (
auto stream : streams)
1704 AudioStreamBasicDescription currentFormat;
1706 UInt32 paramSize = 0;
1707 AudioObjectPropertyAddress pa
1709 kAudioStreamPropertyPhysicalFormat,
1710 kAudioObjectPropertyScopeGlobal,
1716 paramSize =
sizeof(currentFormat);
1717 AudioObjectGetPropertyData(s, &pa, 0,
nullptr,
1718 ¶mSize, ¤tFormat);
1721 if (currentFormat.mFormatID ==
'IAC3' ||
1722 currentFormat.mFormatID == kAudioFormat60958AC3)
1731 if (format.mFormat.mFormatID == kAudioFormatLinearPCM)
1733 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::ResetStream: Resetting stream %1 to %2").arg(s).arg(
StreamDescriptionToString(format.mFormat)));
1734 err = AudioObjectSetPropertyData(s, &pa, 0,
nullptr,
1735 sizeof(format), &(format.mFormat));
1738 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:ResetStream: could not set physical format: [%1]")
1743 std::this_thread::sleep_for(1s);
1751 auto *devs =
new QMap<QString, QString>();
1756 AudioObjectPropertyAddress pa
1758 kAudioHardwarePropertyDevices,
1759 kAudioObjectPropertyScopeGlobal,
1763 OSStatus err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &pa,
1767 LOG(VB_AUDIO, LOG_INFO,
LOC + QString(
"GetPropertyDataSize: Unable to retrieve the property sizes. "
1773 UInt32 deviceCount = size /
sizeof(AudioDeviceID);
1774 std::vector<AudioDeviceID> devices = {};
1775 devices.resize(deviceCount);
1776 err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &pa,
1777 0,
nullptr, &size, devices.data());
1780 LOG(VB_AUDIO, LOG_INFO,
LOC + QString(
"AudioOutputCA::GetDevices: Unable to retrieve the list of "
1781 "available devices. Error [%1]")
1786 LOG(VB_AUDIO, LOG_INFO,
LOC + QString(
"GetDevices: Number of devices: %1").arg(deviceCount));
1788 for (
const auto & dev : devices)
1793 QString *name = device.
GetName();
1796 devs->insert(*name, QString());
std::vector< AudioStreamID > AudioStreamIDVec
std::vector< AudioValueRange > AudioValueRangeVec
std::vector< AudioStreamRangedDescription > AudioStreamRangedVec
QString StreamDescriptionToString(AudioStreamBasicDescription desc)
static OSStatus RenderCallbackAnalog(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData)
static OSStatus RenderCallbackSPDIF(AudioDeviceID inDevice, const AudioTimeStamp *inNow, const void *inInputData, const AudioTimeStamp *inInputTime, AudioBufferList *outOutputData, const AudioTimeStamp *inOutputTime, void *inRefCon)
static bool IsRateCommon(Float64 inRate)
char * UInt32ToFourCC(const UInt32 *pVal)
std::vector< int > RatesVec
static constexpr UInt32 sNumberCommonSampleRates
static std::array< Float64, sNumberCommonSampleRates > sCommonSampleRates
static constexpr int8_t kMythAudioObjectPropertyElementMain
std::array< bool, CHANNELS_MAX > ChannelsArr
static constexpr int CHANNELS_MAX
static constexpr int CHANNELS_MIN
static void ReorderSmpteToCA(AudioDataType *buf, uint frames)
static const std::array< const std::string, 8 > formats
void KillAudio(void)
Kill the output thread and cleanup.
void Reconfigure(const AudioSettings &settings) override
(Re)Configure AudioOutputBase
AudioFormat m_outputFormat
int m_outputBytesPerFrame
void InitSettings(const AudioSettings &settings)
std::chrono::milliseconds GetBaseAudBufTimeCode() const
int GetAudioData(uchar *buffer, int buf_size, bool full_buffer, volatile uint *local_raud=nullptr)
Copy frames from the audiobuffer into the buffer provided.
int audioready() const
Get the scaled number of bytes in the audiobuffer, i.e.
Implements Core Audio (Mac OS X Hardware Abstraction Layer) output.
friend class CoreAudioData
std::chrono::milliseconds GetAudiotime(void) override
Reimplement the base class's version of GetAudiotime() so that we don't use gettimeofday or Qt mutexe...
int GetVolumeChannel(int channel) const override
void CloseDevice(void) override
void SetVolumeChannel(int channel, int volume) override
void WriteAudio(unsigned char *aubuf, int size) override
int GetBufferedOnSoundcard(void) const override
Return the size in bytes of frames currently in the audio buffer adjusted with the audio playback lat...
AudioOutputSettings * GetOutputSettings(bool digital) override
static QMap< QString, QString > * GetDevices(const char *type=nullptr)
AudioOutputCA(const AudioSettings &settings)
bool OpenDevice(void) override
bool RenderAudio(unsigned char *aubuf, int size, unsigned long long timestamp)
Object-oriented part of callback.
static int FormatToBits(AudioFormat format)
const int & channels() const
bool m_init
If set to false, AudioOutput instance will not try to initially open the audio device.
This holds Core Audio member variables and low-level audio IO methods The name is now a misnomer,...
static void SetAutoHogMode(bool enable)
static AudioDeviceID GetDeviceWithName(const QString &deviceName)
AudioStreamBasicDescription mFormatOrig
static AudioStreamRangedVec FormatsList(AudioStreamID s)
static AudioDeviceID GetDefaultOutputDevice()
AudioDeviceIOProcID mIoProcID
static pid_t GetHogStatus()
static RatesVec RatesList(AudioDeviceID d)
static AudioStreamIDVec StreamsList(AudioDeviceID d)
Get a list of all the streams on this device.
QString * GetName() const
int GetTotalOutputChannels() const
static int AudioStreamChangeFormat(AudioStreamID s, AudioStreamBasicDescription format)
bool ChannelsList(AudioDeviceID d, bool passthru, ChannelsArr &chans) const
bool FindAC3Stream() const
static bool GetAutoHogMode()
bool SetHogStatus(bool hog)
bool SetMixingSupport(bool mix)
AudioStreamBasicDescription mFormatNew
CoreAudioData(AudioOutputCA *parent)
static void ResetStream(AudioStreamID s)
static void ResetAudioDevices()
Reset any devices with an AC3 stream back to a Linear PCM so that they can become a default output de...
bool GetMixingSupport() const
QString GetSetting(const QString &key, const QString &defaultval="")
int GetNumSetting(const QString &key, int defaultval=0)
Contains Packet Identifier numeric values.
virtual void SetCurrentVolume(int value)
static const iso6937table * d
std::chrono::milliseconds millisecondsFromFloat(T value)
Helper function for convert a floating point number to a duration.
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)