Browse Source

JackCoreAudioIOAdapter working

git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@2589 0c269be4-1314-0410-8aa9-9f06e86f4224
tags/1.90
sletz 17 years ago
parent
commit
d9c60823d2
11 changed files with 852 additions and 126 deletions
  1. +64
    -0
      common/JackFilters.h
  2. +1
    -0
      common/JackIOAdapter.h
  3. +3
    -2
      common/JackNetIOAdapter.cpp
  4. +153
    -0
      common/JackResampler.cpp
  5. +63
    -0
      common/JackResampler.h
  6. +2
    -2
      common/wscript
  7. +1
    -1
      macosx/JackCoreAudioDriver.cpp
  8. +512
    -56
      macosx/JackCoreAudioIOAdapter.cpp
  9. +36
    -17
      macosx/JackCoreAudioIOAdapter.h
  10. +13
    -17
      windows/JackPortAudioIOAdapter.cpp
  11. +4
    -31
      windows/JackPortAudioIOAdapter.h

+ 64
- 0
common/JackFilters.h View File

@@ -0,0 +1,64 @@
/*
Copyright (C) 2008 Grame

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

#ifndef __JackFilters__
#define __JackFilters__

#include "jack.h"

namespace Jack
{

#define MAX_SIZE 64
struct JackFilter
{
jack_time_t fTable[MAX_SIZE];
JackFilter()
{
for (int i = 0; i < MAX_SIZE; i++)
fTable[i] = 0;
}
void AddValue(jack_time_t val)
{
memcpy(&fTable[1], &fTable[0], sizeof(jack_time_t) * (MAX_SIZE - 1));
fTable[0] = val;
}
jack_time_t GetVal()
{
jack_time_t mean = 0;
for (int i = 0; i < MAX_SIZE; i++)
mean += fTable[i];
return mean / MAX_SIZE;
}
};
inline float Range(float min, float max, float val)
{
return (val < min) ? min : ((val > max) ? max : val);
}

}

#endif

+ 1
- 0
common/JackIOAdapter.h View File

@@ -25,6 +25,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#include "JackError.h"
#include "JackResampler.h"
#include <samplerate.h>
#include <stdio.h>

namespace Jack
{


+ 3
- 2
common/JackNetIOAdapter.cpp View File

@@ -115,9 +115,10 @@ extern "C"
return 1;
} else {
jack_log("Loading NetAudio Adapter");
// adapter = new Jack::JackNetIOAdapter(jack_client, new Jack::JackCoreAudioIOAdapter(2, 2, 512, 44100.f), 2, 2);
adapter = new Jack::JackCallbackNetIOAdapter(jack_client,
new Jack::JackPortAudioIOAdapter(2, 2, jack_get_buffer_size(jack_client), jack_get_sample_rate(jack_client)), 2, 2);
new Jack::JackCoreAudioIOAdapter(2, 2, jack_get_buffer_size(jack_client), jack_get_sample_rate(jack_client)), 2, 2);
//adapter = new Jack::JackCallbackNetIOAdapter(jack_client,
// new Jack::JackPortAudioIOAdapter(2, 2, jack_get_buffer_size(jack_client), jack_get_sample_rate(jack_client)), 2, 2);
assert(adapter);
if (adapter->Open() == 0) {


+ 153
- 0
common/JackResampler.cpp View File

@@ -0,0 +1,153 @@
/*
Copyright (C) 2008 Grame

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

#include "JackResampler.h"

namespace Jack
{

JackResampler::JackResampler():fRatio(0)
{
int error;
fResampler = src_new(SRC_LINEAR, 1, &error);
if (error != 0)
jack_error("JackResampler::JackResampler err = %s", src_strerror(error));
fRingBuffer = jack_ringbuffer_create(sizeof(float) * DEFAULT_RB_SIZE);
}

JackResampler::~JackResampler()
{
src_delete(fResampler);
if (fRingBuffer)
jack_ringbuffer_free(fRingBuffer);
}

int JackResampler::Read(float* buffer, unsigned int frames)
{
size_t len = jack_ringbuffer_read_space(fRingBuffer);
jack_log("JackResampler::Read INPUT available = %ld", len / sizeof(float));
if (len < frames * sizeof(float)) {
jack_error("JackResampler::Read : producer too slow, skip frames = %d", frames);
//jack_ringbuffer_read(fRingBuffer, buffer, len);
return 0;
} else {
jack_ringbuffer_read(fRingBuffer, (char*)buffer, frames * sizeof(float));
return frames;
}
}

int JackResampler::Write(float* buffer, unsigned int frames)
{
size_t len = jack_ringbuffer_write_space(fRingBuffer);
jack_log("JackResampler::Write OUTPUT available = %ld", len / sizeof(float));
if (len < frames * sizeof(float)) {
jack_error("JackResampler::Write : consumer too slow, missing frames = %d", frames);
//jack_ringbuffer_write(fRingBuffer, buffer, len);
return 0;
} else {
jack_ringbuffer_write(fRingBuffer, (char*)buffer, frames * sizeof(float));
return frames;
}
}

int JackResampler::ReadResample(float* buffer, unsigned int frames)
{
jack_ringbuffer_data_t ring_buffer_data[2];
SRC_DATA src_data;
unsigned int frames_to_write = frames;
unsigned int written_frames = 0;
int res;
jack_ringbuffer_get_read_vector(fRingBuffer, ring_buffer_data);
unsigned int available_frames = (ring_buffer_data[0].len + ring_buffer_data[1].len) / sizeof(float);
jack_log("OUPUT available = %ld", available_frames);
for (int j = 0; j < 2; j++) {
if (ring_buffer_data[j].len > 0) {
src_data.data_in = (float*)ring_buffer_data[j].buf;
src_data.data_out = &buffer[written_frames];
src_data.input_frames = ring_buffer_data[j].len / sizeof(float);
src_data.output_frames = frames_to_write;
src_data.end_of_input = 0;
src_data.src_ratio = fRatio;
res = src_process(fResampler, &src_data);
if (res != 0)
jack_error("JackPortAudioIOAdapter::Render err = %s", src_strerror(res));
frames_to_write -= src_data.output_frames_gen;
written_frames += src_data.output_frames_gen;
jack_log("OUTPUT : j = %d input_frames_used = %ld output_frames_gen = %ld", j, src_data.input_frames_used, src_data.output_frames_gen);
jack_ringbuffer_read_advance(fRingBuffer, src_data.input_frames_used * sizeof(float));
}
}
if (written_frames < frames)
jack_error("JackPortAudioIOAdapter::Render error written_frames = %ld", written_frames);
return written_frames;
}

int JackResampler::WriteResample(float* buffer, unsigned int frames)
{
jack_ringbuffer_data_t ring_buffer_data[2];
SRC_DATA src_data;
unsigned int frames_to_read = frames;
unsigned int read_frames = 0;
int res;
jack_ringbuffer_get_write_vector(fRingBuffer, ring_buffer_data);
unsigned int available_frames = (ring_buffer_data[0].len + ring_buffer_data[1].len) / sizeof(float);
jack_log("INPUT available = %ld", available_frames);
for (int j = 0; j < 2; j++) {
if (ring_buffer_data[j].len > 0) {
src_data.data_in = &buffer[read_frames];
src_data.data_out = (float*)ring_buffer_data[j].buf;
src_data.input_frames = frames_to_read;
src_data.output_frames = (ring_buffer_data[j].len / sizeof(float));
src_data.end_of_input = 0;
src_data.src_ratio = fRatio;
res = src_process(fResampler, &src_data);
if (res != 0)
jack_error("JackPortAudioIOAdapter::Render err = %s", src_strerror(res));
frames_to_read -= src_data.input_frames_used;
read_frames += src_data.input_frames_used;
jack_log("INPUT : j = %d input_frames_used = %ld output_frames_gen = %ld", j, src_data.input_frames_used, src_data.output_frames_gen);
jack_ringbuffer_write_advance(fRingBuffer, src_data.output_frames_gen * sizeof(float));
}
}
if (read_frames < frames)
jack_error("JackPortAudioIOAdapter::Render error read_frames = %ld", read_frames);
return read_frames;
}

}

+ 63
- 0
common/JackResampler.h View File

@@ -0,0 +1,63 @@
/*
Copyright (C) 2008 Grame

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

#ifndef __JackResampler__
#define __JackResampler__

#include "ringbuffer.h"
#include "JackError.h"
#include <samplerate.h>

namespace Jack
{

#define DEFAULT_RB_SIZE 16384

class JackResampler
{
protected:
SRC_STATE* fResampler;
jack_ringbuffer_t* fRingBuffer;
double fRatio;
public:
JackResampler();
virtual ~JackResampler();
int ReadResample(float* buffer, unsigned int frames);
int WriteResample(float* buffer, unsigned int frames);
int Read(float* buffer, unsigned int frames);
int Write(float* buffer, unsigned int frames);
void SetRatio(double ratio)
{
fRatio = ratio;
}
double GetRatio()
{
return fRatio;
}
};
}

#endif

+ 2
- 2
common/wscript View File

@@ -194,9 +194,9 @@ def build(bld):

create_jack_process_obj(bld, 'netmanager', 'JackNetManager.cpp', serverlib)

#create_jack_process_obj(bld, 'netioadapter', 'JackNetIOAdapter.cpp ../macosx/JackCoreAudioIOAdapter.cpp', serverlib)
process = create_jack_process_obj(bld, 'netioadapter', 'JackResampler.cpp JackIOAdapter.cpp JackNetIOAdapter.cpp JackCallbackNetIOAdapter.cpp ../macosx/JackCoreAudioIOAdapter.cpp', serverlib)
#process = create_jack_process_obj(bld, 'netioadapter', 'JackResampler.cpp JackIOAdapter.cpp JackNetIOAdapter.cpp JackCallbackNetIOAdapter.cpp ../windows/JackPortAudioIOAdapter.cpp', serverlib)

process = create_jack_process_obj(bld, 'netioadapter', 'JackResampler.cpp JackIOAdapter.cpp JackNetIOAdapter.cpp JackCallbackNetIOAdapter.cpp ../windows/JackPortAudioIOAdapter.cpp', serverlib)
process.env.append_value("LINKFLAGS", "-lsamplerate")
if bld.env()['IS_MACOSX']:
process.env.append_value("LINKFLAGS", "../macosx/libportaudio.a -framework CoreAudio -framework AudioUnit -framework AudioToolbox -framework CoreServices")


+ 1
- 1
macosx/JackCoreAudioDriver.cpp View File

@@ -224,7 +224,7 @@ OSStatus JackCoreAudioDriver::SRNotificationCallback(AudioDeviceID inDevice,
switch (inPropertyID) {

case kAudioDevicePropertyNominalSampleRate: {
jack_log("JackCoreAudioDriver::SRNotificationCallback kAudioDevicePropertyNominalSampleRate ");
jack_log("JackCoreAudioDriver::SRNotificationCallback kAudioDevicePropertyNominalSampleRate");
driver->fState = true;
break;
}


+ 512
- 56
macosx/JackCoreAudioIOAdapter.cpp View File

@@ -19,110 +19,566 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

#include "JackCoreAudioIOAdapter.h"
#include "JackError.h"
#include <unistd.h>

namespace Jack
{

static void printError(OSStatus err)
{
switch (err) {
case kAudioHardwareNoError:
jack_log("error code : kAudioHardwareNoError");
break;
case kAudioConverterErr_FormatNotSupported:
jack_log("error code : kAudioConverterErr_FormatNotSupported");
break;
case kAudioConverterErr_OperationNotSupported:
jack_log("error code : kAudioConverterErr_OperationNotSupported");
break;
case kAudioConverterErr_PropertyNotSupported:
jack_log("error code : kAudioConverterErr_PropertyNotSupported");
break;
case kAudioConverterErr_InvalidInputSize:
jack_log("error code : kAudioConverterErr_InvalidInputSize");
break;
case kAudioConverterErr_InvalidOutputSize:
jack_log("error code : kAudioConverterErr_InvalidOutputSize");
break;
case kAudioConverterErr_UnspecifiedError:
jack_log("error code : kAudioConverterErr_UnspecifiedError");
break;
case kAudioConverterErr_BadPropertySizeError:
jack_log("error code : kAudioConverterErr_BadPropertySizeError");
break;
case kAudioConverterErr_RequiresPacketDescriptionsError:
jack_log("error code : kAudioConverterErr_RequiresPacketDescriptionsError");
break;
case kAudioConverterErr_InputSampleRateOutOfRange:
jack_log("error code : kAudioConverterErr_InputSampleRateOutOfRange");
break;
case kAudioConverterErr_OutputSampleRateOutOfRange:
jack_log("error code : kAudioConverterErr_OutputSampleRateOutOfRange");
break;
case kAudioHardwareNotRunningError:
jack_log("error code : kAudioHardwareNotRunningError");
break;
case kAudioHardwareUnknownPropertyError:
jack_log("error code : kAudioHardwareUnknownPropertyError");
break;
case kAudioHardwareIllegalOperationError:
jack_log("error code : kAudioHardwareIllegalOperationError");
break;
case kAudioHardwareBadDeviceError:
jack_log("error code : kAudioHardwareBadDeviceError");
break;
case kAudioHardwareBadStreamError:
jack_log("error code : kAudioHardwareBadStreamError");
break;
case kAudioDeviceUnsupportedFormatError:
jack_log("error code : kAudioDeviceUnsupportedFormatError");
break;
case kAudioDevicePermissionsError:
jack_log("error code : kAudioDevicePermissionsError");
break;
case kAudioHardwareBadObjectError:
jack_log("error code : kAudioHardwareBadObjectError");
break;
case kAudioHardwareUnsupportedOperationError:
jack_log("error code : kAudioHardwareUnsupportedOperationError");
break;
default:
jack_log("error code : unknown");
break;
}
}

OSStatus JackCoreAudioIOAdapter::SRNotificationCallback(AudioDeviceID inDevice,
UInt32 inChannel,
Boolean isInput,
AudioDevicePropertyID inPropertyID,
void* inClientData)
{
JackCoreAudioIOAdapter* driver = static_cast<JackCoreAudioIOAdapter*>(inClientData);

switch (inPropertyID) {

case kAudioDevicePropertyNominalSampleRate: {
jack_log("JackCoreAudioDriver::SRNotificationCallback kAudioDevicePropertyNominalSampleRate");
driver->fState = true;
break;
}
}

return noErr;
}
OSStatus JackCoreAudioIOAdapter::Render(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData)
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData)
{
JackCoreAudioIOAdapter* adapter = static_cast<JackCoreAudioIOAdapter*>(inRefCon);
jack_log("JackCoreAudioIOAdapter::Render inNumberFrames %ld", inNumberFrames);
JackCoreAudioIOAdapter* driver = static_cast<JackCoreAudioIOAdapter*>(inRefCon);
AudioUnitRender(adapter->fAUHAL, ioActionFlags, inTimeStamp, 1, inNumberFrames, adapter->fInputData);
/*
driver->fActionFags = ioActionFlags;
driver->fCurrentTime = (AudioTimeStamp *)inTimeStamp;
driver->fDriverOutputData = ioData;
driver->CycleTakeBeginTime();
return driver->Process();
adapter->fLastCallbackTime = adapter->fCurCallbackTime;
adapter->fCurCallbackTime = jack_get_time();
adapter->fConsumerFilter.AddValue(adapter->fCurCallbackTime - adapter->fLastCallbackTime);
adapter->fProducerFilter.AddValue(adapter->fDeltaTime);

jack_log("JackCoreAudioIOAdapter::Render delta %ld", adapter->fCurCallbackTime - adapter->fLastCallbackTime);
if (!adapter->fRunning) {
adapter->fRunning = true;
float buffer[inNumberFrames];
for (int i = 0; i < adapter->fCaptureChannels; i++) {
adapter->fCaptureRingBuffer[i].Read(buffer, inNumberFrames);
adapter->fCaptureRingBuffer[i].Read(buffer, inNumberFrames);
adapter->fCaptureRingBuffer[i].Read(buffer, inNumberFrames);
}
for (int i = 0; i < adapter->fPlaybackChannels; i++) {
adapter->fPlaybackRingBuffer[i].Write(buffer, inNumberFrames);
adapter->fPlaybackRingBuffer[i].Write(buffer, inNumberFrames);
adapter->fPlaybackRingBuffer[i].Write(buffer, inNumberFrames);
}
}
jack_time_t val2 = adapter->fConsumerFilter.GetVal();
jack_time_t val1 = adapter->fProducerFilter.GetVal();
double src_ratio_output = double(val1) / double(val2);
double src_ratio_input = double(val2) / double(val1);
if (src_ratio_input < 0.8f || src_ratio_input > 1.2f)
jack_error("src_ratio_input = %f", src_ratio_input);
AudioUnitRender(fAUHAL, fActionFags, fCurrentTime, 1, fEngineControl->fBufferSize, fJackInputData);
*/
if (src_ratio_output < 0.8f || src_ratio_output > 1.2f)
jack_error("src_ratio_output = %f", src_ratio_output);
src_ratio_input = Range(0.8f, 1.2f, src_ratio_input);
src_ratio_output = Range(0.8f, 1.2f, src_ratio_output);
jack_log("Callback resampler src_ratio_input = %f src_ratio_output = %f", src_ratio_input, src_ratio_output);
for (int i = 0; i < adapter->fCaptureChannels; i++) {
adapter->fCaptureRingBuffer[i].SetRatio(src_ratio_input);
//adapter->fCaptureRingBuffer[i].WriteResample((float*)adapter->fInputData->mBuffers[i].mData, inNumberFrames);
adapter->fCaptureRingBuffer[i].Write((float*)adapter->fInputData->mBuffers[i].mData, inNumberFrames);
}
///AudioUnitRender(fAUHAL, ioActionFlags, inTimeStamp, 1, inNumberFrames, fJackInputData);
for (int i = 0; i < adapter->fPlaybackChannels; i++) {
adapter->fPlaybackRingBuffer[i].SetRatio(src_ratio_output);
//adapter->fPlaybackRingBuffer[i].ReadResample((float*)ioData->mBuffers[i].mData, inNumberFrames);
adapter->fPlaybackRingBuffer[i].Read((float*)ioData->mBuffers[i].mData, inNumberFrames);
}
return noErr;
}

