Browse Source

Merge branch 'ac3'

tags/1.9.9.5
Stephane Letz 13 years ago
parent
commit
ade10a8de5
7 changed files with 722 additions and 80 deletions
  1. +313
    -0
      common/JackAC3Encoder.cpp
  2. +90
    -0
      common/JackAC3Encoder.h
  3. +15
    -1
      macosx/Jackdmp.xcodeproj/project.pbxproj
  4. +291
    -76
      macosx/coreaudio/JackCoreAudioDriver.cpp
  5. +13
    -3
      macosx/coreaudio/JackCoreAudioDriver.h
  6. BIN
      macosx/libaften_pcm.a
  7. BIN
      macosx/libaften_static.a

+ 313
- 0
common/JackAC3Encoder.cpp View File

@@ -0,0 +1,313 @@
/*
Copyright (C) 2006 Jesse Chappell <jesse@essej.net> (AC3Jack)
Copyright (C) 2012 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 "JackAC3Encoder.h"
#include "JackError.h"
#include <unistd.h>
#include <string.h>
#include <stdio.h>

#define max(x,y) (((x)>(y)) ? (x) : (y))
#define min(x,y) (((x)<(y)) ? (x) : (y))

namespace Jack
{

JackAC3Encoder::JackAC3Encoder(const JackAC3EncoderParams& params)
{
aften_set_defaults(&fAftenContext);
fAftenContext.channels = params.channels;
fAftenContext.samplerate = params.sample_rate;
fAftenContext.params.bitrate = params.bitrate;

int acmod = A52_ACMOD_MONO;
int lfe = params.lfe;
switch (params.channels) {
case 1: acmod = A52_ACMOD_MONO; break;
case 2: acmod = A52_ACMOD_STEREO; break;
case 3: acmod = A52_ACMOD_3_0; break;
case 4: acmod = A52_ACMOD_2_2; break;
case 5: acmod = A52_ACMOD_3_2; break;
break;
default:
break;
}

if (lfe) {
fAftenContext.channels += 1;
}
fAftenContext.acmod = acmod;
fAftenContext.lfe = lfe;
fAftenContext.sample_format = A52_SAMPLE_FMT_FLT;
fAftenContext.verbose = 1;

fAftenContext.system.n_threads = 1;
// create interleaved framebuffer for MAX_AC3_CHANNELS
fSampleBuffer = new float[MAX_AC3_CHANNELS * A52_SAMPLES_PER_FRAME];
// create AC3 buffer
fAC3Buffer = new unsigned char[A52_MAX_CODED_FRAME_SIZE];
memset(fAC3Buffer, 0, A52_MAX_CODED_FRAME_SIZE);
fZeroBuffer = new unsigned char[SPDIF_FRAME_SIZE];
memset(fZeroBuffer, 0, SPDIF_FRAME_SIZE);
fRingBuffer = jack_ringbuffer_create(32768);
fOutSizeByte = 0;
fFramePos = 0;
fSampleRate = 0;
fByteRate = 0;
}

bool JackAC3Encoder::Init(jack_nframes_t sample_rate)
{
fSampleRate = sample_rate;
fByteRate = fSampleRate * sizeof(short) * 2;
return (aften_encode_init(&fAftenContext) == 0);
}
JackAC3Encoder::~JackAC3Encoder()
{
aften_encode_close(&fAftenContext);
delete [] fSampleBuffer;
delete [] fAC3Buffer;
delete [] fZeroBuffer;
if (fRingBuffer) {
jack_ringbuffer_free(fRingBuffer);
}
}

void JackAC3Encoder::Process(float** inputs_buffer, float** outputs_buffer, int nframes)
{
// fill and process frame buffers as appropriate
jack_nframes_t frames_left = A52_SAMPLES_PER_FRAME - fFramePos;
jack_nframes_t offset = 0;

while (offset < nframes)
{
if ((nframes - offset) >= frames_left) {
// copy only frames_left more data
jack_nframes_t pos = fFramePos * fAftenContext.channels;
for (jack_nframes_t spos = offset; spos < offset + frames_left; ++spos) {
for (size_t i = 0; i < fAftenContext.channels; ++i) {
fSampleBuffer[pos + i] = inputs_buffer[i][spos];
}
pos += fAftenContext.channels;
}
// use interleaved version
int res = aften_encode_frame(&fAftenContext, fAC3Buffer + SPDIF_HEADER_SIZE, fSampleBuffer);
if (res < 0) {
jack_error("aften_encode_frame error !!");
return;
}
fOutSizeByte = res;
FillSpdifHeader(fAC3Buffer, fOutSizeByte + SPDIF_HEADER_SIZE);
// push AC3 output to SPDIF ring buffer
float calc_ac3byterate = (fOutSizeByte * fSampleRate / (float) A52_SAMPLES_PER_FRAME);
jack_nframes_t silencebytes = (jack_nframes_t) (fOutSizeByte * (fByteRate / calc_ac3byterate)) - fOutSizeByte - SPDIF_HEADER_SIZE;
jack_ringbuffer_write(fRingBuffer, (const char *)fAC3Buffer, fOutSizeByte + SPDIF_HEADER_SIZE);

// write the proper remainder of zero padding (inefficient, should be memsetting)
jack_ringbuffer_write(fRingBuffer, (const char *)fZeroBuffer, silencebytes);
offset += frames_left;
frames_left = A52_SAMPLES_PER_FRAME;
fFramePos = 0;
} else {
// copy incoming data into frame buffers without processing
jack_nframes_t pos = fFramePos * fAftenContext.channels;
for (jack_nframes_t spos = offset; spos < nframes; ++spos) {
for (size_t i = 0; i < fAftenContext.channels; ++i) {
fSampleBuffer[pos + i] = inputs_buffer[i][spos];
}
pos += fAftenContext.channels;
}

fFramePos += (nframes - offset);
offset += (nframes-offset);
}
}

Output2Driver(outputs_buffer, nframes);
}

void JackAC3Encoder::FillSpdifHeader(unsigned char* buf, int outsize)
{
// todo, use outsize and not assume the fixed frame size?
int ac3outsize = outsize - SPDIF_HEADER_SIZE;
buf[0] = 0x72; buf[1] = 0xf8; /* spdif syncword */
buf[2] = 0x1f; buf[3] = 0x4e; /* .............. */
buf[4] = 0x01; /* AC3 data */
buf[5] = buf[13] & 7; /* bsmod, stream = 0 */
buf[6] = (ac3outsize << 3) & 0xff;
buf[7] = (ac3outsize >> 5) & 0xff;

