|
|
@@ -27,6 +27,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
|
|
|
#include "JackGlobals.h" |
|
|
|
#include "JackTools.h" |
|
|
|
#include "JackLockedEngine.h" |
|
|
|
#include "JackAC3Encoder.h" |
|
|
|
|
|
|
|
#include <sstream> |
|
|
|
#include <iostream> |
|
|
@@ -49,7 +50,7 @@ static void PrintStreamDesc(AudioStreamBasicDescription *inDesc) |
|
|
|
{ |
|
|
|
jack_log("- - - - - - - - - - - - - - - - - - - -"); |
|
|
|
jack_log(" Sample Rate:%f", inDesc->mSampleRate); |
|
|
|
jack_log(" Format ID:%.*s", (int) sizeof(inDesc->mFormatID), (char*)&inDesc->mFormatID); |
|
|
|
jack_log(" Format ID:%.*s", (int)sizeof(inDesc->mFormatID), (char*)&inDesc->mFormatID); |
|
|
|
jack_log(" Format Flags:%lX", inDesc->mFormatFlags); |
|
|
|
jack_log(" Bytes per Packet:%ld", inDesc->mBytesPerPacket); |
|
|
|
jack_log(" Frames per Packet:%ld", inDesc->mFramesPerPacket); |
|
|
@@ -123,7 +124,7 @@ static void printError(OSStatus err) |
|
|
|
jack_log("error code : kAudioHardwareUnsupportedOperationError"); |
|
|
|
break; |
|
|
|
default: |
|
|
|
Print4CharCode("error code : unknown", err); |
|
|
|
Print4CharCode("error code : unknown ", err); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
@@ -191,7 +192,6 @@ static bool CheckAvailableDevice(AudioDeviceID device_id) |
|
|
|
if (device_id == devices[i]) { |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return false; |
|
|
@@ -323,17 +323,37 @@ int JackCoreAudioDriver::Read() |
|
|
|
|
|
|
|
int JackCoreAudioDriver::Write() |
|
|
|
{ |
|
|
|
for (int i = 0; i < fPlaybackChannels; i++) { |
|
|
|
if (fGraphManager->GetConnectionsNum(fPlaybackPortList[i]) > 0) { |
|
|
|
jack_default_audio_sample_t* buffer = GetOutputBuffer(i); |
|
|
|
int size = sizeof(jack_default_audio_sample_t) * fEngineControl->fBufferSize; |
|
|
|
memcpy((jack_default_audio_sample_t*)fDriverOutputData->mBuffers[i].mData, buffer, size); |
|
|
|
// Monitor ports |
|
|
|
if (fWithMonitorPorts && fGraphManager->GetConnectionsNum(fMonitorPortList[i]) > 0) { |
|
|
|
memcpy(GetMonitorBuffer(i), buffer, size); |
|
|
|
if (fAC3Encoder) { |
|
|
|
|
|
|
|
// AC3 encoding and SPDIF write |
|
|
|
jack_default_audio_sample_t* AC3_inputs[MAX_AC3_CHANNELS]; |
|
|
|
jack_default_audio_sample_t* AC3_outputs[2]; |
|
|
|
for (int i = 0; i < fPlaybackChannels; i++) { |
|
|
|
AC3_inputs[i] = GetOutputBuffer(i); |
|
|
|
// If not connected, clear the buffer |
|
|
|
if (fGraphManager->GetConnectionsNum(fPlaybackPortList[i]) == 0) { |
|
|
|
memset(AC3_inputs[i], 0, sizeof(jack_default_audio_sample_t) * fEngineControl->fBufferSize); |
|
|
|
} |
|
|
|
} |
|
|
|
AC3_outputs[0] = (jack_default_audio_sample_t*)fDriverOutputData->mBuffers[0].mData; |
|
|
|
AC3_outputs[1] = (jack_default_audio_sample_t*)fDriverOutputData->mBuffers[1].mData; |
|
|
|
fAC3Encoder->Process(AC3_inputs, AC3_outputs, fEngineControl->fBufferSize); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
// Standard write |
|
|
|
for (int i = 0; i < fPlaybackChannels; i++) { |
|
|
|
if (fGraphManager->GetConnectionsNum(fPlaybackPortList[i]) > 0) { |
|
|
|
jack_default_audio_sample_t* buffer = GetOutputBuffer(i); |
|
|
|
int size = sizeof(jack_default_audio_sample_t) * fEngineControl->fBufferSize; |
|
|
|
memcpy((jack_default_audio_sample_t*)fDriverOutputData->mBuffers[i].mData, buffer, size); |
|
|
|
// Monitor ports |
|
|
|
if (fWithMonitorPorts && fGraphManager->GetConnectionsNum(fMonitorPortList[i]) > 0) { |
|
|
|
memcpy(GetMonitorBuffer(i), buffer, size); |
|
|
|
} |
|
|
|
} else { |
|
|
|
memset((jack_default_audio_sample_t*)fDriverOutputData->mBuffers[i].mData, 0, sizeof(jack_default_audio_sample_t) * fEngineControl->fBufferSize); |
|
|
|
} |
|
|
|
} else { |
|
|
|
memset((jack_default_audio_sample_t*)fDriverOutputData->mBuffers[i].mData, 0, sizeof(jack_default_audio_sample_t) * fEngineControl->fBufferSize); |
|
|
|
} |
|
|
|
} |
|
|
|
return 0; |
|
|
@@ -353,7 +373,7 @@ OSStatus JackCoreAudioDriver::SRNotificationCallback(AudioDeviceID inDevice, |
|
|
|
jack_log("JackCoreAudioDriver::SRNotificationCallback kAudioDevicePropertyNominalSampleRate"); |
|
|
|
// Check new sample rate |
|
|
|
Float64 tmp_sample_rate; |
|
|
|
UInt32 outSize = sizeof(Float64); |
|
|
|
UInt32 outSize = sizeof(Float64); |
|
|
|
OSStatus err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &tmp_sample_rate); |
|
|
|
if (err != noErr) { |
|
|
|
jack_error("Cannot get current sample rate"); |
|
|
@@ -371,7 +391,7 @@ OSStatus JackCoreAudioDriver::SRNotificationCallback(AudioDeviceID inDevice, |
|
|
|
|
|
|
|
OSStatus JackCoreAudioDriver::BSNotificationCallback(AudioDeviceID inDevice, |
|
|
|
UInt32 inChannel, |
|
|
|
Boolean isInput, |
|
|
|
Boolean isInput, |
|
|
|
AudioDevicePropertyID inPropertyID, |
|
|
|
void* inClientData) |
|
|
|
{ |
|
|
@@ -383,7 +403,7 @@ OSStatus JackCoreAudioDriver::BSNotificationCallback(AudioDeviceID inDevice, |
|
|
|
jack_log("JackCoreAudioDriver::BSNotificationCallback kAudioDevicePropertyBufferFrameSize"); |
|
|
|
// Check new buffer size |
|
|
|
UInt32 tmp_buffer_size; |
|
|
|
UInt32 outSize = sizeof(UInt32); |
|
|
|
UInt32 outSize = sizeof(UInt32); |
|
|
|
OSStatus err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyBufferFrameSize, &outSize, &tmp_buffer_size); |
|
|
|
if (err != noErr) { |
|
|
|
jack_error("Cannot get current buffer size"); |
|
|
@@ -406,18 +426,17 @@ OSStatus JackCoreAudioDriver::AudioHardwareNotificationCallback(AudioHardwarePro |
|
|
|
|
|
|
|
switch (inPropertyID) { |
|
|
|
|
|
|
|
case kAudioHardwarePropertyDevices: { |
|
|
|
jack_log("JackCoreAudioDriver::AudioHardwareNotificationCallback kAudioHardwarePropertyDevices"); |
|
|
|
DisplayDeviceNames(); |
|
|
|
AudioDeviceID captureID, playbackID; |
|
|
|
if (CheckAvailableDevice(driver->fDeviceID) || |
|
|
|
(CheckAvailableDeviceName(driver->fCaptureUID, &captureID) |
|
|
|
&& CheckAvailableDeviceName(driver->fPlaybackUID, &playbackID))) { |
|
|
|
case kAudioHardwarePropertyDevices: { |
|
|
|
jack_log("JackCoreAudioDriver::AudioHardwareNotificationCallback kAudioHardwarePropertyDevices"); |
|
|
|
DisplayDeviceNames(); |
|
|
|
AudioDeviceID captureID, playbackID; |
|
|
|
if (CheckAvailableDevice(driver->fDeviceID) || |
|
|
|
(CheckAvailableDeviceName(driver->fCaptureUID, &captureID) |
|
|
|
&& CheckAvailableDeviceName(driver->fPlaybackUID, &playbackID))) { |
|
|
|
|
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return noErr; |
|
|
@@ -461,7 +480,7 @@ OSStatus JackCoreAudioDriver::DeviceNotificationCallback(AudioDeviceID inDevice, |
|
|
|
} |
|
|
|
|
|
|
|
case kAudioDeviceProcessorOverload: { |
|
|
|
jack_error("JackCoreAudioDriver::DeviceNotificationCallback kAudioDeviceProcessorOverload"); |
|
|
|
jack_error("DeviceNotificationCallback kAudioDeviceProcessorOverload"); |
|
|
|
jack_time_t cur_time = GetMicroSeconds(); |
|
|
|
driver->NotifyXRun(cur_time, float(cur_time - driver->fBeginDateUst)); // Better this value than nothing... |
|
|
|
break; |
|
|
@@ -628,12 +647,13 @@ OSStatus JackCoreAudioDriver::GetTotalChannels(AudioDeviceID device, int& channe |
|
|
|
err = AudioDeviceGetPropertyInfo(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize, &outWritable); |
|
|
|
if (err == noErr) { |
|
|
|
int stream_count = outSize / sizeof(AudioBufferList); |
|
|
|
jack_log(" JackCoreAudioDriver::GetTotalChannels stream_count = %d", stream_count); |
|
|
|
AudioBufferList bufferList[stream_count]; |
|
|
|
err = AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize, bufferList); |
|
|
|
if (err == noErr) { |
|
|
|
for (uint i = 0; i < bufferList->mNumberBuffers; i++) { |
|
|
|
channelCount += bufferList->mBuffers[i].mNumberChannels; |
|
|
|
//jack_info("GetTotalChannels stream = %d channels = %d", i, bufferList->mBuffers[i].mNumberChannels); |
|
|
|
jack_log(" JackCoreAudioDriver::GetTotalChannels stream = %d channels = %d", i, bufferList->mBuffers[i].mNumberChannels); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@@ -686,8 +706,77 @@ OSStatus JackCoreAudioDriver::GetStreamLatencies(AudioDeviceID device, bool isIn |
|
|
|
return err; |
|
|
|
} |
|
|
|
|
|
|
|
bool JackCoreAudioDriver::IsDigitalDevice(AudioDeviceID device) |
|
|
|
{ |
|
|
|
OSStatus err = noErr; |
|
|
|
UInt32 outSize1; |
|
|
|
bool is_digital = false; |
|
|
|
|
|
|
|
/* Get a list of all the streams on this device */ |
|
|
|
AudioObjectPropertyAddress streamsAddress = { kAudioDevicePropertyStreams, kAudioDevicePropertyScopeOutput, kAudioObjectPropertyElementMaster }; |
|
|
|
err = AudioObjectGetPropertyDataSize(device, &streamsAddress, 0, NULL, &outSize1); |
|
|
|
if (err != noErr) { |
|
|
|
jack_error("IsDigitalDevice kAudioDevicePropertyStreams err = %d", err); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
int stream_count = outSize1 / sizeof(AudioStreamID); |
|
|
|
AudioStreamID streamIDs[stream_count]; |
|
|
|
|
|
|
|
err = AudioObjectGetPropertyData(device, &streamsAddress, 0, NULL, &outSize1, streamIDs); |
|
|
|
|
|
|
|
if (err != noErr) { |
|
|
|
jack_error("IsDigitalDevice kAudioDevicePropertyStreams list err = %d", err); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
AudioObjectPropertyAddress physicalFormatsAddress = { kAudioStreamPropertyAvailablePhysicalFormats, kAudioObjectPropertyScopeGlobal, 0 }; |
|
|
|
|
|
|
|
for (int i = 0; i < stream_count ; i++) { |
|
|
|
|
|
|
|
/* Find a stream with a cac3 stream */ |
|
|
|
int format_num = 0; |
|
|
|
|
|
|
|
/* Retrieve all the stream formats supported by each output stream */ |
|
|
|
err = AudioObjectGetPropertyDataSize(streamIDs[i], &physicalFormatsAddress, 0, NULL, &outSize1); |
|
|
|
|
|
|
|
if (err != noErr) { |
|
|
|
jack_error("IsDigitalDevice kAudioStreamPropertyAvailablePhysicalFormats err = %d", err); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
format_num = outSize1 / sizeof(AudioStreamRangedDescription); |
|
|
|
AudioStreamRangedDescription format_list[format_num]; |
|
|
|
|
|
|
|
err = AudioObjectGetPropertyData(streamIDs[i], &physicalFormatsAddress, 0, NULL, &outSize1, format_list); |
|
|
|
|
|
|
|
if (err != noErr) { |
|
|
|
jack_error("IsDigitalDevice could not get the list of streamformats err = %d", err); |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
/* Check if one of the supported formats is a digital format */ |
|
|
|
for (int j = 0; j < format_num; j++) { |
|
|
|
|
|
|
|
PrintStreamDesc(&format_list[j].mFormat); |
|
|
|
|
|
|
|
if (format_list[j].mFormat.mFormatID == 'IAC3' || |
|
|
|
format_list[j].mFormat.mFormatID == 'iac3' || |
|
|
|
format_list[j].mFormat.mFormatID == kAudioFormat60958AC3 || |
|
|
|
format_list[j].mFormat.mFormatID == kAudioFormatAC3) |
|
|
|
{ |
|
|
|
is_digital = true; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return is_digital; |
|
|
|
} |
|
|
|
|
|
|
|
JackCoreAudioDriver::JackCoreAudioDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table) |
|
|
|
: JackAudioDriver(name, alias, engine, table), |
|
|
|
fAC3Encoder(NULL), |
|
|
|
fJackInputData(NULL), |
|
|
|
fDriverOutputData(NULL), |
|
|
|
fPluginID(0), |
|
|
@@ -695,11 +784,14 @@ JackCoreAudioDriver::JackCoreAudioDriver(const char* name, const char* alias, Ja |
|
|
|
fHogged(false), |
|
|
|
fIOUsage(1.f), |
|
|
|
fComputationGrain(-1.f), |
|
|
|
fClockDriftCompensate(false) |
|
|
|
fClockDriftCompensate(false), |
|
|
|
fDigitalPlayback(false) |
|
|
|
{} |
|
|
|
|
|
|
|
JackCoreAudioDriver::~JackCoreAudioDriver() |
|
|
|
{} |
|
|
|
{ |
|
|
|
delete fAC3Encoder; |
|
|
|
} |
|
|
|
|
|
|
|
OSStatus JackCoreAudioDriver::DestroyAggregateDevice() |
|
|
|
{ |
|
|
@@ -714,14 +806,14 @@ OSStatus JackCoreAudioDriver::DestroyAggregateDevice() |
|
|
|
|
|
|
|
osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize); |
|
|
|
if (osErr != noErr) { |
|
|
|
jack_error("JackCoreAudioDriver::DestroyAggregateDevice : AudioObjectGetPropertyDataSize error"); |
|
|
|
jack_error("DestroyAggregateDevice : AudioObjectGetPropertyDataSize error"); |
|
|
|
printError(osErr); |
|
|
|
return osErr; |
|
|
|
} |
|
|
|
|
|
|
|
osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, 0, NULL, &outDataSize, &fDeviceID); |
|
|
|
if (osErr != noErr) { |
|
|
|
jack_error("JackCoreAudioDriver::DestroyAggregateDevice : AudioObjectGetPropertyData error"); |
|
|
|
jack_error("DestroyAggregateDevice : AudioObjectGetPropertyData error"); |
|
|
|
printError(osErr); |
|
|
|
return osErr; |
|
|
|
} |
|
|
@@ -793,18 +885,18 @@ OSStatus JackCoreAudioDriver::CreateAggregateDeviceAux(vector<AudioDeviceID> cap |
|
|
|
|
|
|
|
for (UInt32 i = 0; i < captureDeviceID.size(); i++) { |
|
|
|
if (SetupSampleRateAux(captureDeviceID[i], samplerate) < 0) { |
|
|
|
jack_error("JackCoreAudioDriver::CreateAggregateDevice : cannot set SR of input device"); |
|
|
|
jack_error("CreateAggregateDevice : cannot set SR of input device"); |
|
|
|
} else { |
|
|
|
// Check clock domain |
|
|
|
osErr = AudioDeviceGetProperty(captureDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain); |
|
|
|
if (osErr != 0) { |
|
|
|
jack_error("JackCoreAudioDriver::CreateAggregateDevice : kAudioDevicePropertyClockDomain error"); |
|
|
|
jack_error("CreateAggregateDevice : kAudioDevicePropertyClockDomain error"); |
|
|
|
printError(osErr); |
|
|
|
} else { |
|
|
|
keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain; |
|
|
|
jack_log("JackCoreAudioDriver::CreateAggregateDevice : input clockdomain = %d", clockdomain); |
|
|
|
if (clockdomain != 0 && clockdomain != keptclockdomain) { |
|
|
|
jack_error("JackCoreAudioDriver::CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed..."); |
|
|
|
jack_error("CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed..."); |
|
|
|
need_clock_drift_compensation = true; |
|
|
|
} |
|
|
|
} |
|
|
@@ -813,18 +905,18 @@ OSStatus JackCoreAudioDriver::CreateAggregateDeviceAux(vector<AudioDeviceID> cap |
|
|
|
|
|
|
|
for (UInt32 i = 0; i < playbackDeviceID.size(); i++) { |
|
|
|
if (SetupSampleRateAux(playbackDeviceID[i], samplerate) < 0) { |
|
|
|
jack_error("JackCoreAudioDriver::CreateAggregateDevice : cannot set SR of output device"); |
|
|
|
jack_error("CreateAggregateDevice : cannot set SR of output device"); |
|
|
|
} else { |
|
|
|
// Check clock domain |
|
|
|
osErr = AudioDeviceGetProperty(playbackDeviceID[i], 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyClockDomain, &outSize, &clockdomain); |
|
|
|
if (osErr != 0) { |
|
|
|
jack_error("JackCoreAudioDriver::CreateAggregateDevice : kAudioDevicePropertyClockDomain error"); |
|
|
|
jack_error("CreateAggregateDevice : kAudioDevicePropertyClockDomain error"); |
|
|
|
printError(osErr); |
|
|
|
} else { |
|
|
|
keptclockdomain = (keptclockdomain == 0) ? clockdomain : keptclockdomain; |
|
|
|
jack_log("JackCoreAudioDriver::CreateAggregateDevice : output clockdomain = %d", clockdomain); |
|
|
|
if (clockdomain != 0 && clockdomain != keptclockdomain) { |
|
|
|
jack_error("JackCoreAudioDriver::CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed..."); |
|
|
|
jack_error("CreateAggregateDevice : devices do not share the same clock!! clock drift compensation would be needed..."); |
|
|
|
need_clock_drift_compensation = true; |
|
|
|
} |
|
|
|
} |
|
|
@@ -853,7 +945,7 @@ OSStatus JackCoreAudioDriver::CreateAggregateDeviceAux(vector<AudioDeviceID> cap |
|
|
|
|
|
|
|
osErr = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyPlugInForBundleID, &outSize, &outWritable); |
|
|
|
if (osErr != noErr) { |
|
|
|
jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioHardwareGetPropertyInfo kAudioHardwarePropertyPlugInForBundleID error"); |
|
|
|
jack_error("CreateAggregateDevice : AudioHardwareGetPropertyInfo kAudioHardwarePropertyPlugInForBundleID error"); |
|
|
|
printError(osErr); |
|
|
|
return osErr; |
|
|
|
} |
|
|
@@ -869,7 +961,7 @@ OSStatus JackCoreAudioDriver::CreateAggregateDeviceAux(vector<AudioDeviceID> cap |
|
|
|
|
|
|
|
osErr = AudioHardwareGetProperty(kAudioHardwarePropertyPlugInForBundleID, &outSize, &pluginAVT); |
|
|
|
if (osErr != noErr) { |
|
|
|
jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioHardwareGetProperty kAudioHardwarePropertyPlugInForBundleID error"); |
|
|
|
jack_error("CreateAggregateDevice : AudioHardwareGetProperty kAudioHardwarePropertyPlugInForBundleID error"); |
|
|
|
printError(osErr); |
|
|
|
return osErr; |
|
|
|
} |
|
|
@@ -986,14 +1078,14 @@ OSStatus JackCoreAudioDriver::CreateAggregateDeviceAux(vector<AudioDeviceID> cap |
|
|
|
|
|
|
|
osErr = AudioObjectGetPropertyDataSize(fPluginID, &pluginAOPA, 0, NULL, &outDataSize); |
|
|
|
if (osErr != noErr) { |
|
|
|
jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectGetPropertyDataSize error"); |
|
|
|
jack_error("CreateAggregateDevice : AudioObjectGetPropertyDataSize error"); |
|
|
|
printError(osErr); |
|
|
|
goto error; |
|
|
|
} |
|
|
|
|
|
|
|
osErr = AudioObjectGetPropertyData(fPluginID, &pluginAOPA, sizeof(aggDeviceDict), &aggDeviceDict, &outDataSize, outAggregateDevice); |
|
|
|
if (osErr != noErr) { |
|
|
|
jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectGetPropertyData error"); |
|
|
|
jack_error("CreateAggregateDevice : AudioObjectGetPropertyData error"); |
|
|
|
printError(osErr); |
|
|
|
goto error; |
|
|
|
} |
|
|
@@ -1012,7 +1104,7 @@ OSStatus JackCoreAudioDriver::CreateAggregateDeviceAux(vector<AudioDeviceID> cap |
|
|
|
outDataSize = sizeof(CFMutableArrayRef); |
|
|
|
osErr = AudioObjectSetPropertyData(*outAggregateDevice, &pluginAOPA, 0, NULL, outDataSize, &subDevicesArray); |
|
|
|
if (osErr != noErr) { |
|
|
|
jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectSetPropertyData for sub-device list error"); |
|
|
|
jack_error("CreateAggregateDevice : AudioObjectSetPropertyData for sub-device list error"); |
|
|
|
printError(osErr); |
|
|
|
goto error; |
|
|
|
} |
|
|
@@ -1032,7 +1124,7 @@ OSStatus JackCoreAudioDriver::CreateAggregateDeviceAux(vector<AudioDeviceID> cap |
|
|
|
outDataSize = sizeof(CFStringRef); |
|
|
|
osErr = AudioObjectSetPropertyData(*outAggregateDevice, &pluginAOPA, 0, NULL, outDataSize, &captureDeviceUID[0]); // First apture is master... |
|
|
|
if (osErr != noErr) { |
|
|
|
jack_error("JackCoreAudioDriver::CreateAggregateDevice : AudioObjectSetPropertyData for master device error"); |
|
|
|
jack_error("CreateAggregateDevice : AudioObjectSetPropertyData for master device error"); |
|
|
|
printError(osErr); |
|
|
|
goto error; |
|
|
|
} |
|
|
@@ -1050,7 +1142,7 @@ OSStatus JackCoreAudioDriver::CreateAggregateDeviceAux(vector<AudioDeviceID> cap |
|
|
|
// Get the property data size |
|
|
|
osErr = AudioObjectGetPropertyDataSize(*outAggregateDevice, &theAddressOwned, theQualifierDataSize, theQualifierData, &outSize); |
|
|
|
if (osErr != noErr) { |
|
|
|
jack_error("JackCoreAudioDriver::CreateAggregateDevice kAudioObjectPropertyOwnedObjects error"); |
|
|
|
jack_error("CreateAggregateDevice kAudioObjectPropertyOwnedObjects error"); |
|
|
|
printError(osErr); |
|
|
|
} |
|
|
|
|
|
|
@@ -1062,7 +1154,7 @@ OSStatus JackCoreAudioDriver::CreateAggregateDeviceAux(vector<AudioDeviceID> cap |
|
|
|
|
|
|
|
osErr = AudioObjectGetPropertyData(*outAggregateDevice, &theAddressOwned, theQualifierDataSize, theQualifierData, &outSize, subDevices); |
|
|
|
if (osErr != noErr) { |
|
|
|
jack_error("JackCoreAudioDriver::CreateAggregateDevice kAudioObjectPropertyOwnedObjects error"); |
|
|
|
jack_error("CreateAggregateDevice kAudioObjectPropertyOwnedObjects error"); |
|
|
|
printError(osErr); |
|
|
|
} |
|
|
|
|
|
|
@@ -1071,7 +1163,7 @@ OSStatus JackCoreAudioDriver::CreateAggregateDeviceAux(vector<AudioDeviceID> cap |
|
|
|
UInt32 theDriftCompensationValue = 1; |
|
|
|
osErr = AudioObjectSetPropertyData(subDevices[index], &theAddressDrift, 0, NULL, sizeof(UInt32), &theDriftCompensationValue); |
|
|
|
if (osErr != noErr) { |
|
|
|
jack_error("JackCoreAudioDriver::CreateAggregateDevice kAudioSubDevicePropertyDriftCompensation error"); |
|
|
|
jack_error("CreateAggregateDevice kAudioSubDevicePropertyDriftCompensation error"); |
|
|
|
printError(osErr); |
|
|
|
} |
|
|
|
} |
|
|
@@ -1119,7 +1211,8 @@ int JackCoreAudioDriver::SetupDevices(const char* capture_driver_uid, |
|
|
|
const char* playback_driver_uid, |
|
|
|
char* capture_driver_name, |
|
|
|
char* playback_driver_name, |
|
|
|
jack_nframes_t samplerate) |
|
|
|
jack_nframes_t samplerate, |
|
|
|
bool ac3_encoding) |
|
|
|
{ |
|
|
|
capture_driver_name[0] = 0; |
|
|
|
playback_driver_name[0] = 0; |
|
|
@@ -1142,12 +1235,22 @@ int JackCoreAudioDriver::SetupDevices(const char* capture_driver_uid, |
|
|
|
jack_error("Cannot get device name from device ID"); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
if (fHogged) { |
|
|
|
if (!TakeHogAux(fDeviceID, false)) { |
|
|
|
jack_error("Cannot take hog mode"); |
|
|
|
} |
|
|
|
if (ac3_encoding) { |
|
|
|
fDigitalPlayback = IsDigitalDevice(fDeviceID); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
// Creates aggregate device |
|
|
|
AudioDeviceID captureID, playbackID; |
|
|
|
|
|
|
|
AudioDeviceID captureID = -1; |
|
|
|
AudioDeviceID playbackID = -1; |
|
|
|
|
|
|
|
if (GetDeviceIDFromUID(capture_driver_uid, &captureID) != noErr) { |
|
|
|
jack_log("JackCoreAudioDriver::SetupDevices : will take default input"); |
|
|
|
if (GetDefaultInputDevice(&captureID) != noErr) { |
|
|
@@ -1170,7 +1273,20 @@ int JackCoreAudioDriver::SetupDevices(const char* capture_driver_uid, |
|
|
|
|
|
|
|
GetDeviceNameFromID(captureID, fCaptureUID); |
|
|
|
GetDeviceNameFromID(playbackID, fPlaybackUID); |
|
|
|
} |
|
|
|
|
|
|
|
if (fHogged) { |
|
|
|
if (!TakeHogAux(captureID, true)) { |
|
|
|
jack_error("Cannot take hog mode for capture device"); |
|
|
|
} |
|
|
|
if (!TakeHogAux(playbackID, false)) { |
|
|
|
jack_error("Cannot take hog mode for playback device"); |
|
|
|
} |
|
|
|
if (ac3_encoding) { |
|
|
|
fDigitalPlayback = IsDigitalDevice(playbackID); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// Capture only |
|
|
|
} else if (strcmp(capture_driver_uid, "") != 0) { |
|
|
@@ -1186,6 +1302,12 @@ int JackCoreAudioDriver::SetupDevices(const char* capture_driver_uid, |
|
|
|
jack_error("Cannot get device name from device ID"); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
if (fHogged) { |
|
|
|
if (!TakeHogAux(fDeviceID, true)) { |
|
|
|
jack_error("Cannot take hog mode for capture device"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Playback only |
|
|
|
} else if (strcmp(playback_driver_uid, "") != 0) { |
|
|
@@ -1201,6 +1323,15 @@ int JackCoreAudioDriver::SetupDevices(const char* capture_driver_uid, |
|
|
|
jack_error("Cannot get device name from device ID"); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
if (fHogged) { |
|
|
|
if (!TakeHogAux(fDeviceID, false)) { |
|
|
|
jack_error("Cannot take hog mode for playback device"); |
|
|
|
} |
|
|
|
if (ac3_encoding) { |
|
|
|
fDigitalPlayback = IsDigitalDevice(fDeviceID); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Use default driver in duplex mode |
|
|
|
} else { |
|
|
@@ -1209,8 +1340,9 @@ int JackCoreAudioDriver::SetupDevices(const char* capture_driver_uid, |
|
|
|
jack_error("Cannot open default device in duplex mode, so aggregate default input and default output"); |
|
|
|
|
|
|
|
// Creates aggregate device |
|
|
|
AudioDeviceID captureID, playbackID; |
|
|
|
|
|
|
|
AudioDeviceID captureID = -1; |
|
|
|
AudioDeviceID playbackID = -1; |
|
|
|
|
|
|
|
if (GetDeviceIDFromUID(capture_driver_uid, &captureID) != noErr) { |
|
|
|
jack_log("JackCoreAudioDriver::SetupDevices : will take default input"); |
|
|
|
if (GetDefaultInputDevice(&captureID) != noErr) { |
|
|
@@ -1233,15 +1365,21 @@ int JackCoreAudioDriver::SetupDevices(const char* capture_driver_uid, |
|
|
|
|
|
|
|
GetDeviceNameFromID(captureID, fCaptureUID); |
|
|
|
GetDeviceNameFromID(playbackID, fPlaybackUID); |
|
|
|
|
|
|
|
if (fHogged) { |
|
|
|
if (!TakeHogAux(captureID, true)) { |
|
|
|
jack_error("Cannot take hog mode for capture device"); |
|
|
|
} |
|
|
|
if (!TakeHogAux(playbackID, false)) { |
|
|
|
jack_error("Cannot take hog mode for playback device"); |
|
|
|
} |
|
|
|
if (ac3_encoding) { |
|
|
|
fDigitalPlayback = IsDigitalDevice(playbackID); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (fHogged) { |
|
|
|
if (TakeHog()) { |
|
|
|
jack_info("Device = %ld has been hogged", fDeviceID); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
@@ -1255,7 +1393,7 @@ int JackCoreAudioDriver::SetupChannels(bool capturing, bool playing, int& inchan |
|
|
|
if (capturing) { |
|
|
|
err = GetTotalChannels(fDeviceID, in_nChannels, true); |
|
|
|
if (err != noErr) { |
|
|
|
jack_error("JackCoreAudioDriver::SetupChannels : cannot get input channel number"); |
|
|
|
jack_error("SetupChannels : cannot get input channel number"); |
|
|
|
printError(err); |
|
|
|
return -1; |
|
|
|
} else { |
|
|
@@ -1335,7 +1473,7 @@ int JackCoreAudioDriver::SetupBufferSize(jack_nframes_t buffer_size) |
|
|
|
|
|
|
|
err = AudioDeviceSetProperty(fDeviceID, NULL, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyBufferFrameSize, outSize, &tmp_buffer_size); |
|
|
|
if (err != noErr) { |
|
|
|
jack_error("JackCoreAudioDriver::SetupBufferSize : cannot set buffer size = %ld", tmp_buffer_size); |
|
|
|
jack_error("SetupBufferSize : cannot set buffer size = %ld", tmp_buffer_size); |
|
|
|
printError(err); |
|
|
|
goto error; |
|
|
|
} |
|
|
@@ -1351,7 +1489,7 @@ int JackCoreAudioDriver::SetupBufferSize(jack_nframes_t buffer_size) |
|
|
|
} |
|
|
|
|
|
|
|
// Check new buffer size |
|
|
|
outSize = sizeof(UInt32); |
|
|
|
outSize = sizeof(UInt32); |
|
|
|
err = AudioDeviceGetProperty(fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyBufferFrameSize, &outSize, &tmp_buffer_size); |
|
|
|
if (err != noErr) { |
|
|
|
jack_error("Cannot get current buffer size"); |
|
|
@@ -1368,7 +1506,7 @@ int JackCoreAudioDriver::SetupBufferSize(jack_nframes_t buffer_size) |
|
|
|
|
|
|
|
error: |
|
|
|
|
|
|
|
// Remove SR change notification |
|
|
|
// Remove BS change notification |
|
|
|
AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyBufferFrameSize, BSNotificationCallback); |
|
|
|
return -1; |
|
|
|
|
|
|
@@ -1430,7 +1568,7 @@ int JackCoreAudioDriver::SetupSampleRateAux(AudioDeviceID inDevice, jack_nframes |
|
|
|
} |
|
|
|
|
|
|
|
// Check new sample rate |
|
|
|
outSize = sizeof(Float64); |
|
|
|
outSize = sizeof(Float64); |
|
|
|
err = AudioDeviceGetProperty(inDevice, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &tmp_sample_rate); |
|
|
|
if (err != noErr) { |
|
|
|
jack_error("Cannot get current sample rate"); |
|
|
@@ -1494,7 +1632,7 @@ int JackCoreAudioDriver::OpenAUHAL(bool capturing, |
|
|
|
printError(err1); |
|
|
|
goto error; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Start I/O |
|
|
|
if (capturing && inchannels > 0) { |
|
|
|
enableIO = 1; |
|
|
@@ -1850,7 +1988,10 @@ int JackCoreAudioDriver::Open(jack_nframes_t buffer_size, |
|
|
|
int async_output_latency, |
|
|
|
int computation_grain, |
|
|
|
bool hogged, |
|
|
|
bool clock_drift) |
|
|
|
bool clock_drift, |
|
|
|
bool ac3_encoding, |
|
|
|
int ac3_bitrate, |
|
|
|
bool ac3_lfe) |
|
|
|
{ |
|
|
|
int in_nChannels = 0; |
|
|
|
int out_nChannels = 0; |
|
|
@@ -1890,12 +2031,12 @@ int JackCoreAudioDriver::Open(jack_nframes_t buffer_size, |
|
|
|
AudioObjectPropertyAddress theAddress = { kAudioHardwarePropertyRunLoop, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; |
|
|
|
OSStatus osErr = AudioObjectSetPropertyData (kAudioObjectSystemObject, &theAddress, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop); |
|
|
|
if (osErr != noErr) { |
|
|
|
jack_error("JackCoreAudioDriver::Open kAudioHardwarePropertyRunLoop error"); |
|
|
|
jack_error("Open kAudioHardwarePropertyRunLoop error"); |
|
|
|
printError(osErr); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (SetupDevices(capture_driver_uid, playback_driver_uid, capture_driver_name, playback_driver_name, sample_rate) < 0) { |
|
|
|
|
|
|
|
if (SetupDevices(capture_driver_uid, playback_driver_uid, capture_driver_name, playback_driver_name, sample_rate, ac3_encoding) < 0) { |
|
|
|
goto error; |
|
|
|
} |
|
|
|
|
|
|
@@ -1911,7 +2052,7 @@ int JackCoreAudioDriver::Open(jack_nframes_t buffer_size, |
|
|
|
goto error; |
|
|
|
} |
|
|
|
|
|
|
|
if (SetupChannels(capturing, playing, inchannels, outchannels, in_nChannels, out_nChannels, true) < 0) { |
|
|
|
if (SetupChannels(capturing, playing, inchannels, outchannels, in_nChannels, out_nChannels, !ac3_encoding) < 0) { |
|
|
|
goto error; |
|
|
|
} |
|
|
|
|
|
|
@@ -1922,6 +2063,47 @@ int JackCoreAudioDriver::Open(jack_nframes_t buffer_size, |
|
|
|
if (SetupSampleRate(sample_rate) < 0) { |
|
|
|
goto error; |
|
|
|
} |
|
|
|
|
|
|
|
if (ac3_encoding) { |
|
|
|
|
|
|
|
if (!fDigitalPlayback) { |
|
|
|
jack_error("AC3 encoding can only be used with a digital device"); |
|
|
|
goto error; |
|
|
|
} |
|
|
|
|
|
|
|
JackAC3EncoderParams params; |
|
|
|
memset(¶ms, 0, sizeof(JackAC3EncoderParams)); |
|
|
|
params.bitrate = ac3_bitrate; |
|
|
|
params.channels = outchannels; |
|
|
|
params.sample_rate = sample_rate; |
|
|
|
params.lfe = ac3_lfe; |
|
|
|
fAC3Encoder = new JackAC3Encoder(params); |
|
|
|
|
|
|
|
if (!fAC3Encoder || !fAC3Encoder->Init(sample_rate)) { |
|
|
|
jack_error("Cannot allocate or init AC3 encoder"); |
|
|
|
goto error; |
|
|
|
} |
|
|
|
|
|
|
|
// Setup AC3 channel number |
|
|
|
fPlaybackChannels = outchannels; |
|
|
|
if (ac3_lfe) { |
|
|
|
fPlaybackChannels++; |
|
|
|
} |
|
|
|
|
|
|
|
if (fPlaybackChannels < 2 || fPlaybackChannels > 6) { |
|
|
|
jack_error("AC3 encoder channels must be between 2 and 6"); |
|
|
|
goto error; |
|
|
|
} |
|
|
|
|
|
|
|
// Force real output channel number to 2 |
|
|
|
outchannels = out_nChannels = 2; |
|
|
|
|
|
|
|
} else { |
|
|
|
fPlaybackChannels = outchannels; |
|
|
|
} |
|
|
|
|
|
|
|
// Core driver may have changed the in/out values |
|
|
|
fCaptureChannels = inchannels; |
|
|
|
|
|
|
|
if (OpenAUHAL(capturing, playing, inchannels, outchannels, in_nChannels, out_nChannels, parsed_chan_in_list, parsed_chan_out_list, buffer_size, sample_rate) < 0) { |
|
|
|
goto error; |
|
|
@@ -1936,10 +2118,7 @@ int JackCoreAudioDriver::Open(jack_nframes_t buffer_size, |
|
|
|
if (AddListeners() < 0) { |
|
|
|
goto error; |
|
|
|
} |
|
|
|
|
|
|
|
// Core driver may have changed the in/out values |
|
|
|
fCaptureChannels = inchannels; |
|
|
|
fPlaybackChannels = outchannels; |
|
|
|
|
|
|
|
return noErr; |
|
|
|
|
|
|
|
error: |
|
|
@@ -2112,6 +2291,15 @@ int JackCoreAudioDriver::Attach() |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (fAC3Encoder) { |
|
|
|
// Setup specific AC3 channels names |
|
|
|
for (int i = 0; i < fPlaybackChannels; i++) { |
|
|
|
fAC3Encoder->GetChannelName("coreaudio", "", alias, i); |
|
|
|
port = fGraphManager->GetPort(fPlaybackPortList[i]); |
|
|
|
port->SetAlias(alias); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
UpdateLatencies(); |
|
|
|
|
|
|
@@ -2194,6 +2382,8 @@ bool JackCoreAudioDriver::TakeHogAux(AudioDeviceID deviceID, bool isInput) |
|
|
|
jack_error("Cannot read hog state..."); |
|
|
|
printError(err); |
|
|
|
} |
|
|
|
|
|
|
|
jack_log("JackCoreAudioDriver::TakeHogAux : deviceID = %d", deviceID); |
|
|
|
|
|
|
|
if (hog_pid != getpid()) { |
|
|
|
hog_pid = getpid(); |
|
|
@@ -2274,6 +2464,15 @@ extern "C" |
|
|
|
|
|
|
|
value.i = 0; |
|
|
|
jack_driver_descriptor_add_parameter(desc, &filler, "monitor", 'm', JackDriverParamBool, &value, NULL, "Provide monitor ports for the output", NULL); |
|
|
|
|
|
|
|
value.i = 0; |
|
|
|
jack_driver_descriptor_add_parameter(desc, &filler, "AC3-encoding", 'a', JackDriverParamBool, &value, NULL, "AC3 multi-channels encoding", NULL); |
|
|
|
|
|
|
|
value.i = 448; |
|
|
|
jack_driver_descriptor_add_parameter(desc, &filler, "AC3-bitrate", 'b', JackDriverParamUInt, &value, NULL, "AC3 bitrate", NULL); |
|
|
|
|
|
|
|
value.i = 0; |
|
|
|
jack_driver_descriptor_add_parameter(desc, &filler, "AC3-LFE", 'f', JackDriverParamBool, &value, NULL, "AC3 LFE channel", NULL); |
|
|
|
|
|
|
|
value.i = TRUE; |
|
|
|
jack_driver_descriptor_add_parameter(desc, &filler, "duplex", 'D', JackDriverParamBool, &value, NULL, "Provide both capture and playback ports", NULL); |
|
|
@@ -2330,6 +2529,9 @@ extern "C" |
|
|
|
int computation_grain = -1; |
|
|
|
bool hogged = false; |
|
|
|
bool clock_drift = false; |
|
|
|
bool ac3_encoding = false; |
|
|
|
int ac3_bitrate = 448; |
|
|
|
bool ac3_lfe = false; |
|
|
|
|
|
|
|
for (node = params; node; node = jack_slist_next(node)) { |
|
|
|
param = (const jack_driver_param_t *) node->data; |
|
|
@@ -2383,6 +2585,18 @@ extern "C" |
|
|
|
case 'm': |
|
|
|
monitor = param->value.i; |
|
|
|
break; |
|
|
|
|
|
|
|
case 'a': |
|
|
|
ac3_encoding = param->value.i; |
|
|
|
break; |
|
|
|
|
|
|
|
case 'b': |
|
|
|
ac3_bitrate = param->value.i; |
|
|
|
break; |
|
|
|
|
|
|
|
case 'f': |
|
|
|
ac3_lfe = param->value.i; |
|
|
|
break; |
|
|
|
|
|
|
|
case 'r': |
|
|
|
srate = param->value.ui; |
|
|
@@ -2449,7 +2663,8 @@ extern "C" |
|
|
|
systemic_output_latency, |
|
|
|
async_output_latency, |
|
|
|
computation_grain, |
|
|
|
hogged, clock_drift) == 0) { |
|
|
|
hogged, clock_drift, |
|
|
|
ac3_encoding, ac3_bitrate, ac3_lfe) == 0) { |
|
|
|
return driver; |
|
|
|
} else { |
|
|
|
delete driver; |
|
|
|