OSStatus JackCoreAudioIOAdapter::GetDeviceIDFromUID(const char* UID, AudioDeviceID* id)
OSStatus JackCoreAudioIOAdapter::GetDefaultDevice(AudioDeviceID* id)
{
/*
UInt32 size = sizeof(AudioValueTranslation);
CFStringRef inIUD = CFStringCreateWithCString(NULL, UID, CFStringGetSystemEncoding());
AudioValueTranslation value = { &inIUD, sizeof(CFStringRef), id, sizeof(AudioDeviceID) };
OSStatus res;
UInt32 theSize = sizeof(UInt32);
AudioDeviceID inDefault;
AudioDeviceID outDefault;

if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &theSize, &inDefault)) != noErr)
return res;

if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &theSize, &outDefault)) != noErr)
return res;

if (inIUD == NULL) {
return kAudioHardwareUnspecifiedError;
jack_log("GetDefaultDevice: input = %ld output = %ld", inDefault, outDefault);

// Get the device only if default input and ouput are the same
if (inDefault == outDefault) {
*id = inDefault;
return noErr;
} else {
OSStatus res = AudioHardwareGetProperty(kAudioHardwarePropertyDeviceForUID, &size, &value);
CFRelease(inIUD);
jack_log("get_device_id_from_uid %s %ld ", UID, *id);
return (*id == kAudioDeviceUnknown) ? kAudioHardwareBadDeviceError : res;
jack_error("Default input and output devices are not the same !!");
return kAudioHardwareBadDeviceError;
}
*/
return noErr;
}