#if !IS_BIGENDIAN
swab(buf+SPDIF_HEADER_SIZE, buf + SPDIF_HEADER_SIZE, ac3outsize);
#endif
}

int JackAC3Encoder::Output2Driver(float** outputs, jack_nframes_t nframes)
{
int wrotebytes = 0;
jack_nframes_t nframes_left = nframes;
if (jack_ringbuffer_read_space(fRingBuffer) == 0) {
// just write silence
memset(outputs[0], 0, nframes * sizeof(jack_default_audio_sample_t));
memset(outputs[1], 0, nframes * sizeof(jack_default_audio_sample_t));
} else {
jack_ringbuffer_data_t rb_data[2];

jack_ringbuffer_get_read_vector(fRingBuffer, rb_data);
while (nframes_left > 0 && rb_data[0].len > 4) {
jack_nframes_t towrite_frames = (rb_data[0].len) / (sizeof(short) * 2);
towrite_frames = min(towrite_frames, nframes_left);
// write and deinterleave into the two channels
#if 1
sample_move_dS_s16(outputs[0] + (nframes - nframes_left), (char *) rb_data[0].buf, towrite_frames, sizeof(short) * 2);
sample_move_dS_s16(outputs[1] + (nframes - nframes_left), (char *) rb_data[0].buf + sizeof(short), towrite_frames, sizeof(short) * 2);
#else
sample_move_dS_s16_24ph(outputs[0] + (nframes - nframes_left), (char *) rb_data[0].buf, towrite_frames, sizeof(short) * 2);
sample_move_dS_s16_24ph(outputs[1] + (nframes - nframes_left), (char *) rb_data[0].buf + sizeof(short), towrite_frames, sizeof(short) * 2);
#endif
wrotebytes = towrite_frames * sizeof(short) * 2;
nframes_left -= towrite_frames;
jack_ringbuffer_read_advance(fRingBuffer, wrotebytes);
jack_ringbuffer_get_read_vector(fRingBuffer, rb_data);
}

if (nframes_left > 0) {
// write silence
memset(outputs[0] + (nframes - nframes_left), 0, (nframes_left) * sizeof(jack_default_audio_sample_t));
memset(outputs[1] + (nframes - nframes_left), 0, (nframes_left) * sizeof(jack_default_audio_sample_t));
}
}

return wrotebytes;
}

