Browse Source

Big rewrite of Solaris boomer driver, seems to work in duplex mode at least.

git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@3604 0c269be4-1314-0410-8aa9-9f06e86f4224
tags/v1.9.3
sletz 16 years ago
parent
commit
bfecb007bd
3 changed files with 186 additions and 122 deletions
  1. +5
    -1
      ChangeLog
  2. +131
    -105
      solaris/oss/JackBoomerDriver.cpp
  3. +50
    -16
      solaris/oss/JackBoomerDriver.h

+ 5
- 1
ChangeLog View File

@@ -24,10 +24,14 @@ Paul Davis
---------------------------
Jackdmp changes log
---------------------------

2009-07-17 Stephane Letz <letz@grame.fr>
* Big rewrite of Solaris boomer driver, seems to work in duplex mode at least.
2009-07-17 Stephane Letz <letz@grame.fr>
* In combined --dbus and --classic compilation ode, use PulseAudio acquire/release code.
* In combined --dbus and --classic compilation code, use PulseAudio acquire/release code.
2009-07-16 Stephane Letz <letz@grame.fr>


+ 131
- 105
solaris/oss/JackBoomerDriver.cpp View File

@@ -230,6 +230,26 @@ void JackBoomerDriver::DisplayDeviceInfo()
}
}

JackBoomerDriver::JackBoomerDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table)
: JackAudioDriver(name, alias, engine, table),
fInFD(-1), fOutFD(-1), fBits(0),
fSampleFormat(0), fNperiods(0), fRWMode(0), fExcl(false), fIgnoreHW(true),
fInputBufferSize(0), fOutputBufferSize(0),
fInputBuffer(NULL), fOutputBuffer(NULL),
fInputThread(&fInputHandler), fOutputThread(&fOutputHandler),
fInputHandler(this), fOutputHandler(this)
{
sem_init(&fReadSema, 0, 0);
sem_init(&fWriteSema, 0, 0);
}

JackBoomerDriver::~JackBoomerDriver()
{
sem_destroy(&fReadSema);
sem_destroy(&fWriteSema);
}

int JackBoomerDriver::OpenInput()
{
int flags = 0;
@@ -488,15 +508,6 @@ int JackBoomerDriver::OpenAux()
return -1;
}
// Prepare ringbuffers used for output
if (fPlaybackChannels > 0) {
fRingBuffer = new jack_ringbuffer_t*[fPlaybackChannels];
for (int i = 0; i < fPlaybackChannels; i++) {
fRingBuffer[i] = jack_ringbuffer_create(fOutputBufferSize * 2);
jack_ringbuffer_read_advance(fRingBuffer[i], fOutputBufferSize);
}
}

DisplayDeviceInfo();
return 0;
}
@@ -520,27 +531,25 @@ void JackBoomerDriver::CloseAux()
if (fOutputBuffer)
free(fOutputBuffer);
fOutputBuffer = NULL;
for (int i = 0; i < fPlaybackChannels; i++) {
if (fRingBuffer[i])
jack_ringbuffer_free(fRingBuffer[i]);
fRingBuffer[i] = NULL;
}
delete [] fRingBuffer;
fRingBuffer = NULL;
}