OSStatus JackCoreAudioIOAdapter::GetDefaultDevice(AudioDeviceID* id)
OSStatus JackCoreAudioIOAdapter::GetTotalChannels(AudioDeviceID device, int* channelCount, bool isInput)
{
return noErr;
OSStatus err = noErr;
UInt32 outSize;
Boolean outWritable;
AudioBufferList* bufferList = 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;
}

if (bufferList)
free(bufferList);
}

return err;
}
OSStatus JackCoreAudioIOAdapter::GetDefaultInputDevice(AudioDeviceID* id)

// Setup
int JackCoreAudioIOAdapter::SetupDevices(const char* capture_driver_uid,
const char* playback_driver_uid,
char* capture_driver_name,
char* playback_driver_name)
{
return noErr;
if (GetDefaultDevice(&fDeviceID) != noErr) {
jack_error("Cannot open default device");
return -1;
}
return 0;
}
OSStatus JackCoreAudioIOAdapter::GetDefaultOutputDevice(AudioDeviceID* id)

int JackCoreAudioIOAdapter::SetupChannels(bool capturing,
bool playing,
int& inchannels,
int& outchannels,
int& in_nChannels,
int& out_nChannels,
bool strict)
{
return noErr;
OSStatus err = noErr;
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;
}
return 0;
}
OSStatus JackCoreAudioIOAdapter::GetDeviceNameFromID(AudioDeviceID id, char* name)