void JackAC3Encoder::sample_move_dS_s16(jack_default_audio_sample_t* dst, char *src, jack_nframes_t nsamples, unsigned long src_skip)
{
/* ALERT: signed sign-extension portability !!! */
while (nsamples--) {
*dst = (*((short *) src)) / SAMPLE_MAX_16BIT;
dst++;
src += src_skip;
}
}

void JackAC3Encoder::sample_move_dS_s16_24ph(jack_default_audio_sample_t* dst, char *src, jack_nframes_t nsamples, unsigned long src_skip)
{
/* ALERT: signed sign-extension portability !!! */
while (nsamples--) {
*dst = (((int)(*((short *) src))) << 8) / SAMPLE_MAX_24BIT;
dst++;
src += src_skip;
}
}

void JackAC3Encoder::GetChannelName(const char* name, const char* alias, char* portname, int channel)
{
/*
* 2 channels = L, R
* 3 channels = L, C, R
* 4 channels = L, R, LS, RS
* 5 ch = L, C, R, LS, RS
* 6 ch = L, C, R, LS, RS, LFE
*/
const char* AC3_name = "";
switch (channel) {
case 0:
AC3_name = "AC3_1_Left";
break;
case 1:
if (fAftenContext.channels == 2 || fAftenContext.channels == 4) {
AC3_name = "AC3_2_Right";
} else {
AC3_name = "AC3_2_Center";
}
break;
case 2:
if (fAftenContext.channels == 4) {
AC3_name = "AC3_3_LeftSurround";
} else {
AC3_name = "AC3_3_Right";
}
break;
case 3:
if (fAftenContext.channels == 4) {
AC3_name = "AC3_4_RightSurround";
} else {
AC3_name = "AC3_4_LeftSurround";
}
break;
case 4:
if (fAftenContext.channels > 4) {
AC3_name = "AC3_5_RightSurround";
}
break;
default:
break;
}
// Last channel
if (fAftenContext.lfe && (channel == fAftenContext.channels - 1)) {
sprintf(portname, "%s:%s:AC3_%d_LFE", name, alias, fAftenContext.channels);
} else {
sprintf(portname, "%s:%s:%s", name, alias, AC3_name);
}
}

} // end of namespace

+ 90
- 0
common/JackAC3Encoder.h View File

