Commit ea9f5872 authored by sletz's avatar sletz
Browse files

Better parameter handling in JackCoreAudioAdapter.

git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@2808 0c269be4-1314-0410-8aa9-9f06e86f4224
parent 4f97d39e
......@@ -22,6 +22,10 @@ Florian Faber
Jackdmp changes log
---------------------------
2008-08-26 Stephane Letz <letz@grame.fr>
* Better parameter handling in JackCoreAudioAdapter.
2008-08-22 Stephane Letz <letz@grame.fr>
* Move GetCurrentTransportFrame code from JackClient to JackTransportEngine.
......
......@@ -127,13 +127,13 @@ namespace Jack
int JackAudioAdapter::Open()
{
jack_log("JackAudioAdapter::Open");
int i;
char name[32];
fCaptureChannels = fAudioAdapter->GetInputs();
fPlaybackChannels = fAudioAdapter->GetOutputs();
jack_log("JackAudioAdapter::Open fCaptureChannels %d fPlaybackChannels %d", fCaptureChannels, fPlaybackChannels);
//ringbuffers
fCaptureRingBuffer = new JackResampler*[fCaptureChannels];
......
......@@ -51,26 +51,31 @@ extern "C"
Jack::JackAudioAdapter* adapter;
jack_nframes_t buffer_size = jack_get_buffer_size(jack_client);
jack_nframes_t sample_rate = jack_get_sample_rate(jack_client);
#ifdef __linux__
adapter = new Jack::JackAudioAdapter(jack_client, new Jack::JackAlsaAdapter(buffer_size, sample_rate, params));
#endif
#ifdef WIN32
adapter = new Jack::JackAudioAdapter(jack_client, new Jack::JackPortAudioAdapter(buffer_size, sample_rate, params));
#endif
#ifdef __APPLE__
adapter = new Jack::JackAudioAdapter(jack_client, new Jack::JackCoreAudioAdapter(buffer_size, sample_rate, params));
#endif
assert(adapter);
if (adapter->Open() == 0)
return 0;
else
{
delete adapter;
try {
#ifdef __linux__
adapter = new Jack::JackAudioAdapter(jack_client, new Jack::JackAlsaAdapter(buffer_size, sample_rate, params));
#endif
#ifdef WIN32
adapter = new Jack::JackAudioAdapter(jack_client, new Jack::JackPortAudioAdapter(buffer_size, sample_rate, params));
#endif
#ifdef __APPLE__
adapter = new Jack::JackAudioAdapter(jack_client, new Jack::JackCoreAudioAdapter(buffer_size, sample_rate, params));
#endif
assert(adapter);
if (adapter->Open() == 0)
return 0;
else
{
delete adapter;
return 1;
}
} catch (...) {
return 1;
}
}
......
......@@ -28,6 +28,54 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
namespace Jack
{
static OSStatus DisplayDeviceNames()
{
UInt32 size;
Boolean isWritable;
int i, deviceNum;
OSStatus err;
CFStringRef UIname;
err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &size, &isWritable);
if (err != noErr)
return err;
deviceNum = size / sizeof(AudioDeviceID);
AudioDeviceID devices[deviceNum];
err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &size, devices);
if (err != noErr)
return err;
for (i = 0; i < deviceNum; i++) {
char device_name[256];
char internal_name[256];
size = sizeof(CFStringRef);
UIname = NULL;
err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceUID, &size, &UIname);
if (err == noErr) {
CFStringGetCString(UIname, internal_name, 256, CFStringGetSystemEncoding());
} else {
goto error;
}
size = 256;
err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceName, &size, device_name);
if (err != noErr)
return err;
jack_info("Device name = \'%s\', internal_name = \'%s\' (to be used as -C, -P, or -d parameter)", device_name, internal_name);
}
return noErr;
error:
if (UIname != NULL)
CFRelease(UIname);
return err;
}
static void printError(OSStatus err)
{
switch (err) {
......@@ -117,6 +165,136 @@ OSStatus JackCoreAudioAdapter::SRNotificationCallback(AudioDeviceID inDevice,
return noErr;
}
// A better implementation would try to recover in case of hardware device change (see HALLAB HLFilePlayerWindowControllerAudioDevicePropertyListenerProc code)
OSStatus JackCoreAudioAdapter::DeviceNotificationCallback(AudioDeviceID inDevice,
UInt32 inChannel,
Boolean isInput,
AudioDevicePropertyID inPropertyID,
void* inClientData)
{
JackCoreAudioAdapter* driver = (JackCoreAudioAdapter*)inClientData;
switch (inPropertyID) {
case kAudioDevicePropertyStreamConfiguration:
case kAudioDevicePropertyNominalSampleRate: {
UInt32 outSize = sizeof(Float64);
Float64 sampleRate;
int in_nChannels = 0;
int out_nChannels = 0;
char capture_driver_name[256];
char playback_driver_name[256];
// Stop and restart
AudioOutputUnitStop(driver->fAUHAL);
driver->RemoveListeners();
driver->CloseAUHAL();
OSStatus err = AudioDeviceGetProperty(driver->fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate);
if (err != noErr) {
jack_error("Cannot get current sample rate");
printError(err);
}
jack_log("JackCoreAudioDriver::DeviceNotificationCallback kAudioDevicePropertyNominalSampleRate %ld", long(sampleRate));
if (driver->SetupDevices(driver->fCaptureUID, driver->fPlaybackUID, capture_driver_name, playback_driver_name) < 0)
return -1;
if (driver->SetupChannels(driver->fCapturing, driver->fPlaying, driver->fCaptureChannels, driver->fPlaybackChannels, in_nChannels, out_nChannels, false) < 0)
return -1;
if (driver->SetupBufferSizeAndSampleRate(driver->fAdaptedBufferSize, sampleRate) < 0)
return -1;
driver->SetAdaptedSampleRate(sampleRate);
if (driver->OpenAUHAL(driver->fCapturing,
driver->fPlaying,
driver->fCaptureChannels,
driver->fPlaybackChannels,
in_nChannels,
out_nChannels,
driver->fAdaptedBufferSize,
sampleRate,
false) < 0)
goto error;
if (driver->AddListeners() < 0)
goto error;
AudioOutputUnitStart(driver->fAUHAL);
return noErr;
error:
driver->CloseAUHAL();
break;
}
}
return noErr;
}
int JackCoreAudioAdapter::AddListeners()
{
OSStatus err = noErr;
// Add listeners
err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioHardwarePropertyDevices, DeviceNotificationCallback, this);
if (err != noErr) {
jack_error("Error calling AudioDeviceAddPropertyListener with kAudioHardwarePropertyDevices");
printError(err);
return -1;
}
err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, DeviceNotificationCallback, this);
if (err != noErr) {
jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate");
printError(err);
return -1;
}
err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceIsRunning, DeviceNotificationCallback, this);
if (err != noErr) {
jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyDeviceIsRunning");
printError(err);
return -1;
}
err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback, this);
if (err != noErr) {
jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyStreamConfiguration");
printError(err);
return -1;
}
err = AudioDeviceAddPropertyListener(fDeviceID, 0, false, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback, this);
if (err != noErr) {
jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyStreamConfiguration");
printError(err);
return -1;
}
return 0;
}
void JackCoreAudioAdapter::RemoveListeners()
{
/*
#ifdef MAC_OS_X_VERSION_10_5
AudioDeviceDestroyIOProcID(fDeviceID, fMesureCallbackID);
#else
AudioDeviceRemoveIOProc(fDeviceID, MeasureCallback);
#endif
*/
AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioHardwarePropertyDevices, DeviceNotificationCallback);
AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, DeviceNotificationCallback);
AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyDeviceIsRunning, DeviceNotificationCallback);
AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback);
AudioDeviceRemovePropertyListener(fDeviceID, 0, false, kAudioDevicePropertyStreamConfiguration, DeviceNotificationCallback);
}
OSStatus JackCoreAudioAdapter::Render(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
......@@ -153,19 +331,27 @@ OSStatus JackCoreAudioAdapter::Render(void *inRefCon,
jack_error("JackCoreAudioAdapter::Render ringbuffer failure... reset");
adapter->ResetRingBuffers();
}
return noErr;
}
JackCoreAudioAdapter::JackCoreAudioAdapter(jack_nframes_t buffer_size, jack_nframes_t sample_rate, const JSList* params)
:JackAudioAdapterInterface(buffer_size, sample_rate),fInputData(0),fCapturing(false),fPlaying(false),fState(false)
:JackAudioAdapterInterface(buffer_size, sample_rate), fInputData(0), fCapturing(false), fPlaying(false), fState(false)
{
const JSList* node;
const jack_driver_param_t* param;
fCaptureChannels = 2;
fPlaybackChannels = 2;
char captureName[256];
char playbackName[256];
fCaptureUID[0] = 0;
fPlaybackUID[0] = 0;
// Default values
fCaptureChannels = 0;
fPlaybackChannels = 0;
for (node = params; node; node = jack_slist_next(node)) {
param = (const jack_driver_param_t*) node->data;
......@@ -185,12 +371,17 @@ OSStatus JackCoreAudioAdapter::Render(void *inRefCon,
case 'C':
fCapturing = true;
strncpy(fCaptureName, param->value.str, strlen(param->value.str));
strncpy(fCaptureUID, param->value.str, 256);
break;
case 'P':
fPlaying = true;
strncpy(fPlaybackName, param->value.str, strlen(param->value.str));
strncpy(fPlaybackUID, param->value.str, 256);
break;
case 'd':
strncpy(fCaptureUID, param->value.str, 256);
strncpy(fPlaybackUID, param->value.str, 256);
break;
case 'D':
......@@ -206,9 +397,38 @@ OSStatus JackCoreAudioAdapter::Render(void *inRefCon,
break;
case 'l':
DisplayDeviceNames();
break;
}
}
/* duplex is the default */
if (!fCapturing && !fPlaying) {
fCapturing = true;
fPlaying = true;
}
int in_nChannels = 0;
int out_nChannels = 0;
if (SetupDevices(fCaptureUID, fPlaybackUID, captureName, playbackName) < 0)
throw -1;
if (SetupChannels(fCapturing, fPlaying, fCaptureChannels, fPlaybackChannels, in_nChannels, out_nChannels, true) < 0)
throw -1;
if (SetupBufferSizeAndSampleRate(fAdaptedBufferSize, fAdaptedSampleRate) < 0)
throw -1;
if (fCapturing && fCaptureChannels > 0)
if (SetupBuffers(fCaptureChannels) < 0)
throw -1;
if (OpenAUHAL(fCapturing, fPlaying, fCaptureChannels, fPlaybackChannels, in_nChannels, out_nChannels, fAdaptedBufferSize, fAdaptedSampleRate, true) < 0)
throw -1;
if (AddListeners() < 0)
throw -1;
}
OSStatus JackCoreAudioAdapter::GetDefaultDevice(AudioDeviceID* id)
......@@ -236,21 +456,21 @@ OSStatus JackCoreAudioAdapter::GetDefaultDevice(AudioDeviceID* id)
}
}
OSStatus JackCoreAudioAdapter::GetTotalChannels(AudioDeviceID device, int* channelCount, bool isInput)
OSStatus JackCoreAudioAdapter::GetTotalChannels(AudioDeviceID device, int& channelCount, bool isInput)
{
OSStatus err = noErr;
UInt32 outSize;
Boolean outWritable;
AudioBufferList* bufferList = 0;
*channelCount = 0;
channelCount = 0;
err = AudioDeviceGetPropertyInfo(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize, &outWritable);
if (err == noErr) {
bufferList = (AudioBufferList*)malloc(outSize);
err = AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize, bufferList);
if (err == noErr) {
for (unsigned int i = 0; i < bufferList->mNumberBuffers; i++)
*channelCount += bufferList->mBuffers[i].mNumberChannels;
channelCount += bufferList->mBuffers[i].mNumberChannels;
}
if (bufferList)
......@@ -271,7 +491,7 @@ OSStatus JackCoreAudioAdapter::GetDeviceIDFromUID(const char* UID, AudioDeviceID
} else {
OSStatus res = AudioHardwareGetProperty(kAudioHardwarePropertyDeviceForUID, &size, &value);
CFRelease(inIUD);
jack_log("get_device_id_from_uid %s %ld ", UID, *id);
jack_log("GetDeviceIDFromUID %s %ld", UID, *id);
return (*id == kAudioDeviceUnknown) ? kAudioHardwareBadDeviceError : res;
}
}
......@@ -321,7 +541,7 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid,
// Duplex
if (strcmp(capture_driver_uid, "") != 0 && strcmp(playback_driver_uid, "") != 0) {
jack_log("JackCoreAudioDriver::Open duplex ");
jack_log("JackCoreAudioAdapter::Open duplex");
if (GetDeviceIDFromUID(playback_driver_uid, &fDeviceID) != noErr) {
if (GetDefaultDevice(&fDeviceID) != noErr) {
jack_error("Cannot open default device");
......@@ -335,7 +555,7 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid,
// Capture only
} else if (strcmp(capture_driver_uid, "") != 0) {
jack_log("JackCoreAudioDriver::Open capture only ");
jack_log("JackCoreAudioAdapter::Open capture only");
if (GetDeviceIDFromUID(capture_driver_uid, &fDeviceID) != noErr) {
if (GetDefaultInputDevice(&fDeviceID) != noErr) {
jack_error("Cannot open default device");
......@@ -349,7 +569,7 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid,
// Playback only
} else if (strcmp(playback_driver_uid, "") != 0) {
jack_log("JackCoreAudioDriver::Open playback only ");
jack_log("JackCoreAudioAdapter::Open playback only");
if (GetDeviceIDFromUID(playback_driver_uid, &fDeviceID) != noErr) {
if (GetDefaultOutputDevice(&fDeviceID) != noErr) {
jack_error("Cannot open default device");
......@@ -363,7 +583,7 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid,
// Use default driver in duplex mode
} else {
jack_log("JackCoreAudioDriver::Open default driver ");
jack_log("JackCoreAudioAdapter::Open default driver");
if (GetDefaultDevice(&fDeviceID) != noErr) {
jack_error("Cannot open default device");
return -1;
......@@ -375,7 +595,6 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid,
}
return 0;
}
int JackCoreAudioAdapter::SetupChannels(bool capturing,
......@@ -388,18 +607,44 @@ int JackCoreAudioAdapter::SetupChannels(bool capturing,
{
OSStatus err = noErr;
err = GetTotalChannels(fDeviceID, &in_nChannels, true);
if (err != noErr) {
jack_error("Cannot get input channel number");
printError(err);
return -1;
if (capturing) {
err = GetTotalChannels(fDeviceID, in_nChannels, true);
if (err != noErr) {
jack_error("Cannot get input channel number");
printError(err);
return -1;
}
}
err = GetTotalChannels(fDeviceID, &out_nChannels, false);
if (err != noErr) {
jack_error("Cannot get output channel number");
printError(err);
return -1;
if (playing) {
err = GetTotalChannels(fDeviceID, out_nChannels, false);
if (err != noErr) {
jack_error("Cannot get output channel number");
printError(err);
return -1;
}
}
if (inchannels > in_nChannels) {
jack_error("This device hasn't required input channels inchannels = %ld in_nChannels = %ld", inchannels, in_nChannels);
if (strict)
return -1;
}
if (outchannels > out_nChannels) {
jack_error("This device hasn't required output channels outchannels = %ld out_nChannels = %ld", outchannels, out_nChannels);
if (strict)
return -1;
}
if (inchannels == 0) {
jack_log("Setup max in channels = %ld", in_nChannels);
inchannels = in_nChannels;
}
if (outchannels == 0) {
jack_log("Setup max out channels = %ld", out_nChannels);
outchannels = out_nChannels;
}
return 0;
......@@ -461,9 +706,9 @@ int JackCoreAudioAdapter::SetupBufferSizeAndSampleRate(jack_nframes_t nframes, j
return 0;
}
int JackCoreAudioAdapter::SetupBuffers(int inchannels, int outchannels)
int JackCoreAudioAdapter::SetupBuffers(int inchannels)
{
jack_log("JackCoreAudioAdapter::SetupBuffers: input = %ld output = %ld", inchannels, outchannels);
jack_log("JackCoreAudioAdapter::SetupBuffers: input = %ld", inchannels);
// Prepare buffers
fInputData = (AudioBufferList*)malloc(sizeof(UInt32) + inchannels * sizeof(AudioBuffer));
......@@ -504,7 +749,7 @@ int JackCoreAudioAdapter::OpenAUHAL(bool capturing,
UInt32 enableIO;
AudioStreamBasicDescription srcFormat, dstFormat;
jack_log("OpenAUHAL capturing = %ld playing = %ld playing = %ld outchannels = %ld in_nChannels = %ld out_nChannels = %ld ", capturing, playing, inchannels, inchannels, in_nChannels, out_nChannels);
jack_log("OpenAUHAL capturing = %ld playing = %ld inchannels = %ld outchannels = %ld in_nChannels = %ld out_nChannels = %ld ", capturing, playing, inchannels, outchannels, in_nChannels, out_nChannels);
// AUHAL
ComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_HALOutput, kAudioUnitManufacturer_Apple, 0, 0};
......@@ -676,35 +921,7 @@ void JackCoreAudioAdapter::CloseAUHAL()
int JackCoreAudioAdapter::Open()
{
OSStatus err;
int in_nChannels = 0;
int out_nChannels = 0;
if (SetupDevices(fCaptureUID, fPlaybackUID, fCaptureName, fPlaybackName) < 0)
return -1;
if (SetupChannels(fCapturing, fPlaying, fCaptureChannels, fPlaybackChannels, in_nChannels, out_nChannels, true) < 0)
return -1;
if (SetupBufferSizeAndSampleRate(fAdaptedBufferSize, fAdaptedSampleRate) < 0)
return -1;
if (OpenAUHAL(fCapturing, fPlaying, fCaptureChannels, fPlaybackChannels, in_nChannels, out_nChannels, fAdaptedBufferSize, fAdaptedSampleRate, true) < 0)
goto error;
if (fCapturing && fCaptureChannels > 0)
if (SetupBuffers(fCaptureChannels, fPlaybackChannels) < 0)
goto error;
err = AudioOutputUnitStart(fAUHAL);
if (err != noErr)
goto error;
return 0;
error:
Close();
return -1;
return (AudioOutputUnitStart(fAUHAL) != noErr) ? -1 : 0;
}
int JackCoreAudioAdapter::Close()
......
......@@ -50,10 +50,7 @@ class JackCoreAudioAdapter : public JackAudioAdapterInterface
char fCaptureUID[256];
char fPlaybackUID[256];
char fCaptureName[256];
char fPlaybackName[256];
bool fCapturing;
bool fPlaying;
......@@ -75,9 +72,14 @@ class JackCoreAudioAdapter : public JackAudioAdapterInterface
Boolean isInput,
AudioDevicePropertyID inPropertyID,
void* inClientData);
static OSStatus DeviceNotificationCallback(AudioDeviceID inDevice,
UInt32 inChannel,
Boolean isInput,
AudioDevicePropertyID inPropertyID,
void* inClientData);
OSStatus GetDefaultDevice(AudioDeviceID* id);
OSStatus GetTotalChannels(AudioDeviceID device, int* channelCount, bool isInput);
OSStatus GetTotalChannels(AudioDeviceID device, int& channelCount, bool isInput);
OSStatus GetDeviceIDFromUID(const char* UID, AudioDeviceID* id);
OSStatus GetDefaultInputDevice(AudioDeviceID* id);
OSStatus GetDefaultOutputDevice(AudioDeviceID* id);
......@@ -108,9 +110,12 @@ class JackCoreAudioAdapter : public JackAudioAdapterInterface
bool strict);
int SetupBufferSizeAndSampleRate(jack_nframes_t buffer_size, jack_nframes_t samplerate);
int SetupBuffers(int inchannels, int outchannels);
int SetupBuffers(int inchannels);
void DisposeBuffers();
void CloseAUHAL();
int AddListeners();
void RemoveListeners();
public:
......
......@@ -333,7 +333,7 @@ OSStatus JackCoreAudioDriver::GetDeviceIDFromUID(const char* UID, AudioDeviceID*
} else {
OSStatus res = AudioHardwareGetProperty(kAudioHardwarePropertyDeviceForUID, &size, &value);
CFRelease(inIUD);
jack_log("get_device_id_from_uid %s %ld ", UID, *id);
jack_log("GetDeviceIDFromUID %s %ld", UID, *id);
return (*id == kAudioDeviceUnknown) ? kAudioHardwareBadDeviceError : res;
}
}
......@@ -397,21 +397,21 @@ OSStatus JackCoreAudioDriver::GetDeviceNameFromID(AudioDeviceID id, char* name)
return AudioDeviceGetProperty(id, 0, false, kAudioDevicePropertyDeviceName, &size, name);
}
OSStatus JackCoreAudioDriver::GetTotalChannels(AudioDeviceID device, int* channelCount, bool isInput)
OSStatus JackCoreAudioDriver::GetTotalChannels(AudioDeviceID device, int& channelCount, bool isInput)
{
OSStatus err = noErr;
UInt32 outSize;
Boolean outWritable;
AudioBufferList* bufferList = 0;