int JackCoreAudioIOAdapter::SetupBufferSizeAndSampleRate(jack_nframes_t nframes, jack_nframes_t samplerate)
{
return noErr;
OSStatus err = noErr;
UInt32 outSize;
Float64 sampleRate;

// Setting buffer size
outSize = sizeof(UInt32);
err = AudioDeviceSetProperty(fDeviceID, NULL, 0, false, kAudioDevicePropertyBufferFrameSize, outSize, &nframes);
if (err != noErr) {
jack_error("Cannot set buffer size %ld", nframes);
printError(err);
return -1;
}

// Get sample rate
outSize = sizeof(Float64);
err = AudioDeviceGetProperty(fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate);
if (err != noErr) {
jack_error("Cannot get current sample rate");
printError(err);
return -1;
}

// If needed, set new sample rate
if (samplerate != (jack_nframes_t)sampleRate) {
sampleRate = (Float64)samplerate;

// To get SR change notification
err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback, this);
if (err != noErr) {
jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate");
printError(err);
return -1;
}
err = AudioDeviceSetProperty(fDeviceID, NULL, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, outSize, &sampleRate);
if (err != noErr) {
jack_error("Cannot set sample rate = %ld", samplerate);
printError(err);
return -1;
}

// Waiting for SR change notification
int count = 0;
while (!fState && count++ < 100) {
usleep(100000);
jack_log("Wait count = %ld", count);
}

// Remove SR change notification
AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback);
}

