diff --git a/ChangeLog b/ChangeLog index c615c46a..2548033e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -25,7 +25,12 @@ Paul Davis Jackdmp changes log --------------------------- -2009-07-30 Stephane Letz +2009-07-31 Stephane Letz + + * Use SNDCTL_DSP_SYNCGROUP/SNDCTL_DSP_SYNCSTART API to synchronize input and output in Solaris boomer backend. + + +2009-07-29 Stephane Letz * Add a -G parameter in CoreAudio backend (the computation value in RT thread expressed as percent of period). diff --git a/solaris/oss/JackBoomerDriver.cpp b/solaris/oss/JackBoomerDriver.cpp index 396b80ef..7c2dfc22 100644 --- a/solaris/oss/JackBoomerDriver.cpp +++ b/solaris/oss/JackBoomerDriver.cpp @@ -171,6 +171,7 @@ void JackBoomerDriver::DisplayDeviceInfo() } else { jack_info("output space info: fragments = %d, fragstotal = %d, fragsize = %d, bytes = %d", info.fragments, info.fragstotal, info.fragsize, info.bytes); + fFragmentSize = info.fragsize; } if (ioctl(fOutFD, SNDCTL_DSP_GETCAPS, &cap) == -1) { @@ -233,7 +234,8 @@ 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), + fSampleFormat(0), fNperiods(0), fSampleSize(0), fFragmentSize(0), + fRWMode(0), fExcl(false), fSyncIO(false), fInputBufferSize(0), fOutputBufferSize(0), fInputBuffer(NULL), fOutputBuffer(NULL), fInputThread(&fInputHandler), fOutputThread(&fOutputHandler), @@ -401,7 +403,7 @@ int JackBoomerDriver::Open(jack_nframes_t nframes, const char* playback_driver_uid, jack_nframes_t capture_latency, jack_nframes_t playback_latency, - int bits) + int bits, bool syncio) { // Generic JackAudioDriver Open if (JackAudioDriver::Open(nframes, samplerate, capturing, playing, inchannels, outchannels, monitor, @@ -419,6 +421,7 @@ int JackBoomerDriver::Open(jack_nframes_t nframes, fBits = bits; fExcl = excl; fNperiods = (user_nperiods == 0) ? 1 : user_nperiods ; + fSyncIO = syncio; #ifdef JACK_MONITOR // Force memory page in @@ -529,7 +532,60 @@ int JackBoomerDriver::Start() { jack_log("JackBoomerDriver::Start"); JackAudioDriver::Start(); - + + // Input/output synchronisation + if (fInFD >= 0 && fOutFD >= 0 && fSyncIO) { + + jack_log ("JackBoomerDriverOutput::Start sync input/output"); + + // Create and fill synch group + int id; + oss_syncgroup group; + group.id = 0; + + group.mode = PCM_ENABLE_INPUT; + if (ioctl(fInFD, SNDCTL_DSP_SYNCGROUP, &group) == -1) + jack_error("JackBoomerDriver::Start failed to use SNDCTL_DSP_SYNCGROUP : %s@%i, errno = %d", __FILE__, __LINE__, errno); + + group.mode = PCM_ENABLE_OUTPUT; + if (ioctl(fOutFD, SNDCTL_DSP_SYNCGROUP, &group) == -1) + jack_error("JackBoomerDriver::Start failed to use SNDCTL_DSP_SYNCGROUP : %s@%i, errno = %d", __FILE__, __LINE__, errno); + + // Prefill ouput buffer : 2 fragments of silence as described in http://manuals.opensound.com/developer/synctest.c.html#LOC6 + char* silence_buf = (char*)malloc(fFragmentSize); + memset(silence_buf, 0, fFragmentSize); + + jack_log ("JackBoomerDriverOutput::Start prefill size = %d", fFragmentSize); + + for (int i = 0; i < 2; i++) { + ssize_t count = ::write(fOutFD, silence_buf, fFragmentSize); + if (count < (int)fFragmentSize) { + jack_error("JackBoomerDriverOutput::Start error bytes written = %ld", count); + } + } + + free(silence_buf); + + // Start input/output in sync + id = group.id; + + if (ioctl(fInFD, SNDCTL_DSP_SYNCSTART, &id) == -1) + jack_error("JackBoomerDriver::Start failed to use SNDCTL_DSP_SYNCSTART : %s@%i, errno = %d", __FILE__, __LINE__, errno); + + } else if (fOutFD >= 0) { + + // Maybe necessary to write an empty output buffer first time : see http://manuals.opensound.com/developer/fulldup.c.html + memset(fOutputBuffer, 0, fOutputBufferSize); + + // Prefill ouput buffer + for (int i = 0; i < fNperiods; i++) { + ssize_t count = ::write(fOutFD, fOutputBuffer, fOutputBufferSize); + if (count < (int)fOutputBufferSize) { + jack_error("JackBoomerDriverOutput::Init error bytes written = %ld", count); + } + } + } + // Start input thread only when needed if (fInFD >= 0) { if (fInputThread.StartSync() < 0) { @@ -653,18 +709,7 @@ bool JackBoomerDriver::JackBoomerDriverOutput::Init() set_threaded_log_function(); } } - - // Maybe necessary to write an empty output buffer first time : see http://manuals.opensound.com/developer/fulldup.c.html - memset(fDriver->fOutputBuffer, 0, fDriver->fOutputBufferSize); - - // Prefill ouput buffer - 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("JackBoomerDriverOutput::Init error bytes written = %ld", count); - } - } - + int delay; if (ioctl(fDriver->fOutFD, SNDCTL_DSP_GETODELAY, &delay) == -1) { jack_error("JackBoomerDriverOutput::Init error get out delay : %s@%i, errno = %d", __FILE__, __LINE__, errno); @@ -876,6 +921,14 @@ SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor() strcpy(desc->params[i].short_desc, "Extra output latency"); strcpy(desc->params[i].long_desc, desc->params[i].short_desc); + i++; + strcpy(desc->params[i].name, "sync-io"); + desc->params[i].character = 'S'; + desc->params[i].type = JackDriverParamBool; + desc->params[i].value.i = false; + strcpy(desc->params[i].short_desc, "In duplex mode, synchronize input and ouput"); + strcpy(desc->params[i].long_desc, desc->params[i].short_desc); + return desc; } @@ -892,6 +945,7 @@ EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine int chan_out = 0; bool monitor = false; bool excl = false; + bool syncio = false; unsigned int nperiods = OSS_DRIVER_DEF_NPERIODS; const JSList *node; const jack_driver_param_t *param; @@ -958,6 +1012,10 @@ EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine case 'O': systemic_output_latency = param->value.ui; break; + + case 'S': + syncio = true; + break; } } @@ -971,7 +1029,7 @@ EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine // 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) == 0) { + monitor, capture_pcm_name, playback_pcm_name, systemic_input_latency, systemic_output_latency, bits, syncio) == 0) { return boomer_driver; } else { delete boomer_driver; // Delete the driver diff --git a/solaris/oss/JackBoomerDriver.h b/solaris/oss/JackBoomerDriver.h index c54d6a91..61fc5c50 100644 --- a/solaris/oss/JackBoomerDriver.h +++ b/solaris/oss/JackBoomerDriver.h @@ -30,7 +30,7 @@ namespace Jack typedef jack_default_audio_sample_t jack_sample_t; -#define OSS_DRIVER_N_PARAMS 12 +#define OSS_DRIVER_N_PARAMS 13 #define OSS_DRIVER_DEF_DEV "/dev/dsp" #define OSS_DRIVER_DEF_FS 48000 #define OSS_DRIVER_DEF_BLKSIZE 1024 @@ -91,8 +91,10 @@ class JackBoomerDriver : public JackAudioDriver int fSampleFormat; int fNperiods; unsigned int fSampleSize; + unsigned int fFragmentSize; int fRWMode; bool fExcl; + bool fSyncIO; unsigned int fInputBufferSize; unsigned int fOutputBufferSize; @@ -136,7 +138,7 @@ class JackBoomerDriver : public JackAudioDriver const char* playback_driver_name, jack_nframes_t capture_latency, jack_nframes_t playback_latency, - int bits); + int bits, bool syncio); int Close();