@@ -0,0 +1,90 @@
/*
Copyright (C) 2006 Jesse Chappell <jesse@essej.net> (AC3Jack)
Copyright (C) 2012 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 __JackAC3Encoder__
#define __JackAC3Encoder__

#include <aften/aften.h>
#include <aften/aften-types.h>

#include "ringbuffer.h"
#include "types.h"

#define MAX_AC3_CHANNELS 6

#define SPDIF_HEADER_SIZE 8
#define SPDIF_FRAME_SIZE 6144

#define SAMPLE_MAX_16BIT 32768.0f
#define SAMPLE_MAX_24BIT 8388608.0f

namespace Jack
{

struct JackAC3EncoderParams
{
int64_t duration;
unsigned int channels;
int bitdepth;
int bitrate;
unsigned int sample_rate;
bool lfe;
};

class JackAC3Encoder
{

private:

AftenContext fAftenContext;
jack_ringbuffer_t* fRingBuffer;
float* fSampleBuffer;
unsigned char* fAC3Buffer;
unsigned char* fZeroBuffer;
int fOutSizeByte;
jack_nframes_t fFramePos;
jack_nframes_t fSampleRate;
jack_nframes_t fByteRate;
void FillSpdifHeader(unsigned char* buf, int outsize);
int Output2Driver(float** outputs, jack_nframes_t nframes);
void sample_move_dS_s16(jack_default_audio_sample_t* dst, char *src, jack_nframes_t nsamples, unsigned long src_skip);
void sample_move_dS_s16_24ph(jack_default_audio_sample_t* dst, char *src, jack_nframes_t nsamples, unsigned long src_skip);

public:

JackAC3Encoder(const JackAC3EncoderParams& params);
virtual ~JackAC3Encoder();
bool Init(jack_nframes_t sample_rate);
void Process(float** inputs, float** outputs, int nframes);
void GetChannelName(const char* name, const char* alias, char* portname, int channel);
};

typedef JackAC3Encoder * JackAC3EncoderPtr;

} // end of namespace

#endif

+ 15
- 1
macosx/Jackdmp.xcodeproj/project.pbxproj View File

@@ -878,6 +878,10 @@
4BA7BE240DC2350D00AA3457 /* Jackservermp.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B35C4FC0D4731D1000DE7AE /* Jackservermp.framework */; };
4BA7BE270DC2352A00AA3457 /* Jackservermp.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B35C4FC0D4731D1000DE7AE /* Jackservermp.framework */; };
4BA7FECA0D8E76650017FF73 /* control.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BA7FEC80D8E76650017FF73 /* control.c */; };
4BAA150314F04FB600402512 /* JackAC3Encoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BAA150114F04FB600402512 /* JackAC3Encoder.cpp */; };
4BAA150414F04FB600402512 /* JackAC3Encoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BAA150214F04FB600402512 /* JackAC3Encoder.h */; };
4BAA150514F04FB600402512 /* JackAC3Encoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BAA150114F04FB600402512 /* JackAC3Encoder.cpp */; };
4BAA150614F04FB600402512 /* JackAC3Encoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BAA150214F04FB600402512 /* JackAC3Encoder.h */; };
4BAB95B80B9E20B800A0C723 /* JackPortType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BAB95B60B9E20B800A0C723 /* JackPortType.cpp */; };
4BAB95B90B9E20B800A0C723 /* JackPortType.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BAB95B70B9E20B800A0C723 /* JackPortType.h */; };
4BAB95BA0B9E20B800A0C723 /* JackPortType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BAB95B60B9E20B800A0C723 /* JackPortType.cpp */; };
@@ -1887,6 +1891,8 @@
4BA692D60CBE4CC600EAD520 /* ipunload.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = ipunload.c; path = "../example-clients/ipunload.c"; sourceTree = SOURCE_ROOT; };
4BA7FEC30D8E76270017FF73 /* jack_server_control */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = jack_server_control; sourceTree = BUILT_PRODUCTS_DIR; };
4BA7FEC80D8E76650017FF73 /* control.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = control.c; path = "../example-clients/control.c"; sourceTree = SOURCE_ROOT; };
4BAA150114F04FB600402512 /* JackAC3Encoder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JackAC3Encoder.cpp; path = ../common/JackAC3Encoder.cpp; sourceTree = SOURCE_ROOT; };
4BAA150214F04FB600402512 /* JackAC3Encoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JackAC3Encoder.h; path = ../common/JackAC3Encoder.h; sourceTree = SOURCE_ROOT; };
4BAB95B60B9E20B800A0C723 /* JackPortType.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = JackPortType.cpp; path = ../common/JackPortType.cpp; sourceTree = SOURCE_ROOT; };
4BAB95B70B9E20B800A0C723 /* JackPortType.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = JackPortType.h; path = ../common/JackPortType.h; sourceTree = SOURCE_ROOT; };
4BAB95EC0B9E21A500A0C723 /* JackAudioPort.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = JackAudioPort.cpp; path = ../common/JackAudioPort.cpp; sourceTree = SOURCE_ROOT; };
@@ -3238,8 +3244,8 @@
4B21794D13E2EEA60095B3E5 /* JackTimedDriver.cpp */,
4BF3390D0F8B86AF0080FB5B /* MIDI */,
4B19B3010E23629800DD4A82 /* Adapter */,
BA222AEA0DC88379001A17F4 /* Net */,
4BD56D8707968982006D44F9 /* Threaded */,
BA222AEA0DC88379001A17F4 /* Net */,
4BD56D8607968979006D44F9 /* Audio */,
);
name = Driver;
@@ -3353,6 +3359,8 @@
4BD56D8607968979006D44F9 /* Audio */ = {
isa = PBXGroup;
children = (
4BAA150114F04FB600402512 /* JackAC3Encoder.cpp */,
4BAA150214F04FB600402512 /* JackAC3Encoder.h */,
4BBB00CF0E72614F0018AB1B /* JackPortAudioDevices.cpp */,
4BBB00D00E72614F0018AB1B /* JackPortAudioDevices.h */,
4BBB00D10E72614F0018AB1B /* JackPortAudioDriver.cpp */,
@@ -3843,6 +3851,7 @@
buildActionMask = 2147483647;
files = (
4BA4ADB50E87AB2600F26C85 /* JackCoreAudioDriver.h in Headers */,
4BAA150614F04FB600402512 /* JackAC3Encoder.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -4277,6 +4286,7 @@
buildActionMask = 2147483647;
files = (
4BE5FECE0E725C090020B576 /* JackCoreAudioDriver.h in Headers */,
4BAA150414F04FB600402512 /* JackAC3Encoder.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -7381,6 +7391,7 @@
buildActionMask = 2147483647;
files = (
4BA4ADB40E87AB2500F26C85 /* JackCoreAudioDriver.cpp in Sources */,
4BAA150514F04FB600402512 /* JackAC3Encoder.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -7791,6 +7802,7 @@
buildActionMask = 2147483647;
files = (
4BE5FECD0E725C090020B576 /* JackCoreAudioDriver.cpp in Sources */,
4BAA150314F04FB600402512 /* JackAC3Encoder.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -11851,6 +11863,8 @@
"-DJACK_32_64",
);
OTHER_LDFLAGS = (
libaften_pcm.a,
libaften_static.a,
"-framework",
Jackservermp,
"-framework",


+ 291
- 76
macosx/coreaudio/JackCoreAudioDriver.cpp View File

@@ -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(&params, 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;


+ 13
- 3
macosx/coreaudio/JackCoreAudioDriver.h View File

@@ -50,10 +50,14 @@ typedef UInt8 CAAudioHardwareDeviceSectionID;
\todo hardware monitoring
*/

class JackAC3Encoder;

class JackCoreAudioDriver : public JackAudioDriver
{

private:
JackAC3Encoder* fAC3Encoder;

AudioUnit fAUHAL;

@@ -75,8 +79,8 @@ class JackCoreAudioDriver : public JackAudioDriver
float fIOUsage;
float fComputationGrain;
bool fClockDriftCompensate;
bool fDigitalPlayback;
static OSStatus Render(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
@@ -122,7 +126,8 @@ class JackCoreAudioDriver : public JackAudioDriver
const char* playback_driver_uid,
char* capture_driver_name,
char* playback_driver_name,
jack_nframes_t samplerate);
jack_nframes_t samplerate,
bool ac3_encoding);

int SetupChannels(bool capturing,
bool playing,
@@ -158,6 +163,8 @@ class JackCoreAudioDriver : public JackAudioDriver
bool TakeHog();

void UpdateLatencies();
bool IsDigitalDevice(AudioDeviceID device);

public:

@@ -180,7 +187,10 @@ class JackCoreAudioDriver : public JackAudioDriver
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 Close();

int Attach();


BIN
macosx/libaften_pcm.a View File


BIN
macosx/libaften_static.a View File


Loading…
Cancel
Save