return 0;
}
OSStatus JackCoreAudioIOAdapter::GetTotalChannels(AudioDeviceID device, int* channelCount, bool isInput)

int JackCoreAudioIOAdapter::SetupBuffers(int inchannels, int outchannels)
{
return noErr;
jack_log("JackCoreAudioIOAdapter::SetupBuffers: input = %ld output = %ld", inchannels, outchannels);
// Prepare buffers
fInputData = (AudioBufferList*)malloc(sizeof(UInt32) + inchannels * sizeof(AudioBuffer));
if (fInputData == 0) {
jack_error("Cannot allocate memory for input buffers");
return -1;
}
fInputData->mNumberBuffers = inchannels;
for (int i = 0; i < fCaptureChannels; i++) {
fInputData->mBuffers[i].mNumberChannels = 1;
fInputData->mBuffers[i].mDataByteSize = fBufferSize * sizeof(float);
fInputData->mBuffers[i].mData = malloc(fBufferSize * sizeof(float));
}
return 0;
}

// Setup
int JackCoreAudioIOAdapter::SetupDevices(const char* capture_driver_uid,
const char* playback_driver_uid,
char* capture_driver_name,
char* playback_driver_name)
void JackCoreAudioIOAdapter::DisposeBuffers()
{
return 0;
if (fInputData) {
for (int i = 0; i < fCaptureChannels; i++)
free(fInputData->mBuffers[i].mData);
free(fInputData);
fInputData = 0;
}
}