int JackBoomerDriver::Start()
{
jack_log("JackBoomerDriver::Start");
JackAudioDriver::Start();

// Start input thread only when needed
if (fInFD > 0) {
if (fInputThread.StartSync() < 0) {
jack_error("Cannot start input thread");
return -1;
}
}

// Start output thread only when needed
if (fOutFD > 0) {
if (fThread.StartSync() < 0) {
jack_error("Cannot start thread");
if (fOutputThread.StartSync() < 0) {
jack_error("Cannot start output thread");
return -1;
}
}
@@ -550,20 +559,59 @@ int JackBoomerDriver::Start()

int JackBoomerDriver::Stop()
{
// Stop input thread only when needed
if (fInFD > 0) {
fInputThread.Kill();
}

// Stop output thread only when needed
if (fOutFD > 0) {
return fThread.Kill();
} else {
return 0;
fOutputThread.Kill();
}

return 0;
}

int JackBoomerDriver::Read()
{
if (fInFD < 0) {
/*
// Keep begin cycle time
JackDriver::CycleTakeBeginTime();
*/

return 0;
}

int JackBoomerDriver::Write()
{
/*
// Keep begin cycle time
JackDriver::CycleTakeEndTime();
*/

return 0;
}

bool JackBoomerDriver::JackBoomerDriverInput::Init()
{
if (fDriver->IsRealTime()) {
jack_log("JackBoomerDriverInput::Init IsRealTime");
if (fDriver->fInputThread.AcquireRealTime(GetEngineControl()->fServerPriority) < 0) {
jack_error("AcquireRealTime error");
} else {
set_threaded_log_function();
}
}
return true;
}

bool JackBoomerDriver::JackBoomerDriverInput::Execute()
{
if (fDriver->fInFD < 0) {
// Keep begin cycle time
JackDriver::CycleTakeBeginTime();
return 0;
fDriver->CycleTakeBeginTime();
return true;
}
#ifdef JACK_MONITOR
@@ -571,21 +619,21 @@ int JackBoomerDriver::Read()
#endif

audio_errinfo ei_in;
ssize_t count = ::read(fInFD, fInputBuffer, fInputBufferSize);
ssize_t count = ::read(fDriver->fInFD, fDriver->fInputBuffer, fDriver->fInputBufferSize);
#ifdef JACK_MONITOR
if (count > 0 && count != (int)fInputBufferSize)
jack_log("JackBoomerDriver::Read count = %ld", count / (fSampleSize * fCaptureChannels));
if (count > 0 && count != (int)fDriver->fInputBufferSize)
jack_log("JackBoomerDriverInput::Execute count = %ld", count / (fDriver->fSampleSize * fDriver->fCaptureChannels));
gCycleTable.fTable[gCycleReadCount].fAfterRead = GetMicroSeconds();
#endif
// XRun detection
if (ioctl(fInFD, SNDCTL_DSP_GETERROR, &ei_in) == 0) {
if (ioctl(fDriver->fInFD, SNDCTL_DSP_GETERROR, &ei_in) == 0) {

if (ei_in.rec_overruns > 0 ) {
jack_error("JackBoomerDriver::Read overruns");
jack_error("JackBoomerDriverInput::Execute overruns");
jack_time_t cur_time = GetMicroSeconds();
NotifyXRun(cur_time, float(cur_time - fBeginDateUst)); // Better this value than nothing...
fDriver->NotifyXRun(cur_time, float(cur_time - fDriver->fBeginDateUst)); // Better this value than nothing...
}

if (ei_in.rec_errorcount > 0 && ei_in.rec_lasterror != 0) {
@@ -594,18 +642,16 @@ int JackBoomerDriver::Read()
}
if (count < 0) {
jack_log("JackBoomerDriver::Read error = %s", strerror(errno));
return -1;
} else if (count < (int)fInputBufferSize) {
jack_error("JackBoomerDriver::Read error bytes read = %ld", count);
return -1;
jack_log("JackBoomerDriverInput::Execute error = %s", strerror(errno));
} else if (count < (int)fDriver->fInputBufferSize) {
jack_error("JackBoomerDriverInput::Execute error bytes read = %ld", count);
} else {

// Keep begin cycle time
JackDriver::CycleTakeBeginTime();
for (int i = 0; i < fCaptureChannels; i++) {
if (fGraphManager->GetConnectionsNum(fCapturePortList[i]) > 0) {
CopyAndConvertIn(GetInputBuffer(i), fInputBuffer, fEngineControl->fBufferSize, i, fCaptureChannels, fBits);
fDriver->CycleTakeBeginTime();
for (int i = 0; i < fDriver->fCaptureChannels; i++) {
if (fDriver->fGraphManager->GetConnectionsNum(fDriver->fCapturePortList[i]) > 0) {
CopyAndConvertIn(fDriver->GetInputBuffer(i), fDriver->fInputBuffer, fDriver->fEngineControl->fBufferSize, i, fDriver->fCaptureChannels, fDriver->fBits);
}
}

@@ -613,29 +659,17 @@ int JackBoomerDriver::Read()
gCycleTable.fTable[gCycleReadCount].fAfterReadConvert = GetMicroSeconds();
gCycleReadCount = (gCycleReadCount == CYCLE_POINTS - 1) ? gCycleReadCount: gCycleReadCount + 1;
#endif
return 0;
}
}

int JackBoomerDriver::Write()
{
for (int i = 0; i < fPlaybackChannels; i++) {
if (fGraphManager->GetConnectionsNum(fPlaybackPortList[i]) > 0) {
if (jack_ringbuffer_write(fRingBuffer[i], (char*)GetOutputBuffer(i), fOutputBufferSize) < fOutputBufferSize) {
jack_error("JackBoomerDriver::Write ringbuffer full");
}
}
}

return 0;
fDriver->SynchronizeRead();
return true;
}

bool JackBoomerDriver::Init()
bool JackBoomerDriver::JackBoomerDriverOutput::Init()
{
if (IsRealTime()) {
jack_log("JackBoomerDriver::Init IsRealTime");
if (fThread.AcquireRealTime(GetEngineControl()->fServerPriority) < 0) {
if (fDriver->IsRealTime()) {
jack_log("JackBoomerDriverOutput::Init IsRealTime");
if (fDriver->fOutputThread.AcquireRealTime(GetEngineControl()->fServerPriority) < 0) {
jack_error("AcquireRealTime error");
} else {
set_threaded_log_function();
@@ -643,61 +677,40 @@ bool JackBoomerDriver::Init()
}

// Maybe necessary to write an empty output buffer first time : see http://manuals.opensound.com/developer/fulldup.c.html
memset(fOutputBuffer, 0, fOutputBufferSize);
memset(fDriver->fOutputBuffer, 0, fDriver->fOutputBufferSize);

// Prefill ouput buffer
if (fOutFD > 0) {
for (int i = 0; i < fNperiods; i++) {
ssize_t count = ::write(fOutFD, fOutputBuffer, fOutputBufferSize);
if (count < (int)fOutputBufferSize) {
if (fDriver->fOutFD > 0) {
for (int i = 0; i < fDriver->fNperiods; i++) {
ssize_t count = ::write(fDriver->fOutFD, fDriver->fOutputBuffer, fDriver->fOutputBufferSize);
if (count < (int)fDriver->fOutputBufferSize) {
jack_error("JackBoomerDriver::Write error bytes written = %ld", count);
}
}
int delay;
if (ioctl(fOutFD, SNDCTL_DSP_GETODELAY, &delay) == -1) {
if (ioctl(fDriver->fOutFD, SNDCTL_DSP_GETODELAY, &delay) == -1) {
jack_error("JackBoomerDriver::Write error get out delay : %s@%i, errno = %d", __FILE__, __LINE__, errno);
}
delay /= fSampleSize * fPlaybackChannels;
delay /= fDriver->fSampleSize * fDriver->fPlaybackChannels;
jack_info("JackBoomerDriver::Write output latency frames = %ld", delay);
}
return true;
}

bool JackBoomerDriver::Execute()
bool JackBoomerDriver::JackBoomerDriverOutput::Execute()
{
memset(fOutputBuffer, 0, fOutputBufferSize);
memset(fDriver->fOutputBuffer, 0, fDriver->fOutputBufferSize);

#ifdef JACK_MONITOR
gCycleTable.fTable[gCycleWriteCount].fBeforeWriteConvert = GetMicroSeconds();
#endif
for (int i = 0; i < fPlaybackChannels; i++) {
if (fGraphManager->GetConnectionsNum(fPlaybackPortList[i]) > 0) {

jack_ringbuffer_data_t ring_buffer_data[2];
jack_ringbuffer_get_read_vector(fRingBuffer[i], ring_buffer_data);

unsigned int available_frames = (ring_buffer_data[0].len + ring_buffer_data[1].len) / sizeof(float);
jack_log("Output available = %ld", available_frames);

unsigned int needed_bytes = fOutputBufferSize;
float* output = (float*)fOutputBuffer;

for (int j = 0; j < 2; j++) {
unsigned int consumed_bytes = std::min(needed_bytes, ring_buffer_data[j].len);
CopyAndConvertOut(output, (float*)ring_buffer_data[j].buf, consumed_bytes / sizeof(float), i, fPlaybackChannels, fBits);
output += consumed_bytes / sizeof(float);
needed_bytes -= consumed_bytes;
}

if (needed_bytes > 0) {
jack_error("JackBoomerDriver::Execute missing bytes = %ld", needed_bytes);
}

jack_ringbuffer_read_advance(fRingBuffer[i], fOutputBufferSize - needed_bytes);
for (int i = 0; i < fDriver->fPlaybackChannels; i++) {
if (fDriver->fGraphManager->GetConnectionsNum(fDriver->fPlaybackPortList[i]) > 0) {
CopyAndConvertOut(fDriver->fOutputBuffer, fDriver->GetOutputBuffer(i), fDriver->fEngineControl->fBufferSize, i, fDriver->fPlaybackChannels, fDriver->fBits);
}
}
@@ -705,23 +718,23 @@ bool JackBoomerDriver::Execute()
gCycleTable.fTable[gCycleWriteCount].fBeforeWrite = GetMicroSeconds();
#endif

ssize_t count = ::write(fOutFD, fOutputBuffer, fOutputBufferSize);
ssize_t count = ::write(fDriver->fOutFD, fDriver->fOutputBuffer, fDriver->fOutputBufferSize);

#ifdef JACK_MONITOR
if (count > 0 && count != (int)fOutputBufferSize)
jack_log("JackBoomerDriver::Execute count = %ld", count / (fSampleSize * fPlaybackChannels));
if (count > 0 && count != (int)fDriver->fOutputBufferSize)
jack_log("JackBoomerDriverOutput::Execute count = %ld", count / (fDriver->fSampleSize * fDriver->fPlaybackChannels));
gCycleTable.fTable[gCycleWriteCount].fAfterWrite = GetMicroSeconds();
gCycleWriteCount = (gCycleWriteCount == CYCLE_POINTS - 1) ? gCycleWriteCount: gCycleWriteCount + 1;
#endif

// XRun detection
audio_errinfo ei_out;
if (ioctl(fOutFD, SNDCTL_DSP_GETERROR, &ei_out) == 0) {
if (ioctl(fDriver->fOutFD, SNDCTL_DSP_GETERROR, &ei_out) == 0) {

if (ei_out.play_underruns > 0) {
jack_error("JackBoomerDriver::Execute underruns");
jack_error("JackBoomerDriverOutput::Execute underruns");
jack_time_t cur_time = GetMicroSeconds();
NotifyXRun(cur_time, float(cur_time - fBeginDateUst)); // Better this value than nothing...
fDriver->NotifyXRun(cur_time, float(cur_time - fDriver->fBeginDateUst)); // Better this value than nothing...
}

if (ei_out.play_errorcount > 0 && ei_out.play_lasterror != 0) {
@@ -730,14 +743,28 @@ bool JackBoomerDriver::Execute()
}
if (count < 0) {
jack_log("JackBoomerDriver::Execute error = %s", strerror(errno));
} else if (count < (int)fOutputBufferSize) {
jack_error("JackBoomerDriver::Execute error bytes written = %ld", count);
jack_log("JackBoomerDriverOutput::Execute error = %s", strerror(errno));
} else if (count < (int)fDriver->fOutputBufferSize) {
jack_error("JackBoomerDriverOutput::Execute error bytes written = %ld", count);
}
fDriver->SynchronizeWrite();
return true;
}

void JackBoomerDriver::SynchronizeRead()
{
sem_wait(&fWriteSema);
Process();
sem_post(&fReadSema);
}

void JackBoomerDriver::SynchronizeWrite()
{
sem_post(&fWriteSema);
sem_wait(&fReadSema);
}

int JackBoomerDriver::SetBufferSize(jack_nframes_t buffer_size)
{
CloseAux();
@@ -966,14 +993,13 @@ EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine
}

Jack::JackBoomerDriver* boomer_driver = new Jack::JackBoomerDriver("system", "boomer", engine, table);
Jack::JackDriverClientInterface* threaded_driver = new Jack::JackThreadedDriver(boomer_driver);
// Special open for Boomer driver...
if (boomer_driver->Open(frames_per_interrupt, nperiods, srate, capture, playback, chan_in, chan_out,
excl, monitor, capture_pcm_name, playback_pcm_name, systemic_input_latency, systemic_output_latency, bits, ignorehwbuf) == 0) {
return threaded_driver;
return boomer_driver;
} else {
delete threaded_driver; // Delete the decorated driver
delete boomer_driver; // Delete the driver
return NULL;
}
}


+ 50
- 16
solaris/oss/JackBoomerDriver.h View File

@@ -23,7 +23,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#include "JackAudioDriver.h"
#include "JackPlatformPlug.h"
#include "ringbuffer.h"
//#include "JackThread.h"
#include <semaphore.h>

namespace Jack
{
@@ -43,13 +43,47 @@ typedef jack_default_audio_sample_t jack_sample_t;
\brief The Boomer driver.
*/

class JackBoomerDriver : public JackAudioDriver, public JackRunnableInterface
class JackBoomerDriver : public JackAudioDriver
{

enum { kRead = 1, kWrite = 2, kReadWrite = 3 };

private:

class JackBoomerDriverInput : public JackRunnableInterface {

private:
JackBoomerDriver* fDriver;

public:

JackBoomerDriverInput(JackBoomerDriver* driver): fDriver(driver)
{}
~JackBoomerDriverInput()
{}

bool Init();
bool Execute();
};

class JackBoomerDriverOutput : public JackRunnableInterface {

private:
JackBoomerDriver* fDriver;

public:

JackBoomerDriverOutput(JackBoomerDriver* driver): fDriver(driver)
{}
~JackBoomerDriverOutput()
{}

bool Init();
bool Execute();
};

int fInFD;
int fOutFD;
@@ -66,8 +100,15 @@ class JackBoomerDriver : public JackAudioDriver, public JackRunnableInterface
void* fInputBuffer;
void* fOutputBuffer;
jack_ringbuffer_t** fRingBuffer;
JackThread fThread;
sem_t fReadSema;
sem_t fWriteSema;

JackThread fInputThread;
JackThread fOutputThread;
JackBoomerDriverInput fInputHandler;
JackBoomerDriverOutput fOutputHandler;
int OpenInput();
int OpenOutput();
@@ -75,21 +116,14 @@ class JackBoomerDriver : public JackAudioDriver, public JackRunnableInterface
void CloseAux();
void SetSampleFormat();
void DisplayDeviceInfo();
void SynchronizeRead();
void SynchronizeWrite();

public:

JackBoomerDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table)
: JackAudioDriver(name, alias, engine, table),
fInFD(-1), fOutFD(-1), fBits(0),
fSampleFormat(0), fNperiods(0), fRWMode(0), fExcl(false), fIgnoreHW(true),
fInputBufferSize(0), fOutputBufferSize(0),
fInputBuffer(NULL), fOutputBuffer(NULL),
fRingBuffer(NULL), fThread(this)
{}

virtual ~JackBoomerDriver()
{}

JackBoomerDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table);
virtual ~JackBoomerDriver();
int Open(jack_nframes_t frames_per_cycle,
int user_nperiods,
jack_nframes_t rate,


Loading…
Cancel
Save