15#include <SoundTouch.h>
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 char fourCC[5];
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));
242 if (i == 8 && !channels[6-1])
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.");
273 LOG(VB_AUDIO, LOG_INFO,
"AudioOutputCA::OpenDevice() Trying Analog.");
278 LOG(VB_AUDIO, LOG_INFO, QString(
"AudioOutputCA::OpenDevice: OpenAnalog = %1").arg(result));
285 deviceOpened = (result > 0);
290 LOG(VB_GENERAL, LOG_ERR,
"AudioOutputCA Error: Couldn't open any audio device!");
298 controlLabel +=
"MixerVolume";
307 LOG(VB_AUDIO, LOG_INFO,
LOC + QString(
"CloseDevice [%1]: Entering")
315template <
class AudioDataType>
320 AudioDataType tmpRLs;
321 AudioDataType tmpRRs;
323 for (
uint i = 0; i < frames; i++)
325 buf = buf2 = buf + 4;
350 int size,
unsigned long long timestamp)
366 if (written_size && (size > written_size))
369 memset(aubuf + written_size, 0, size - written_size);
379 UInt64 nanos = AudioConvertHostTimeToNanos(timestamp -
380 AudioGetCurrentHostTime());
385 return (written_size > 0);
390 [[maybe_unused]]
int size)
406 if (audbuf_timecode == 0ms)
418 AudioUnitRenderActionFlags *ioActionFlags,
419 const AudioTimeStamp *inTimeStamp,
420 [[maybe_unused]] UInt32 inBusNumber,
421 [[maybe_unused]] UInt32 inNumberFrames,
422 AudioBufferList *ioData)
426 if (!inst->
RenderAudio((
unsigned char *)(ioData->mBuffers[0].mData),
427 ioData->mBuffers[0].mDataByteSize,
428 inTimeStamp->mHostTime))
431 memset(ioData->mBuffers[0].mData, 0, ioData->mBuffers[0].mDataByteSize);
432 *ioActionFlags = kAudioUnitRenderAction_OutputIsSilence;
443 kHALOutputParam_Volume,
444 kAudioUnitScope_Global, 0, &volume))
445 return (
int)lroundf(volume * 100.0F);
453 AudioUnitSetParameter(
d->
mOutputUnit, kHALOutputParam_Volume,
454 kAudioUnitScope_Global, 0, (volume * 0.01F), 0);
459 [[maybe_unused]]
const AudioTimeStamp *inNow,
460 [[maybe_unused]]
const void *inInputData,
461 [[maybe_unused]]
const AudioTimeStamp *inInputTime,
462 AudioBufferList *outOutputData,
463 const AudioTimeStamp *inOutputTime,
468 int index =
d->mStreamIndex;
474 if (
d->mBytesPerPacket > 0 &&
475 outOutputData->mBuffers[index].mDataByteSize >
d->mBytesPerPacket)
477 outOutputData->mBuffers[index].mDataByteSize =
d->mBytesPerPacket;
479 if (!a->
RenderAudio((
unsigned char *)(outOutputData->mBuffers[index].mData),
480 outOutputData->mBuffers[index].mDataByteSize,
481 inOutputTime->mHostTime))
484 memset(outOutputData->mBuffers[index].mData, 0,
485 outOutputData->mBuffers[index].mDataByteSize);
516 if (deviceName !=
"Default Output Device")
518 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:CoreAudioData: \"%1\" not found, using default device %2.")
522 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::CoreAudioData: device number is %1")
529 AudioDeviceID deviceID = 0;
530 AudioObjectPropertyAddress pa
532 kAudioHardwarePropertyDevices,
533 kAudioObjectPropertyScopeGlobal,
537 OSStatus err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &pa,
541 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:GetPropertyDataSize: Unable to retrieve the property sizes. "
547 UInt32 deviceCount = size /
sizeof(AudioDeviceID);
548 std::vector<AudioDeviceID> devices = {};
549 devices.resize(deviceCount);
551 err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &pa,
552 0,
nullptr, &size, devices.data());
555 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:GetDeviceWithName: Unable to retrieve the list of available devices. "
561 for (
const auto & dev : devices)
566 QString *name = device.
GetName();
567 if (name && *name == deviceName)
569 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::GetDeviceWithName: Found: %1").arg(*name));
583 AudioDeviceID deviceId = 0;
584 AudioObjectPropertyAddress pa
586 kAudioHardwarePropertyDefaultOutputDevice,
587 kAudioObjectPropertyScopeGlobal,
592 paramSize =
sizeof(deviceId);
593 OSStatus err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &pa,
594 0,
nullptr, ¶mSize, &deviceId);
596 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::GetDefaultOutputDevice: default device ID = %1").arg(deviceId));
599 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:GetDefaultOutputDevice: could not get default audio device: [%1]")
612 AudioObjectPropertyAddress pa
614 kAudioDevicePropertyStreamConfiguration,
615 kAudioDevicePropertyScopeOutput,
619 OSStatus err = AudioObjectGetPropertyDataSize(
mDeviceID, &pa,
623 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:GetTotalOutputChannels: Unable to get "
624 "size of device output channels - id: %1 Error = [%2]")
630 auto *pList = (AudioBufferList *)malloc(size);
631 err = AudioObjectGetPropertyData(
mDeviceID, &pa,
632 0,
nullptr, &size, pList);
635 for (UInt32 buffer = 0; buffer < pList->mNumberBuffers; buffer++)
636 channels += pList->mBuffers[buffer].mNumberChannels;
640 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:GetTotalOutputChannels: Unable to get "
641 "total device output channels - id: %1 Error = [%2]")
645 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::GetTotalOutputChannels: Found %1 channels in %2 buffers")
646 .arg(channels).arg(pList->mNumberBuffers));
656 AudioObjectPropertyAddress pa
658 kAudioObjectPropertyName,
659 kAudioObjectPropertyScopeGlobal,
664 UInt32 propertySize =
sizeof(CFStringRef);
665 OSStatus err = AudioObjectGetPropertyData(
mDeviceID, &pa,
666 0,
nullptr, &propertySize, &name);
669 LOG(VB_GENERAL, LOG_ERR, QString(
"CoreAudioData Error:AudioObjectGetPropertyData for kAudioObjectPropertyName error: [%1]")
673 char *cname =
new char[CFStringGetLength(name) + 1];
674 CFStringGetCString(name, cname, CFStringGetLength(name) + 1, kCFStringEncodingUTF8);
675 auto *qname =
new QString(cname);
683 UInt32 size =
sizeof(val);
684 AudioObjectPropertyAddress pa
686 kAudioHardwarePropertyHogModeIsAllowed,
687 kAudioObjectPropertyScopeGlobal,
691 OSStatus err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &pa, 0,
nullptr, &size, &val);
694 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:GetAutoHogMode: Unable to get auto 'hog' mode. Error = [%1]")
703 UInt32 val = enable ? 1 : 0;
704 AudioObjectPropertyAddress pa
706 kAudioHardwarePropertyHogModeIsAllowed,
707 kAudioObjectPropertyScopeGlobal,
711 OSStatus err = AudioObjectSetPropertyData(kAudioObjectSystemObject, &pa, 0,
nullptr,
715 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:SetAutoHogMode: Unable to set auto 'hog' mode. Error = [%1]")
723 UInt32 PIDsize =
sizeof(
PID);
724 AudioObjectPropertyAddress pa
726 kAudioDevicePropertyHogMode,
727 kAudioObjectPropertyScopeGlobal,
731 OSStatus err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &pa, 0,
nullptr,
737 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::GetHogStatus: unable to check: [%1]")
746 AudioObjectPropertyAddress pa
748 kAudioDevicePropertyHogMode,
749 kAudioObjectPropertyScopeGlobal,
763 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::SetHogStatus: Setting 'hog' status on device %1")
765 OSStatus err = AudioObjectSetPropertyData(
mDeviceID, &pa, 0,
nullptr,
767 if (err ||
mHog != getpid())
769 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:SetHogStatus: Unable to set 'hog' status. Error = [%1]")
773 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::SetHogStatus: Successfully set 'hog' status on device %1")
781 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::SetHogStatus: Releasing 'hog' status on device %1")
784 OSStatus err = AudioObjectSetPropertyData(
mDeviceID, &pa, 0,
nullptr,
785 sizeof(hogPid), &hogPid);
786 if (err || hogPid == getpid())
788 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:SetHogStatus: Unable to release 'hog' status. Error = [%1]")
805 UInt32 mixEnable = mix ? 1 : 0;
806 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::SetMixingSupport: %1abling mixing for device %2")
807 .arg(mix ?
"En" :
"Dis")
810 AudioObjectPropertyAddress pa
812 kAudioDevicePropertySupportsMixing,
813 kAudioObjectPropertyScopeGlobal,
816 OSStatus err = AudioObjectSetPropertyData(
mDeviceID, &pa, 0,
nullptr,
817 sizeof(mixEnable), &mixEnable);
820 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:SetMixingSupport: Unable to set MixingSupport to %1. Error = [%2]")
821 .arg(mix ?
"'On'" :
"'Off'")
835 UInt32 size =
sizeof(val);
836 AudioObjectPropertyAddress pa
838 kAudioDevicePropertySupportsMixing,
839 kAudioObjectPropertyScopeGlobal,
842 OSStatus err = AudioObjectGetPropertyData(
mDeviceID, &pa, 0,
nullptr,
858 AudioObjectPropertyAddress pa
860 kAudioDevicePropertyStreams,
861 kAudioObjectPropertyScopeGlobal,
865 err = AudioObjectGetPropertyDataSize(
d, &pa,
866 0,
nullptr, &listSize);
869 LOG(VB_GENERAL, LOG_ERR, QString(
"CoreAudioData Error:StreamsList: could not get list size: [%1]")
877 vec.resize(listSize /
sizeof(AudioStreamID));
881 LOG(VB_GENERAL, LOG_ERR,
"CoreAudioData Error:StreamsList(): out of memory?");
885 err = AudioObjectGetPropertyData(
d, &pa,
886 0,
nullptr, &listSize, vec.data());
889 LOG(VB_GENERAL, LOG_ERR, QString(
"CoreAudioData Error:StreamsList: could not get list: [%1]")
903 AudioObjectPropertyAddress pa
906 kAudioStreamPropertyAvailablePhysicalFormats,
907 kAudioObjectPropertyScopeGlobal,
912 err = AudioObjectGetPropertyDataSize(s, &pa, 0,
nullptr, &listSize);
915 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:FormatsList(): couldn't get list size: [%1]")
922 vec.resize(listSize /
sizeof(AudioStreamRangedDescription));
926 LOG(VB_GENERAL, LOG_ERR,
"CoreAudioData Error:FormatsList(): out of memory?");
930 err = AudioObjectGetPropertyData(s, &pa, 0,
nullptr, &listSize, vec.data());
933 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:FormatsList: couldn't get list: [%1]")
943 8000.0, 11025.0, 12000.0,
944 16000.0, 22050.0, 24000.0,
945 32000.0, 44100.0, 48000.0,
946 64000.0, 88200.0, 96000.0,
947 128000.0, 176400.0, 192000.0 };
951 bool theAnswer =
false;
966 AudioObjectPropertyAddress pa
968 kAudioDevicePropertyAvailableNominalSampleRates,
969 kAudioObjectPropertyScopeGlobal,
974 err = AudioObjectGetPropertyDataSize(
d, &pa, 0,
nullptr, &listSize);
977 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:RatesList(): couldn't get data rate list size: [%1]")
984 ranges.resize(listSize /
sizeof(AudioValueRange));
985 finalvec.reserve(listSize /
sizeof(AudioValueRange));
989 LOG(VB_GENERAL, LOG_ERR,
"CoreAudioData Error:RatesList(): out of memory?");
993 err = AudioObjectGetPropertyData(
d, &pa, 0,
nullptr, &listSize, ranges.data());
996 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:RatesList(): couldn't get list: [%1]")
1002 UInt32 theFirstIndex;
1003 UInt32 theLastIndex = 0;
1004 for(
auto range : ranges)
1006 theFirstIndex = theLastIndex;
1014 theLastIndex = theFirstIndex;
1022 finalvec.push_back(range.mMinimum);
1024 finalvec.push_back(range.mMaximum);
1034 bool founddigital =
false;
1039 if (streams.empty())
1044 for (
auto stream : streams)
1053 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::ChannelsList: (passthru) found format: %1")
1057 chans[format.mFormat.mChannelsPerFrame-1] =
true;
1059 if (format.mFormat.mFormatID ==
'IAC3' ||
1060 format.mFormat.mFormatID == kAudioFormat60958AC3)
1066 founddigital =
true;
1074 for (
auto stream : streams)
1081 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::ChannelsList: (!founddigital) found format: %1")
1084 chans[format.mFormat.mChannelsPerFrame-1] =
true;
1093 AudioComponentDescription desc;
1094 AudioStreamBasicDescription DeviceFormat;
1095 AudioChannelLayout *layout;
1096 AudioChannelLayout new_layout;
1098 AudioObjectPropertyAddress pa
1100 kAudioHardwarePropertyDevices,
1101 kAudioObjectPropertyScopeGlobal,
1105 LOG(VB_AUDIO, LOG_INFO,
"CoreAudioData::OpenAnalog: Entering");
1107 desc.componentType = kAudioUnitType_Output;
1110 desc.componentSubType = kAudioUnitSubType_DefaultOutput;
1114 desc.componentSubType = kAudioUnitSubType_HALOutput;
1116 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
1117 desc.componentFlags = 0;
1118 desc.componentFlagsMask = 0;
1121 AudioComponent comp = AudioComponentFindNext(
nullptr, &desc);
1122 if (comp ==
nullptr)
1124 LOG(VB_GENERAL, LOG_ERR,
"CoreAudioData Error:OpenAnalog: AudioComponentFindNext failed");
1128 OSErr err = AudioComponentInstanceNew(comp, &
mOutputUnit);
1131 LOG(VB_GENERAL, LOG_ERR, QString(
"CoreAudioData Error:OpenAnalog: AudioComponentInstanceNew returned %1")
1138 UInt32 size_hasIO =
sizeof(hasIO);
1140 kAudioOutputUnitProperty_HasIO,
1141 kAudioUnitScope_Output,
1143 &hasIO, &size_hasIO);
1144 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::OpenAnalog: HasIO (output) = %1").arg(hasIO));
1147 UInt32 enableIO = 1;
1149 kAudioOutputUnitProperty_EnableIO,
1150 kAudioUnitScope_Global,
1152 &enableIO,
sizeof(enableIO));
1155 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:OpenAnalog: failed enabling IO: %1")
1160 kAudioOutputUnitProperty_HasIO,
1161 kAudioUnitScope_Output,
1163 &hasIO, &size_hasIO);
1164 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::HasIO = %1").arg(hasIO));
1174 kAudioOutputUnitProperty_CurrentDevice,
1175 kAudioUnitScope_Global,
1180 LOG(VB_GENERAL, LOG_ERR, QString(
"CoreAudioData Error:OpenAnalog: Unable to set current device to %1. Error = %2")
1187 UInt32 param_size =
sizeof(AudioStreamBasicDescription);
1190 kAudioUnitProperty_StreamFormat,
1191 kAudioUnitScope_Input,
1197 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:OpenAnalog: Unable to retrieve current stream format: [%1]")
1202 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::OpenAnalog: current format is: %1")
1206 pa.mSelector = kAudioDevicePropertyPreferredChannelLayout;
1207 err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &pa,
1208 0,
nullptr, ¶m_size);
1212 layout = (AudioChannelLayout *) malloc(param_size);
1214 err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &pa,
1215 0,
nullptr, ¶m_size, layout);
1218 if(layout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap)
1221 err = AudioFormatGetProperty(kAudioFormatProperty_ChannelLayoutForBitmap,
1222 sizeof(UInt32), &layout->mChannelBitmap,
1226 LOG(VB_GENERAL, LOG_WARNING,
"CoreAudioData Warning:OpenAnalog: Can't retrieve current channel layout");
1228 else if(layout->mChannelLayoutTag != kAudioChannelLayoutTag_UseChannelDescriptions )
1231 err = AudioFormatGetProperty(kAudioFormatProperty_ChannelLayoutForTag,
1232 sizeof(AudioChannelLayoutTag),
1233 &layout->mChannelLayoutTag,
1237 LOG(VB_GENERAL, LOG_WARNING,
"CoreAudioData Warning:OpenAnalog: Can't retrieve current channel layout");
1240 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::OpenAnalog: Layout of AUHAL has %1 channels")
1241 .arg(layout->mNumberChannelDescriptions));
1243 int channels_found = 0;
1244 for(UInt32 i = 0; i < layout->mNumberChannelDescriptions; i++)
1246 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::OpenAnalog: this is channel: %1")
1247 .arg(layout->mChannelDescriptions[i].mChannelLabel));
1249 switch( layout->mChannelDescriptions[i].mChannelLabel)
1251 case kAudioChannelLabel_Left:
1252 case kAudioChannelLabel_Right:
1253 case kAudioChannelLabel_Center:
1254 case kAudioChannelLabel_LFEScreen:
1255 case kAudioChannelLabel_LeftSurround:
1256 case kAudioChannelLabel_RightSurround:
1257 case kAudioChannelLabel_RearSurroundLeft:
1258 case kAudioChannelLabel_RearSurroundRight:
1259 case kAudioChannelLabel_CenterSurround:
1263 LOG(VB_AUDIO, LOG_INFO, QString(
"CoreAudioData::unrecognized channel form provided by driver: %1")
1264 .arg(layout->mChannelDescriptions[i].mChannelLabel));
1267 if(channels_found == 0)
1269 LOG(VB_GENERAL, LOG_WARNING,
"CoreAudioData Warning:Audio device is not configured. "
1270 "You should configure your speaker layout with "
1271 "the \"Audio Midi Setup\" utility in /Applications/"
1278 LOG(VB_GENERAL, LOG_WARNING,
"CoreAudioData Warning:this driver does not support kAudioDevicePropertyPreferredChannelLayout.");
1281 memset (&new_layout, 0,
sizeof(new_layout));
1285 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_Mono;
1288 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_Stereo;
1292 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_AudioUnit_5_1;
1298 new_layout.mChannelLayoutTag = kAudioChannelLayoutTag_MPEG_7_1_A;
1303 kAudioUnitProperty_AudioChannelLayout,
1304 kAudioUnitScope_Input,
1306 &new_layout,
sizeof(new_layout));
1309 LOG(VB_GENERAL, LOG_WARNING, QString(
"CoreAudioData Warning:OpenAnalog: couldn't set channels layout [%1]")
1313 if(new_layout.mNumberChannelDescriptions > 0)
1314 free(new_layout.mChannelDescriptions);
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;
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]")
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
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
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)
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...
static void usleep(std::chrono::microseconds time)
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_)
const std::array< const std::string, 8 > formats