int JackCoreAudioIOAdapter::SetupChannels(bool capturing,
bool playing,
int& inchannels,
int& outchannels,
int& in_nChannels,
int& out_nChannels,
bool strict)
int JackCoreAudioIOAdapter::OpenAUHAL(bool capturing,
bool playing,
int inchannels,
int outchannels,
int in_nChannels,
int out_nChannels,
jack_nframes_t nframes,
jack_nframes_t samplerate,
bool strict)
{
ComponentResult err1;
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);

// AUHAL
ComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_HALOutput, kAudioUnitManufacturer_Apple, 0, 0};
Component HALOutput = FindNextComponent(NULL, &cd);

err1 = OpenAComponent(HALOutput, &fAUHAL);
if (err1 != noErr) {
jack_error("Error calling OpenAComponent");
printError(err1);
return -1;
}

err1 = AudioUnitInitialize(fAUHAL);
if (err1 != noErr) {
jack_error("Cannot initialize AUHAL unit");
printError(err1);
return -1;
}

// Start I/O
enableIO = 1;
if (capturing && inchannels > 0) {
jack_log("Setup AUHAL input");
err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO));
if (err1 != noErr) {
jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input");
printError(err1);
if (strict)
return -1;
}
}

if (playing && outchannels > 0) {
jack_log("Setup AUHAL output");
err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO));
if (err1 != noErr) {
jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO,kAudioUnitScope_Output");
printError(err1);
if (strict)
return -1;
}
}

// Setup up choosen device, in both input and output cases
err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &fDeviceID, sizeof(AudioDeviceID));
if (err1 != noErr) {
jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_CurrentDevice");
printError(err1);
if (strict)
return -1;
}

// Set buffer size
if (capturing && inchannels > 0) {
err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 1, (UInt32*) & nframes, sizeof(UInt32));
if (err1 != noErr) {
jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice");
printError(err1);
if (strict)
return -1;
}
}

if (playing && outchannels > 0) {
err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, (UInt32*) & nframes, sizeof(UInt32));
if (err1 != noErr) {
jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice");
printError(err1);
if (strict)
return -1;
}
}

// Setup channel map
if (capturing && inchannels > 0 && inchannels < in_nChannels) {
SInt32 chanArr[in_nChannels];
for (int i = 0; i < in_nChannels; i++) {
chanArr[i] = -1;
}
for (int i = 0; i < inchannels; i++) {
chanArr[i] = i;
}
AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_ChannelMap , kAudioUnitScope_Input, 1, chanArr, sizeof(SInt32) * in_nChannels);
if (err1 != noErr) {
jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap 1");
printError(err1);
}
}

if (playing && outchannels > 0 && outchannels < out_nChannels) {
SInt32 chanArr[out_nChannels];
for (int i = 0; i < out_nChannels; i++) {
chanArr[i] = -1;
}
for (int i = 0; i < outchannels; i++) {
chanArr[i] = i;
}
err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_ChannelMap, kAudioUnitScope_Output, 0, chanArr, sizeof(SInt32) * out_nChannels);
if (err1 != noErr) {
jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap 0");
printError(err1);
}
}

// Setup stream converters
jack_log("Setup AUHAL input stream converter SR = %ld", samplerate);
srcFormat.mSampleRate = samplerate;
srcFormat.mFormatID = kAudioFormatLinearPCM;
srcFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved;
srcFormat.mBytesPerPacket = sizeof(float);
srcFormat.mFramesPerPacket = 1;
srcFormat.mBytesPerFrame = sizeof(float);
srcFormat.mChannelsPerFrame = outchannels;
srcFormat.mBitsPerChannel = 32;

err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &srcFormat, sizeof(AudioStreamBasicDescription));
if (err1 != noErr) {
jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input");
printError(err1);
}

jack_log("Setup AUHAL output stream converter SR = %ld", samplerate);
dstFormat.mSampleRate = samplerate;
dstFormat.mFormatID = kAudioFormatLinearPCM;
dstFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved;
dstFormat.mBytesPerPacket = sizeof(float);
dstFormat.mFramesPerPacket = 1;
dstFormat.mBytesPerFrame = sizeof(float);
dstFormat.mChannelsPerFrame = inchannels;
dstFormat.mBitsPerChannel = 32;

err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &dstFormat, sizeof(AudioStreamBasicDescription));
if (err1 != noErr) {
jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output");
printError(err1);
}

// Setup callbacks
if (inchannels > 0 && outchannels == 0) {
AURenderCallbackStruct output;
output.inputProc = Render;
output.inputProcRefCon = this;
err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &output, sizeof(output));
if (err1 != noErr) {
jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 1");
printError(err1);
return -1;
}
} else {
AURenderCallbackStruct output;
output.inputProc = Render;
output.inputProcRefCon = this;
err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &output, sizeof(output));
if (err1 != noErr) {
jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 0");
printError(err1);
return -1;
}
}

