Commit bfecb007 authored by sletz's avatar sletz
Browse files

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
parent 56f4d13e
......@@ -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>
......
......@@ -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;
}
}
......
......@@ -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,
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment