19#include <CoreServices/CoreServices.h>
20#include <CoreAudio/CoreAudio.h>
21#include <AudioUnit/AudioUnit.h>
22#include <AudioToolbox/AudioFormat.h>
23#include <AvailabilityMacros.h>
33#define LOC QString("CoreAudio: ")
44#define OSS_STATUS(x) UInt32ToFourCC((UInt32*)&(x))
48 char* pIn = (
char*)&inVal;
49 static char fourCC[5];
60 UInt32 formatId = desc.mFormatID;
64 switch (desc.mFormatID)
66 case kAudioFormatLinearPCM:
67 str = QString(
"[%1] %2%3 Channel %4-bit %5 %6 (%7Hz) %8 Channels")
69 .arg((desc.mFormatFlags & kAudioFormatFlagIsNonMixable) ?
"" :
"Mixable ")
70 .arg(desc.mChannelsPerFrame)
71 .arg(desc.mBitsPerChannel)
72 .arg((desc.mFormatFlags & kAudioFormatFlagIsFloat) ?
"Floating Point" :
"Signed Integer")
73 .arg((desc.mFormatFlags & kAudioFormatFlagIsBigEndian) ?
"BE" :
"LE")
74 .arg((UInt32)desc.mSampleRate)
75 .arg(desc.mChannelsPerFrame);
78 str = QString(
"[%1] AC-3/DTS (%2Hz) %3 Channels")
80 .arg((UInt32)desc.mSampleRate)
81 .arg(desc.mChannelsPerFrame);
83 case kAudioFormat60958AC3:
84 str = QString(
"[%1] AC-3/DTS for S/PDIF %2 (%3Hz) %4 Channels")
86 .arg((desc.mFormatFlags & kAudioFormatFlagIsBigEndian) ?
"BE" :
"LE")
87 .arg((UInt32)desc.mSampleRate)
88 .arg(desc.mChannelsPerFrame);
91 str = QString(
"[%1]").arg(fourCC);
135 AudioStreamBasicDescription format);
162 AudioUnitRenderActionFlags *ioActionFlags,
163 const AudioTimeStamp *inTimeStamp,
165 UInt32 inNumberFrames,
166 AudioBufferList *ioData);
168 const AudioTimeStamp *inNow,
169 const void *inInputData,
170 const AudioTimeStamp *inInputTime,
171 AudioBufferList *outOutputData,
172 const AudioTimeStamp *inOutputTime,
183 LOG(VB_AUDIO, LOG_INFO,
LOC + QString(
"AudioOutputCA::AudioOutputCA searching %1").arg(
m_mainDevice));
208 settings->AddSupportedRate(48000);
212 while (
int rate = settings->GetNextRate())
214 for (
auto entry : rates)
218 settings->AddSupportedRate(entry);
231 settings->AddSupportedChannels(2);
239 LOG(VB_AUDIO, LOG_INFO, QString(
"AudioOutputCA::Support %1 channels").arg(i));
242 settings->AddSupportedChannels(6);
243 settings->AddSupportedChannels(i);
250 settings->setPassthrough(1);
257 bool deviceOpened =
false;
262 LOG(VB_AUDIO, LOG_INFO,
"AudioOutputCA::OpenDevice: Entering");
265 LOG(VB_AUDIO, LOG_INFO,
"AudioOutputCA::OpenDevice() Trying Digital.");
272 LOG(VB_AUDIO, LOG_INFO,
"AudioOutputCA::OpenDevice() Trying Analog.");
277 LOG(VB_AUDIO, LOG_INFO, QString(
"AudioOutputCA::OpenDevice: OpenAnalog = %1").arg(result));
281 std::this_thread::sleep_for(1s);
284 deviceOpened = (result > 0);
289 LOG(VB_GENERAL, LOG_ERR,
"AudioOutputCA Error: Couldn't open any audio device!");
297 controlLabel +=
"MixerVolume";
306 LOG(VB_AUDIO, LOG_INFO,
LOC + QString(
"CloseDevice [%1]: Entering")
314template <
class AudioDataType>
319 AudioDataType tmpRLs;
320 AudioDataType tmpRRs;
322 for (
uint i = 0; i < frames; i++)
324 buf = buf2 = buf + 4;
349 int size,
unsigned long long timestamp)
365 if (written_size && (size > written_size))
368 memset(aubuf + written_size, 0, size - written_size);
378 UInt64 nanos = AudioConvertHostTimeToNanos(timestamp -
379 AudioGetCurrentHostTime());
384 return (written_size > 0);
389 [[maybe_unused]]
int size)
405 if (audbuf_timecode == 0ms)
417 AudioUnitRenderActionFlags *ioActionFlags,
418 const AudioTimeStamp *inTimeStamp,
419 [[maybe_unused]] UInt32 inBusNumber,
420 [[maybe_unused]] UInt32 inNumberFrames,
421 AudioBufferList *ioData)
425 if (!inst->
RenderAudio((
unsigned char *)(ioData->mBuffers[0].mData),
426 ioData->mBuffers[0].mDataByteSize,
427 inTimeStamp->mHostTime))
430 memset(ioData->mBuffers[0].mData, 0, ioData->mBuffers[0].mDataByteSize);
431 *ioActionFlags = kAudioUnitRenderAction_OutputIsSilence;
442 kHALOutputParam_Volume,
443 kAudioUnitScope_Global, 0, &volume))
444 return (
int)lroundf(volume * 100.0F);
452 AudioUnitSetParameter(
d->
mOutputUnit, kHALOutputParam_Volume,
453 kAudioUnitScope_Global, 0, (volume * 0.01F), 0);
458 [[maybe_unused]]
const AudioTimeStamp *inNow,
459 [[maybe_unused]]
const void *inInputData,
460 [[maybe_unused]]
const AudioTimeStamp *inInputTime,
461 AudioBufferList *outOutputData,
462 const AudioTimeStamp *inOutputTime,
467 int index =
d->mStreamIndex;
473 if (
d->mBytesPerPacket > 0 &&
474 outOutputData->mBuffers[index].mDataByteSize >
d->mBytesPerPacket)
476 outOutputData->mBuffers[index].mDataByteSize =
d->mBytesPerPacket;
478 if (!a->
RenderAudio((
unsigned char *)(outOutputData->mBuffers[index].mData),
479 outOutputData->mBuffers[index].mDataByteSize,
480 inOutputTime->mHostTime))
483 memset(outOutputData->mBuffers[index].mData, 0,
484 outOutputData->mBuffers[index].mDataByteSize);
515 if (deviceName !=
"Default Output Device")
517 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:CoreAudioData: \"%1\" not found, using default device %2.")
521 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::CoreAudioData: device number is %1")
528 AudioDeviceID deviceID = 0;
529 AudioObjectPropertyAddress pa
531 kAudioHardwarePropertyDevices,
532 kAudioObjectPropertyScopeGlobal,
536 OSStatus err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &pa,
540 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:GetPropertyDataSize: Unable to retrieve the property sizes. "
546 UInt32 deviceCount = size /
sizeof(AudioDeviceID);
547 std::vector<AudioDeviceID> devices = {};
548 devices.resize(deviceCount);
550 err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &pa,
551 0,
nullptr, &size, devices.data());
554 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:GetDeviceWithName: Unable to retrieve the list of available devices. "
560 for (
const auto & dev : devices)
565 QString *name = device.
GetName();
566 if (name && *name == deviceName)
568 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::GetDeviceWithName: Found: %1").arg(*name));
582 AudioDeviceID deviceId = 0;
583 AudioObjectPropertyAddress pa
585 kAudioHardwarePropertyDefaultOutputDevice,
586 kAudioObjectPropertyScopeGlobal,
591 paramSize =
sizeof(deviceId);
592 OSStatus err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &pa,
593 0,
nullptr, ¶mSize, &deviceId);
595 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::GetDefaultOutputDevice: default device ID = %1").arg(deviceId));
598 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:GetDefaultOutputDevice: could not get default audio device: [%1]")
611 AudioObjectPropertyAddress pa
613 kAudioDevicePropertyStreamConfiguration,
614 kAudioDevicePropertyScopeOutput,
618 OSStatus err = AudioObjectGetPropertyDataSize(
mDeviceID, &pa,
622 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:GetTotalOutputChannels: Unable to get "
623 "size of device output channels - id: %1 Error = [%2]")
629 auto *pList = (AudioBufferList *)malloc(size);
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));
655 AudioObjectPropertyAddress pa
657 kAudioObjectPropertyName,
658 kAudioObjectPropertyScopeGlobal,
663 UInt32 propertySize =
sizeof(CFStringRef);
664 OSStatus err = AudioObjectGetPropertyData(
mDeviceID, &pa,
665 0,
nullptr, &propertySize, &name);
668 LOG(VB_GENERAL, LOG_ERR, QString(
"CoreAudioData Error:AudioObjectGetPropertyData for kAudioObjectPropertyName error: [%1]")
672 char *cname =
new char[CFStringGetLength(name) + 1];
673 CFStringGetCString(name, cname, CFStringGetLength(name) + 1, kCFStringEncodingUTF8);
674 auto *qname =
new QString(cname);
682 UInt32 size =
sizeof(val);
683 AudioObjectPropertyAddress pa
685 kAudioHardwarePropertyHogModeIsAllowed,
686 kAudioObjectPropertyScopeGlobal,
690 OSStatus err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &pa, 0,
nullptr, &size, &val);
693 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:GetAutoHogMode: Unable to get auto 'hog' mode. Error = [%1]")
702 UInt32 val = enable ? 1 : 0;
703 AudioObjectPropertyAddress pa
705 kAudioHardwarePropertyHogModeIsAllowed,
706 kAudioObjectPropertyScopeGlobal,
710 OSStatus err = AudioObjectSetPropertyData(kAudioObjectSystemObject, &pa, 0,
nullptr,
714 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:SetAutoHogMode: Unable to set auto 'hog' mode. Error = [%1]")
722 UInt32 PIDsize =
sizeof(
PID);
723 AudioObjectPropertyAddress pa
725 kAudioDevicePropertyHogMode,
726 kAudioObjectPropertyScopeGlobal,
730 OSStatus err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &pa, 0,
nullptr,
736 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::GetHogStatus: unable to check: [%1]")
745 AudioObjectPropertyAddress pa
747 kAudioDevicePropertyHogMode,
748 kAudioObjectPropertyScopeGlobal,
762 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::SetHogStatus: Setting 'hog' status on device %1")
764 OSStatus err = AudioObjectSetPropertyData(
mDeviceID, &pa, 0,
nullptr,
766 if (err ||
mHog != getpid())
768 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:SetHogStatus: Unable to set 'hog' status. Error = [%1]")
772 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::SetHogStatus: Successfully set 'hog' status on device %1")
780 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::SetHogStatus: Releasing 'hog' status on device %1")
783 OSStatus err = AudioObjectSetPropertyData(
mDeviceID, &pa, 0,
nullptr,
784 sizeof(hogPid), &hogPid);
785 if (err || hogPid == getpid())
787 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:SetHogStatus: Unable to release 'hog' status. Error = [%1]")
804 UInt32 mixEnable = mix ? 1 : 0;
805 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::SetMixingSupport: %1abling mixing for device %2")
806 .arg(mix ?
"En" :
"Dis")
809 AudioObjectPropertyAddress pa
811 kAudioDevicePropertySupportsMixing,
812 kAudioObjectPropertyScopeGlobal,
815 OSStatus err = AudioObjectSetPropertyData(
mDeviceID, &pa, 0,
nullptr,
816 sizeof(mixEnable), &mixEnable);
819 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:SetMixingSupport: Unable to set MixingSupport to %1. Error = [%2]")
820 .arg(mix ?
"'On'" :
"'Off'")
834 UInt32 size =
sizeof(val);
835 AudioObjectPropertyAddress pa
837 kAudioDevicePropertySupportsMixing,
838 kAudioObjectPropertyScopeGlobal,
841 OSStatus err = AudioObjectGetPropertyData(
mDeviceID, &pa, 0,
nullptr,
857 AudioObjectPropertyAddress pa
859 kAudioDevicePropertyStreams,
860 kAudioObjectPropertyScopeGlobal,
864 err = AudioObjectGetPropertyDataSize(
d, &pa,
865 0,
nullptr, &listSize);
868 LOG(VB_GENERAL, LOG_ERR, QString(
"CoreAudioData Error:StreamsList: could not get list size: [%1]")
876 vec.resize(listSize /
sizeof(AudioStreamID));
880 LOG(VB_GENERAL, LOG_ERR,
"CoreAudioData Error:StreamsList(): out of memory?");
884 err = AudioObjectGetPropertyData(
d, &pa,
885 0,
nullptr, &listSize, vec.data());
888 LOG(VB_GENERAL, LOG_ERR, QString(
"CoreAudioData Error:StreamsList: could not get list: [%1]")
902 AudioObjectPropertyAddress pa
905 kAudioStreamPropertyAvailablePhysicalFormats,
906 kAudioObjectPropertyScopeGlobal,
911 err = AudioObjectGetPropertyDataSize(s, &pa, 0,
nullptr, &listSize);
914 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:FormatsList(): couldn't get list size: [%1]")
921 vec.resize(listSize /
sizeof(AudioStreamRangedDescription));
925 LOG(VB_GENERAL, LOG_ERR,
"CoreAudioData Error:FormatsList(): out of memory?");
929 err = AudioObjectGetPropertyData(s, &pa, 0,
nullptr, &listSize, vec.data());
932 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:FormatsList: couldn't get list: [%1]")
942 8000.0, 11025.0, 12000.0,
943 16000.0, 22050.0, 24000.0,
944 32000.0, 44100.0, 48000.0,
945 64000.0, 88200.0, 96000.0,
946 128000.0, 176400.0, 192000.0 };
950 bool theAnswer =
false;
965 AudioObjectPropertyAddress pa
967 kAudioDevicePropertyAvailableNominalSampleRates,
968 kAudioObjectPropertyScopeGlobal,
973 err = AudioObjectGetPropertyDataSize(
d, &pa, 0,
nullptr, &listSize);
976 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:RatesList(): couldn't get data rate list size: [%1]")
983 ranges.resize(listSize /
sizeof(AudioValueRange));
984 finalvec.reserve(listSize /
sizeof(AudioValueRange));
988 LOG(VB_GENERAL, LOG_ERR,
"CoreAudioData Error:RatesList(): out of memory?");
992 err = AudioObjectGetPropertyData(
d, &pa, 0,
nullptr, &listSize, ranges.data());
995 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:RatesList(): couldn't get list: [%1]")
1001 UInt32 theFirstIndex;
1002 UInt32 theLastIndex = 0;
1003 for(
auto range : ranges)
1005 theFirstIndex = theLastIndex;
1013 theLastIndex = theFirstIndex;
1021 finalvec.push_back(range.mMinimum);
1023 finalvec.push_back(range.mMaximum);
1033 bool founddigital =
false;
1038 if (streams.empty())
1043 for (
auto stream : streams)
1052 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::ChannelsList: (passthru) found format: %1")
1056 chans[format.mFormat.mChannelsPerFrame-1] =
true;
1058 if (format.mFormat.mFormatID ==
'IAC3' ||
1059 format.mFormat.mFormatID == kAudioFormat60958AC3)
1065 founddigital =
true;
1073 for (
auto stream : streams)
1080 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::ChannelsList: (!founddigital) found format: %1")
1083 chans[format.mFormat.mChannelsPerFrame-1] =
true;
1092 AudioComponentDescription desc;
1093 AudioStreamBasicDescription DeviceFormat;
1094 AudioChannelLayout *layout;
1095 AudioChannelLayout new_layout;
1097 AudioObjectPropertyAddress pa
1099 kAudioHardwarePropertyDevices,
1100 kAudioObjectPropertyScopeGlobal,
1104 LOG(VB_AUDIO, LOG_INFO,
"CoreAudioData::OpenAnalog: Entering");
1106 desc.componentType = kAudioUnitType_Output;
1109 desc.componentSubType = kAudioUnitSubType_DefaultOutput;
1113 desc.componentSubType = kAudioUnitSubType_HALOutput;
1115 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
1116 desc.componentFlags = 0;
1117 desc.componentFlagsMask = 0;
1120 AudioComponent comp = AudioComponentFindNext(
nullptr, &desc);
1121 if (comp ==
nullptr)
1123 LOG(VB_GENERAL, LOG_ERR,
"CoreAudioData Error:OpenAnalog: AudioComponentFindNext failed");
1127 OSErr err = AudioComponentInstanceNew(comp, &
mOutputUnit);
1130 LOG(VB_GENERAL, LOG_ERR, QString(
"CoreAudioData Error:OpenAnalog: AudioComponentInstanceNew returned %1")
1137 UInt32 size_hasIO =
sizeof(hasIO);
1139 kAudioOutputUnitProperty_HasIO,
1140 kAudioUnitScope_Output,
1142 &hasIO, &size_hasIO);
1143 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::OpenAnalog: HasIO (output) = %1").arg(hasIO));
1146 UInt32 enableIO = 1;
1148 kAudioOutputUnitProperty_EnableIO,
1149 kAudioUnitScope_Global,
1151 &enableIO,
sizeof(enableIO));
1154 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:OpenAnalog: failed enabling IO: %1")
1159 kAudioOutputUnitProperty_HasIO,
1160 kAudioUnitScope_Output,
1162 &hasIO, &size_hasIO);
1163 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::HasIO = %1").arg(hasIO));
1173 kAudioOutputUnitProperty_CurrentDevice,
1174 kAudioUnitScope_Global,
1179 LOG(VB_GENERAL, LOG_ERR, QString(
"CoreAudioData Error:OpenAnalog: Unable to set current device to %1. Error = %2")
1186 UInt32 param_size =
sizeof(AudioStreamBasicDescription);
1189 kAudioUnitProperty_StreamFormat,
1190 kAudioUnitScope_Input,
1196 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:OpenAnalog: Unable to retrieve current stream format: [%1]")
1201 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::OpenAnalog: current format is: %1")
1205 pa.mSelector = kAudioDevicePropertyPreferredChannelLayout;
1206 err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &pa,
1207 0,
nullptr, ¶m_size);
1211 layout = (AudioChannelLayout *) malloc(param_size);
1213 err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &pa,
1214 0,
nullptr, ¶m_size, layout);
1217 if(layout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap)
1220 err = AudioFormatGetProperty(kAudioFormatProperty_ChannelLayoutForBitmap,
1221 sizeof(UInt32), &layout->mChannelBitmap,
1225 LOG(VB_GENERAL, LOG_WARNING,
"CoreAudioData Warning:OpenAnalog: Can't retrieve current channel layout");
1227 else if(layout->mChannelLayoutTag != kAudioChannelLayoutTag_UseChannelDescriptions )
1230 err = AudioFormatGetProperty(kAudioFormatProperty_ChannelLayoutForTag,
1231 sizeof(AudioChannelLayoutTag),
1232 &layout->mChannelLayoutTag,
1236 LOG(VB_GENERAL, LOG_WARNING,
"CoreAudioData Warning:OpenAnalog: Can't retrieve current channel layout");
1239 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::OpenAnalog: Layout of AUHAL has %1 channels")
1240 .arg(layout->mNumberChannelDescriptions));
1242 int channels_found = 0;
1243 for(UInt32 i = 0; i < layout->mNumberChannelDescriptions; i++)
1245 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::OpenAnalog: this is channel: %1")
1246 .arg(layout->mChannelDescriptions[i].mChannelLabel));
1248 switch( layout->mChannelDescriptions[i].mChannelLabel)
1250 case kAudioChannelLabel_Left:
1251 case kAudioChannelLabel_Right:
1252 case kAudioChannelLabel_Center:
1253 case kAudioChannelLabel_LFEScreen:
1254 case kAudioChannelLabel_LeftSurround:
1255 case kAudioChannelLabel_RightSurround:
1256 case kAudioChannelLabel_RearSurroundLeft:
1257 case kAudioChannelLabel_RearSurroundRight:
1258 case kAudioChannelLabel_CenterSurround:
1262 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::unrecognized channel form provided by driver: %1")
1263 .arg(layout->mChannelDescriptions[i].mChannelLabel));
1266 if(channels_found == 0)
1268 LOG(VB_GENERAL, LOG_WARNING,
"CoreAudioData Warning:Audio device is not configured. "
1269 "You should configure your speaker layout with "
1270 "the \"Audio Midi Setup\" utility in /Applications/"
1277 LOG(VB_GENERAL, LOG_WARNING,
"CoreAudioData Warning:this driver does not support kAudioDevicePropertyPreferredChannelLayout.");
1280 memset (&new_layout, 0,
sizeof(new_layout));
1284 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_Mono;
1287 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo;
1291 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_AudioUnit_5_1;
1297 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_MPEG_7_1_A;
1302 kAudioUnitProperty_AudioChannelLayout,
1303 kAudioUnitScope_Input,
1305 &new_layout,
sizeof(new_layout));
1308 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:OpenAnalog: couldn't set channels layout [%1]")
1312 if(new_layout.mNumberChannelDescriptions > 0)
1313 free(new_layout.mChannelDescriptions);
1320 formatFlags = kLinearPCMFormatFlagIsSignedInteger;
1323 formatFlags = kLinearPCMFormatFlagIsFloat;
1326 formatFlags = kLinearPCMFormatFlagIsSignedInteger;
1330 AudioStreamBasicDescription conv_in_desc;
1331 memset(&conv_in_desc, 0,
sizeof(AudioStreamBasicDescription));
1333 conv_in_desc.mFormatID = kAudioFormatLinearPCM;
1334 conv_in_desc.mFormatFlags = formatFlags |
1335 kAudioFormatFlagsNativeEndian |
1336 kLinearPCMFormatFlagIsPacked;
1339 conv_in_desc.mFramesPerPacket = 1;
1342 conv_in_desc.mBitsPerChannel =
1347 kAudioUnitProperty_StreamFormat,
1348 kAudioUnitScope_Input,
1351 sizeof(AudioStreamBasicDescription));
1354 LOG(VB_GENERAL, LOG_ERR, QString(
"CoreAudioData Error:OpenAnalog: AudioUnitSetProperty returned [%1]")
1358 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::OpenAnalog: set format as %1")
1362 kAudioUnitProperty_StreamFormat,
1363 kAudioUnitScope_Input,
1368 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::OpenAnalog: the actual set AU format is %1")
1372 AURenderCallbackStruct input;
1374 input.inputProcRefCon =
this;
1377 kAudioUnitProperty_SetRenderCallback,
1378 kAudioUnitScope_Input,
1379 0, &input,
sizeof(input));
1382 LOG(VB_GENERAL, LOG_ERR, QString(
"CoreAudioData Error:OpenAnalog: AudioUnitSetProperty (callback) returned [%1]")
1389 ComponentResult res = AudioUnitInitialize(
mOutputUnit);
1392 LOG(VB_GENERAL, LOG_ERR, QString(
"CoreAudioData Error:OpenAnalog: AudioUnitInitialize error: [%1]")
1401 LOG(VB_GENERAL, LOG_ERR, QString(
"CoreAudioData Error:OpenAnalog: AudioOutputUnitStart error: [%1]")
1413 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::CloseAnalog: Entering: %1")
1420 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::CloseAnalog: AudioOutputUnitStop %1")
1426 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::CloseAnalog: AudioUnitUninitialize %1")
1430 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::CloseAnalog: CloseComponent %1")
1444 AudioStreamBasicDescription outputFormat {};
1446 LOG(VB_AUDIO, LOG_INFO,
"CoreAudioData::OpenSPDIF: Entering");
1449 if (streams.empty())
1451 LOG(VB_GENERAL, LOG_WARNING,
"CoreAudioData Warning:OpenSPDIF: Couldn't retrieve list of streams");
1455 for (
size_t i = 0; i < streams.size(); ++i)
1464 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::OpenSPDIF: Considering Physical Format: %1")
1466 if ((format.mFormat.mFormatID ==
'IAC3' ||
1467 format.mFormat.mFormatID == kAudioFormat60958AC3) &&
1470 LOG(VB_AUDIO, LOG_INFO,
"CoreAudioData::OpenSPDIF: Found digital format");
1473 outputFormat = format.mFormat;
1477 if (outputFormat.mFormatID)
1481 if (!outputFormat.mFormatID)
1483 LOG(VB_GENERAL, LOG_ERR, QString(
"CoreAudioData Error:OpenSPDIF: Couldn't find suitable output"));
1489 AudioObjectPropertyAddress pa
1491 kAudioStreamPropertyPhysicalFormat,
1492 kAudioObjectPropertyScopeGlobal,
1499 err = AudioObjectGetPropertyData(
mStreamID, &pa, 0,
nullptr,
1503 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:OpenSPDIF - could not retrieve the original streamformat: [%1]")
1532 err = AudioDeviceCreateIOProcID(
mDeviceID,
1537 LOG(VB_GENERAL, LOG_ERR, QString(
"CoreAudioData Error:OpenSPDIF: AudioDeviceCreateIOProcID failed: [%1]")
1547 LOG(VB_GENERAL, LOG_ERR, QString(
"CoreAudioData Error:OpenSPDIF: AudioDeviceStart failed: [%1]")
1559 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::CloseSPDIF: Entering [%1]").arg(
mDigitalInUse));;
1568 LOG(VB_GENERAL, LOG_ERR, QString(
"CoreAudioData Error:CloseSPDIF: AudioDeviceStop failed: [%1]")
1578 LOG(VB_GENERAL, LOG_ERR, QString(
"CoreAudioData Error:CloseSPDIF: AudioDeviceDestroyIOProcID failed: [%1]")
1592 AudioHardwareUnload();
1600 AudioStreamBasicDescription format)
1602 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::AudioStreamChangeFormat: %1 -> %2")
1606 AudioObjectPropertyAddress pa
1608 kAudioStreamPropertyPhysicalFormat,
1609 kAudioObjectPropertyScopeGlobal,
1612 OSStatus err = AudioObjectSetPropertyData(s, &pa, 0,
nullptr,
1613 sizeof(format), &format);
1616 LOG(VB_GENERAL, LOG_ERR, QString(
"CoreAudioData Error:AudioStreamChangeFormat couldn't set stream format: [%1]")
1630 if (streams.empty())
1633 for (
auto stream : streams)
1641 if (format.mFormat.mFormatID ==
'IAC3' ||
1642 format.mFormat.mFormatID == kAudioFormat60958AC3)
1644 LOG(VB_AUDIO, LOG_INFO,
"CoreAudioData::FindAC3Stream: found digital format");
1660 AudioObjectPropertyAddress pa
1662 kAudioHardwarePropertyDevices,
1663 kAudioObjectPropertyScopeGlobal,
1667 OSStatus err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &pa,
1671 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:GetPropertyDataSize: Unable to retrieve the property sizes. "
1677 std::vector<AudioDeviceID> devices = {};
1678 devices.resize(size /
sizeof(AudioDeviceID));
1679 err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &pa,
1680 0,
nullptr, &size, devices.data());
1683 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:GetPropertyData: Unable to retrieve the list of available devices. "
1689 for (
const auto & dev : devices)
1694 if (streams.empty())
1696 for (
auto stream : streams)
1703 AudioStreamBasicDescription currentFormat;
1706 AudioObjectPropertyAddress pa
1708 kAudioStreamPropertyPhysicalFormat,
1709 kAudioObjectPropertyScopeGlobal,
1715 paramSize =
sizeof(currentFormat);
1716 AudioObjectGetPropertyData(s, &pa, 0,
nullptr,
1717 ¶mSize, ¤tFormat);
1720 if (currentFormat.mFormatID ==
'IAC3' ||
1721 currentFormat.mFormatID == kAudioFormat60958AC3)
1730 if (format.mFormat.mFormatID == kAudioFormatLinearPCM)
1732 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::ResetStream: Resetting stream %1 to %2").arg(s).arg(
StreamDescriptionToString(format.mFormat)));
1733 err = AudioObjectSetPropertyData(s, &pa, 0,
nullptr,
1734 sizeof(format), &(format.mFormat));
1737 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:ResetStream: could not set physical format: [%1]")
1742 std::this_thread::sleep_for(1s);
1750 auto *devs =
new QMap<QString, QString>();
1755 AudioObjectPropertyAddress pa
1757 kAudioHardwarePropertyDevices,
1758 kAudioObjectPropertyScopeGlobal,
1762 OSStatus err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &pa,
1766 LOG(VB_AUDIO, LOG_INFO,
LOC + QString(
"GetPropertyDataSize: Unable to retrieve the property sizes. "
1772 UInt32 deviceCount = size /
sizeof(AudioDeviceID);
1773 std::vector<AudioDeviceID> devices = {};
1774 devices.resize(deviceCount);
1775 err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &pa,
1776 0,
nullptr, &size, devices.data());
1779 LOG(VB_AUDIO, LOG_INFO,
LOC + QString(
"AudioOutputCA::GetDevices: Unable to retrieve the list of "
1780 "available devices. Error [%1]")
1785 LOG(VB_AUDIO, LOG_INFO,
LOC + QString(
"GetDevices: Number of devices: %1").arg(deviceCount));
1787 for (
const auto & dev : devices)
1792 QString *name = device.
GetName();
1795 devs->insert(*name, QString());
std::vector< AudioStreamID > AudioStreamIDVec
std::vector< AudioValueRange > AudioValueRangeVec
static Float64 sCommonSampleRates[]
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 void _ReorderSmpteToCA(AudioDataType *buf, uint frames)
static constexpr int8_t kMythAudioObjectPropertyElementMain
std::array< bool, CHANNELS_MAX > ChannelsArr
static void ReorderSmpteToCA(void *buf, uint frames, AudioFormat format)
static UInt32 sNumberCommonSampleRates
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.
bool ChannelsList(AudioDeviceID d, bool passthru, ChannelsArr &chans)
static int AudioStreamChangeFormat(AudioStreamID s, AudioStreamBasicDescription format)
static bool GetAutoHogMode()
bool SetHogStatus(bool hog)
bool SetMixingSupport(bool mix)
AudioStreamBasicDescription mFormatNew
CoreAudioData(AudioOutputCA *parent)
static void ResetStream(AudioStreamID s)
int GetTotalOutputChannels()
static void ResetAudioDevices()
Reset any devices with an AC3 stream back to a Linear PCM so that they can become a default output de...
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::enable_if_t< std::is_floating_point_v< T >, 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_)