return 0;
}


int JackCoreAudioIOAdapter::SetupBufferSizeAndSampleRate(jack_nframes_t nframes, jack_nframes_t samplerate)
void JackCoreAudioIOAdapter::CloseAUHAL()
{
return 0;
AudioUnitUninitialize(fAUHAL);
CloseComponent(fAUHAL);
}
int JackCoreAudioIOAdapter::Open()
{
OSStatus err;
int in_nChannels = 0;
int out_nChannels = 0;
if (SetupDevices("", "", "", "") < 0)
return -1;

if (SetupChannels(true, true, fCaptureChannels, fPlaybackChannels, in_nChannels, out_nChannels, true) < 0)
return -1;

if (SetupBufferSizeAndSampleRate(fBufferSize, fSampleRate) < 0)
return -1;

if (OpenAUHAL(true, true, fCaptureChannels, fPlaybackChannels, in_nChannels, out_nChannels, fBufferSize, fSampleRate, true) < 0)
goto error;

if (SetupBuffers(fCaptureChannels, fPlaybackChannels) < 0)
goto error;
err = AudioOutputUnitStart(fAUHAL);
if (err != noErr)
goto error;
return noErr;

error:
Close();
return -1;
}

int JackCoreAudioIOAdapter::Close()
{

AudioOutputUnitStop(fAUHAL);
DisposeBuffers();
CloseAUHAL();
return 0;
}



+ 36
- 17
macosx/JackCoreAudioIOAdapter.h View File

@@ -21,6 +21,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#define __JackCoreAudioIOAdapter__

#include "JackIOAdapter.h"
#include "JackFilters.h"
#include "jack.h"
#include <AudioToolbox/AudioConverter.h>
#include <CoreAudio/CoreAudio.h>
@@ -29,12 +30,11 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
namespace Jack
{

typedef UInt8 CAAudioHardwareDeviceSectionID;
#define kAudioDeviceSectionInput ((CAAudioHardwareDeviceSectionID)0x01)
#define kAudioDeviceSectionOutput ((CAAudioHardwareDeviceSectionID)0x00)
#define kAudioDeviceSectionGlobal ((CAAudioHardwareDeviceSectionID)0x00)
#define kAudioDeviceSectionWildcard ((CAAudioHardwareDeviceSectionID)0xFF)

typedef UInt8 CAAudioHardwareDeviceSectionID;
#define kAudioDeviceSectionInput ((CAAudioHardwareDeviceSectionID)0x01)
#define kAudioDeviceSectionOutput ((CAAudioHardwareDeviceSectionID)0x00)
#define kAudioDeviceSectionGlobal ((CAAudioHardwareDeviceSectionID)0x00)
#define kAudioDeviceSectionWildcard ((CAAudioHardwareDeviceSectionID)0xFF)

class JackCoreAudioIOAdapter : public JackIOAdapterInterface
{
@@ -42,24 +42,31 @@ typedef UInt8 CAAudioHardwareDeviceSectionID;
private:
AudioUnit fAUHAL;
AudioBufferList* fInputData;
JackFilter fProducerFilter;
JackFilter fConsumerFilter;
AudioDeviceID fDeviceID;
bool fState;

AudioUnitRenderActionFlags* fActionFags;
AudioTimeStamp* fCurrentTime;
static OSStatus Render(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData);
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData);
static OSStatus SRNotificationCallback(AudioDeviceID inDevice,
UInt32 inChannel,
Boolean isInput,
AudioDevicePropertyID inPropertyID,
void* inClientData);

OSStatus GetDeviceIDFromUID(const char* UID, AudioDeviceID* id);
OSStatus GetDefaultDevice(AudioDeviceID* id);
OSStatus GetDefaultInputDevice(AudioDeviceID* id);
OSStatus GetDefaultOutputDevice(AudioDeviceID* id);
OSStatus GetDeviceNameFromID(AudioDeviceID id, char* name);
OSStatus GetTotalChannels(AudioDeviceID device, int* channelCount, bool isInput);

// Setup
@@ -75,14 +82,26 @@ typedef UInt8 CAAudioHardwareDeviceSectionID;
int& in_nChannels,
int& out_nChannels,
bool strict);

int OpenAUHAL(bool capturing,
bool playing,
int inchannels,
int outchannels,
int in_nChannels,
int out_nChannels,
jack_nframes_t nframes,
jack_nframes_t samplerate,
bool strict);

int SetupBufferSizeAndSampleRate(jack_nframes_t nframes, jack_nframes_t samplerate);
int SetupBuffers(int inchannels, int outchannels);
void DisposeBuffers();
void CloseAUHAL();
public:
JackCoreAudioIOAdapter(int input, int output, int buffer_size, float sample_rate)
:JackIOAdapterInterface(input, output, buffer_size, sample_rate)
:JackIOAdapterInterface(input, output, buffer_size, sample_rate),fInputData(0),fState(false)
{}
~JackCoreAudioIOAdapter()
{}


+ 13
- 17
windows/JackPortAudioIOAdapter.cpp View File

@@ -49,24 +49,20 @@ int JackPortAudioIOAdapter::Render(const void* inputBuffer, void* outputBuffer,
if (!adapter->fRunning) {
adapter->fRunning = true;
paBuffer = (float**)inputBuffer;
float buffer[framesPerBuffer];
for (int i = 0; i < adapter->fCaptureChannels; i++) {
buffer = static_cast<float*>(paBuffer[i]);
adapter->fCaptureRingBuffer[i].Read(buffer, framesPerBuffer);
adapter->fCaptureRingBuffer[i].Read(buffer, framesPerBuffer);
adapter->fCaptureRingBuffer[i].Read(buffer, framesPerBuffer);
adapter->fCaptureRingBuffer[i].Read(buffer, inNumberFrames);
adapter->fCaptureRingBuffer[i].Read(buffer, inNumberFrames);
adapter->fCaptureRingBuffer[i].Read(buffer, inNumberFrames);
}
paBuffer = (float**)outputBuffer;
for (int i = 0; i < adapter->fPlaybackChannels; i++) {
buffer = static_cast<float*>(paBuffer[i]);
adapter->fPlaybackRingBuffer[i].Write(buffer, framesPerBuffer);
adapter->fPlaybackRingBuffer[i].Write(buffer, framesPerBuffer);
adapter->fPlaybackRingBuffer[i].Write(buffer, framesPerBuffer);
adapter->fPlaybackRingBuffer[i].Write(buffer, inNumberFrames);
adapter->fPlaybackRingBuffer[i].Write(buffer, inNumberFrames);
adapter->fPlaybackRingBuffer[i].Write(buffer, inNumberFrames);
}
}
}
/*
double src_ratio_output = double(adapter->fCurCallbackTime - adapter->fLastCallbackTime) / double(adapter->fDeltaTime);
double src_ratio_input = double(adapter->fDeltaTime) / double(adapter->fCurCallbackTime - adapter->fLastCallbackTime);
@@ -91,16 +87,16 @@ int JackPortAudioIOAdapter::Render(const void* inputBuffer, void* outputBuffer,
for (int i = 0; i < adapter->fCaptureChannels; i++) {
buffer = (float*)paBuffer[i];
adapter->fCaptureRingBuffer[i].SetRatio(src_ratio_input);
//int len = adapter->fCaptureRingBuffer[i].WriteResample(buffer, framesPerBuffer);
int len = adapter->fCaptureRingBuffer[i].Write(buffer, framesPerBuffer);
//adapter->fCaptureRingBuffer[i].WriteResample(buffer, framesPerBuffer);
adapter->fCaptureRingBuffer[i].Write(buffer, framesPerBuffer);
}
paBuffer = (float**)outputBuffer;
for (int i = 0; i < adapter->fPlaybackChannels; i++) {
buffer = (float*)paBuffer[i];
adapter->fPlaybackRingBuffer[i].SetRatio(src_ratio_output);
//int len = adapter->fPlaybackRingBuffer[i].ReadResample(buffer, framesPerBuffer);
int len = adapter->fPlaybackRingBuffer[i].Read(buffer, framesPerBuffer);
//adapter->fPlaybackRingBuffer[i].ReadResample(buffer, framesPerBuffer);
adapter->fPlaybackRingBuffer[i].Read(buffer, framesPerBuffer);
}
return paContinue;


+ 4
- 31
windows/JackPortAudioIOAdapter.h View File

@@ -21,40 +21,13 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#define __JackPortAudioIOAdapter__

#include "JackIOAdapter.h"
#include "JackFilters.h"
#include "portaudio.h"

namespace Jack
{

#define MAX_SIZE 64
struct Filter {
jack_time_t fTable[MAX_SIZE];
Filter()
{
for (int i = 0; i < MAX_SIZE; i++)
fTable[i] = 0;
}
void AddValue(jack_time_t val)
{
memcpy(&fTable[1], &fTable[0], sizeof(jack_time_t) * (MAX_SIZE - 1));
fTable[0] = val;
}
jack_time_t GetVal()
{
jack_time_t mean = 0;
for (int i = 0; i < MAX_SIZE; i++)
mean += fTable[i];
return mean / MAX_SIZE;
}
};

class JackPortAudioIOAdapter : public JackIOAdapterInterface
class JackPortAudioIOAdapter : public JackIOAdapterInterface
{
private:
@@ -63,8 +36,8 @@ namespace Jack
PaDeviceIndex fInputDevice;
PaDeviceIndex fOutputDevice;
Filter fProducerFilter;
Filter fConsumerFilter;
JackFilter fProducerFilter;
JackFilter fConsumerFilter;
static int Render(const void* inputBuffer, void* outputBuffer,
unsigned long framesPerBuffer,


Loading…
Cancel
Save