diff --git a/.cproject b/.cproject
new file mode 100644
index 00000000..3cad824b
--- /dev/null
+++ b/.cproject
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.project b/.project
new file mode 100644
index 00000000..819bdba9
--- /dev/null
+++ b/.project
@@ -0,0 +1,27 @@
+
+
+ jack2
+
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.genmakebuilder
+ clean,full,incremental,
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder
+ full,incremental,
+
+
+
+
+
+ org.eclipse.cdt.core.cnature
+ org.eclipse.cdt.core.ccnature
+ org.eclipse.cdt.managedbuilder.core.managedBuildNature
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigNature
+
+
diff --git a/qnx/driver.h b/qnx/driver.h
new file mode 100644
index 00000000..6e1466f4
--- /dev/null
+++ b/qnx/driver.h
@@ -0,0 +1,300 @@
+/*
+ Copyright (C) 2001 Paul Davis
+
+ 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.
+
+ $Id: driver.h,v 1.2 2005/11/23 11:24:29 letz Exp $
+*/
+
+#ifndef __jack_driver_h__
+#define __jack_driver_h__
+
+#include
+#include "types.h"
+#include "jslist.h"
+#include "driver_interface.h"
+
+typedef float gain_t;
+typedef long channel_t;
+
+typedef enum {
+ Lock = 0x1,
+ NoLock = 0x2,
+ Sync = 0x4,
+ NoSync = 0x8
+} ClockSyncStatus;
+
+typedef void (*ClockSyncListenerFunction)(channel_t, ClockSyncStatus, void*);
+
+typedef struct
+{
+ unsigned long id;
+ ClockSyncListenerFunction function;
+ void *arg;
+}
+ClockSyncListener;
+
+struct _jack_engine;
+struct _jack_driver;
+
+typedef int (*JackDriverAttachFunction)(struct _jack_driver *,
+ struct _jack_engine *);
+typedef int (*JackDriverDetachFunction)(struct _jack_driver *,
+ struct _jack_engine *);
+typedef int (*JackDriverReadFunction)(struct _jack_driver *,
+ jack_nframes_t nframes);
+typedef int (*JackDriverWriteFunction)(struct _jack_driver *,
+ jack_nframes_t nframes);
+typedef int (*JackDriverNullCycleFunction)(struct _jack_driver *,
+ jack_nframes_t nframes);
+typedef int (*JackDriverStopFunction)(struct _jack_driver *);
+typedef int (*JackDriverStartFunction)(struct _jack_driver *);
+typedef int (*JackDriverBufSizeFunction)(struct _jack_driver *,
+ jack_nframes_t nframes);
+/*
+ Call sequence summary:
+
+ 1) engine loads driver via runtime dynamic linking
+ - calls jack_driver_load
+ - we call dlsym for "driver_initialize" and execute it
+ 2) engine attaches to driver
+ 3) engine starts driver
+ 4) driver runs its own thread, calling
+ while () {
+ driver->wait ();
+ driver->engine->run_cycle ()
+ }
+ 5) engine stops driver
+ 6) engine detaches from driver
+ 7) engine calls driver `finish' routine
+
+ Note that stop/start may be called multiple times in the event of an
+ error return from the `wait' function.
+*/
+
+typedef struct _jack_driver
+{
+
+ /* The _jack_driver structure fields are included at the beginning of
+ each driver-specific structure using the JACK_DRIVER_DECL macro,
+ which is defined below. The comments that follow describe each
+ common field.
+
+ The driver should set this to be the interval it expects to elapse
+ between returning from the `wait' function. if set to zero, it
+ implies that the driver does not expect regular periodic wakeups.
+
+ jack_time_t period_usecs;
+
+
+ The driver should set this within its "wait" function to indicate
+ the UST of the most recent determination that the engine cycle
+ should run. it should not be set if the "extra_fd" argument of
+ the wait function is set to a non-zero value.
+
+ jack_time_t last_wait_ust;
+
+
+ These are not used by the driver. They should not be written to or
+ modified in any way
+
+ void *handle;
+ struct _jack_internal_client *internal_client;
+
+ This should perform any cleanup associated with the driver. it will
+ be called when jack server process decides to get rid of the
+ driver. in some systems, it may not be called at all, so the driver
+ should never rely on a call to this. it can set it to NULL if
+ it has nothing do do.
+
+ void (*finish)(struct _jack_driver *);
+
+
+ The JACK engine will call this when it wishes to attach itself to
+ the driver. the engine will pass a pointer to itself, which the driver
+ may use in anyway it wishes to. the driver may assume that this
+ is the same engine object that will make `wait' calls until a
+ `detach' call is made.
+
+ JackDriverAttachFunction attach;
+
+
+ The JACK engine will call this when it is finished using a driver.
+
+ JackDriverDetachFunction detach;
+
+
+ The JACK engine will call this when it wants to wait until the
+ driver decides that its time to process some data. the driver returns
+ a count of the number of audioframes that can be processed.
+
+ it should set the variable pointed to by `status' as follows:
+
+ zero: the wait completed normally, processing may begin
+ negative: the wait failed, and recovery is not possible
+ positive: the wait failed, and the driver stopped itself.
+ a call to `start' will return the driver to
+ a correct and known state.
+
+ the driver should also fill out the `delayed_usecs' variable to
+ indicate any delay in its expected periodic execution. for example,
+ if it discovers that its return from poll(2) is later than it
+ expects it to be, it would place an estimate of the delay
+ in this variable. the engine will use this to decide if it
+ plans to continue execution.
+
+ JackDriverWaitFunction wait;
+
+
+ The JACK engine will call this to ask the driver to move
+ data from its inputs to its output port buffers. it should
+ return 0 to indicate successful completion, negative otherwise.
+
+ This function will always be called after the wait function (above).
+
+ JackDriverReadFunction read;
+
+
+ The JACK engine will call this to ask the driver to move
+ data from its input port buffers to its outputs. it should
+ return 0 to indicate successful completion, negative otherwise.
+
+ this function will always be called after the read function (above).
+
+ JackDriverWriteFunction write;
+
+
+ The JACK engine will call this after the wait function (above) has
+ been called, but for some reason the engine is unable to execute
+ a full "cycle". the driver should do whatever is necessary to
+ keep itself running correctly, but cannot reference ports
+ or other JACK data structures in any way.
+
+ JackDriverNullCycleFunction null_cycle;
+
+
+ The engine will call this when it plans to stop calling the `wait'
+ function for some period of time. the driver should take
+ appropriate steps to handle this (possibly no steps at all).
+ NOTE: the driver must silence its capture buffers (if any)
+ from within this function or the function that actually
+ implements the change in state.
+
+ JackDriverStopFunction stop;
+
+
+ The engine will call this to let the driver know that it plans
+ to start calling the `wait' function on a regular basis. the driver
+ should take any appropriate steps to handle this (possibly no steps
+ at all). NOTE: The driver may wish to silence its playback buffers
+ (if any) from within this function or the function that actually
+ implements the change in state.
+
+ JackDriverStartFunction start;
+
+ The engine will call this to let the driver know that some client
+ has requested a new buffer size. The stop function will be called
+ prior to this, and the start function after this one has returned.
+
+ JackDriverBufSizeFunction bufsize;
+ */
+
+ /* define the fields here... */
+#define JACK_DRIVER_DECL \
+ jack_time_t period_usecs; \
+ jack_time_t last_wait_ust; \
+ void *handle; \
+ struct _jack_client_internal * internal_client; \
+ void (*finish)(struct _jack_driver *);\
+ JackDriverAttachFunction attach; \
+ JackDriverDetachFunction detach; \
+ JackDriverReadFunction read; \
+ JackDriverWriteFunction write; \
+ JackDriverNullCycleFunction null_cycle; \
+ JackDriverStopFunction stop; \
+ JackDriverStartFunction start; \
+ JackDriverBufSizeFunction bufsize;
+
+ JACK_DRIVER_DECL /* expand the macro */
+}
+jack_driver_t;
+
+void jack_driver_init (jack_driver_t *);
+void jack_driver_release (jack_driver_t *);
+
+jack_driver_t *jack_driver_load (int argc, char **argv);
+void jack_driver_unload (jack_driver_t *);
+
+/****************************
+ *** Non-Threaded Drivers ***
+ ****************************/
+
+/*
+ Call sequence summary:
+
+ 1) engine loads driver via runtime dynamic linking
+ - calls jack_driver_load
+ - we call dlsym for "driver_initialize" and execute it
+ - driver_initialize calls jack_driver_nt_init
+ 2) nt layer attaches to driver
+ 3) nt layer starts driver
+ 4) nt layer runs a thread, calling
+ while () {
+ driver->nt_run_ctcle();
+ }
+ 5) nt layer stops driver
+ 6) nt layer detaches driver
+ 7) engine calls driver `finish' routine which calls jack_driver_nt_finish
+
+ Note that stop/start may be called multiple times in the event of an
+ error return from the `wait' function.
+*/
+
+struct _jack_driver_nt;
+
+typedef int (*JackDriverNTAttachFunction)(struct _jack_driver_nt *);
+typedef int (*JackDriverNTDetachFunction)(struct _jack_driver_nt *);
+typedef int (*JackDriverNTStopFunction)(struct _jack_driver_nt *);
+typedef int (*JackDriverNTStartFunction)(struct _jack_driver_nt *);
+typedef int (*JackDriverNTBufSizeFunction)(struct _jack_driver_nt *,
+ jack_nframes_t nframes);
+typedef int (*JackDriverNTRunCycleFunction)(struct _jack_driver_nt *);
+
+typedef struct _jack_driver_nt
+{
+#define JACK_DRIVER_NT_DECL \
+ JACK_DRIVER_DECL \
+ struct _jack_engine * engine; \
+ volatile int nt_run; \
+ pthread_t nt_thread; \
+ pthread_mutex_t nt_run_lock; \
+ JackDriverNTAttachFunction nt_attach; \
+ JackDriverNTDetachFunction nt_detach; \
+ JackDriverNTStopFunction nt_stop; \
+ JackDriverNTStartFunction nt_start; \
+ JackDriverNTBufSizeFunction nt_bufsize; \
+ JackDriverNTRunCycleFunction nt_run_cycle;
+#define nt_read read
+#define nt_write write
+#define nt_null_cycle null_cycle
+
+ JACK_DRIVER_NT_DECL
+}
+jack_driver_nt_t;
+
+void jack_driver_nt_init (jack_driver_nt_t * driver);
+void jack_driver_nt_finish (jack_driver_nt_t * driver);
+
+#endif /* __jack_driver_h__ */
diff --git a/qnx/ioaudio/JackIoAudioDriver.cpp b/qnx/ioaudio/JackIoAudioDriver.cpp
new file mode 100644
index 00000000..7e2d22be
--- /dev/null
+++ b/qnx/ioaudio/JackIoAudioDriver.cpp
@@ -0,0 +1,940 @@
+/*
+Copyright (C) 2001 Paul Davis
+Copyright (C) 2004 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.
+
+*/
+
+#define __STDC_FORMAT_MACROS // For inttypes.h to work in C++
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "JackIoAudioDriver.h"
+#include "JackEngineControl.h"
+#include "JackClientControl.h"
+#include "JackPort.h"
+#include "JackGraphManager.h"
+#include "JackLockedEngine.h"
+#ifdef __ANDROID__
+#include "JackAndroidThread.h"
+#else
+#include "JackPosixThread.h"
+#endif
+#include "JackCompilerDeps.h"
+#include "JackServerGlobals.h"
+
+static struct jack_constraint_enum_str_descriptor midi_constraint_descr_array[] =
+{
+ { "none", "no MIDI driver" },
+ { "seq", "IoAudio Sequencer driver" },
+ { "raw", "IoAudio RawMIDI driver" },
+ { 0 }
+};
+
+static struct jack_constraint_enum_char_descriptor dither_constraint_descr_array[] =
+{
+ { 'n', "none" },
+ { 'r', "rectangular" },
+ { 's', "shaped" },
+ { 't', "triangular" },
+ { 0 }
+};
+
+namespace Jack
+{
+
+int JackIoAudioDriver::SetBufferSize(jack_nframes_t buffer_size)
+{
+ jack_log("JackIoAudioDriver::SetBufferSize %ld", buffer_size);
+ int res = ioaudio_driver_reset_parameters((ioaudio_driver_t *)fDriver, buffer_size,
+ ((ioaudio_driver_t *)fDriver)->user_nperiods,
+ ((ioaudio_driver_t *)fDriver)->frame_rate);
+
+ if (res == 0) { // update fEngineControl and fGraphManager
+ JackAudioDriver::SetBufferSize(buffer_size); // Generic change, never fails
+ // IoAudio specific
+ UpdateLatencies();
+ } else {
+ // Restore old values
+ ioaudio_driver_reset_parameters((ioaudio_driver_t *)fDriver, fEngineControl->fBufferSize,
+ ((ioaudio_driver_t *)fDriver)->user_nperiods,
+ ((ioaudio_driver_t *)fDriver)->frame_rate);
+ }
+
+ return res;
+}
+
+void JackIoAudioDriver::UpdateLatencies()
+{
+ jack_latency_range_t range;
+ ioaudio_driver_t* ioaudio_driver = (ioaudio_driver_t*)fDriver;
+
+ for (int i = 0; i < fCaptureChannels; i++) {
+ range.min = range.max = ioaudio_driver->frames_per_cycle + ioaudio_driver->capture_frame_latency;
+ fGraphManager->GetPort(fCapturePortList[i])->SetLatencyRange(JackCaptureLatency, &range);
+ }
+
+ for (int i = 0; i < fPlaybackChannels; i++) {
+ // Add one buffer more latency if "async" mode is used...
+ range.min = range.max = (ioaudio_driver->frames_per_cycle * (ioaudio_driver->user_nperiods - 1)) +
+ ((fEngineControl->fSyncMode) ? 0 : fEngineControl->fBufferSize) + ioaudio_driver->playback_frame_latency;
+ fGraphManager->GetPort(fPlaybackPortList[i])->SetLatencyRange(JackPlaybackLatency, &range);
+ // Monitor port
+ if (fWithMonitorPorts) {
+ range.min = range.max = ioaudio_driver->frames_per_cycle;
+ fGraphManager->GetPort(fMonitorPortList[i])->SetLatencyRange(JackCaptureLatency, &range);
+ }
+ }
+}
+
+int JackIoAudioDriver::Attach()
+{
+ JackPort* port;
+ jack_port_id_t port_index;
+ unsigned long port_flags = (unsigned long)CaptureDriverFlags;
+ char name[REAL_JACK_PORT_NAME_SIZE];
+ char alias[REAL_JACK_PORT_NAME_SIZE];
+
+ assert(fCaptureChannels < DRIVER_PORT_NUM);
+ assert(fPlaybackChannels < DRIVER_PORT_NUM);
+
+ ioaudio_driver_t* ioaudio_driver = (ioaudio_driver_t*)fDriver;
+
+ if (ioaudio_driver->has_hw_monitoring)
+ port_flags |= JackPortCanMonitor;
+
+ // IoAudio driver may have changed the values
+ JackAudioDriver::SetBufferSize(ioaudio_driver->frames_per_cycle);
+ JackAudioDriver::SetSampleRate(ioaudio_driver->frame_rate);
+
+ jack_log("JackIoAudioDriver::Attach fBufferSize %ld fSampleRate %ld", fEngineControl->fBufferSize, fEngineControl->fSampleRate);
+
+ for (int i = 0; i < fCaptureChannels; i++) {
+ snprintf(alias, sizeof(alias), "%s:%s:out%d", fAliasName, fCaptureDriverName, i + 1);
+ snprintf(name, sizeof(name), "%s:capture_%d", fClientControl.fName, i + 1);
+ if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, (JackPortFlags)port_flags, fEngineControl->fBufferSize, &port_index) < 0) {
+ jack_error("driver: cannot register port for %s", name);
+ return -1;
+ }
+ port = fGraphManager->GetPort(port_index);
+ port->SetAlias(alias);
+ fCapturePortList[i] = port_index;
+ jack_log("JackIoAudioDriver::Attach fCapturePortList[i] %ld ", port_index);
+ }
+
+ port_flags = (unsigned long)PlaybackDriverFlags;
+
+ for (int i = 0; i < fPlaybackChannels; i++) {
+ snprintf(alias, sizeof(alias), "%s:%s:in%d", fAliasName, fPlaybackDriverName, i + 1);
+ snprintf(name, sizeof(name), "%s:playback_%d", fClientControl.fName, i + 1);
+ if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, (JackPortFlags)port_flags, fEngineControl->fBufferSize, &port_index) < 0) {
+ jack_error("driver: cannot register port for %s", name);
+ return -1;
+ }
+ port = fGraphManager->GetPort(port_index);
+ port->SetAlias(alias);
+ fPlaybackPortList[i] = port_index;
+ jack_log("JackIoAudioDriver::Attach fPlaybackPortList[i] %ld ", port_index);
+
+ // Monitor ports
+ if (fWithMonitorPorts) {
+ jack_log("Create monitor port");
+ snprintf(name, sizeof(name), "%s:monitor_%d", fClientControl.fName, i + 1);
+ if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, MonitorDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) {
+ jack_error("IoAudio: cannot register monitor port for %s", name);
+ } else {
+ fMonitorPortList[i] = port_index;
+ }
+ }
+ }
+
+ UpdateLatencies();
+
+// if (ioaudio_driver->midi) {
+// int err = (ioaudio_driver->midi->attach)(ioaudio_driver->midi);
+// if (err)
+// jack_error ("IoAudio: cannot attach MIDI: %d", err);
+// }
+
+ return 0;
+}
+
+int JackIoAudioDriver::Detach()
+{
+ ioaudio_driver_t* ioaudio_driver = (ioaudio_driver_t*)fDriver;
+// if (ioaudio_driver->midi)
+// (ioaudio_driver->midi->detach)(ioaudio_driver->midi);
+
+ return JackAudioDriver::Detach();
+}
+
+extern "C" char* get_control_device_name(const char * device_name)
+{
+ char * ctl_name;
+ const char * comma;
+
+ /* the user wants a hw or plughw device, the ctl name
+ * should be hw:x where x is the card identification.
+ * We skip the subdevice suffix that starts with comma */
+
+ if (strncasecmp(device_name, "plughw:", 7) == 0) {
+ /* skip the "plug" prefix" */
+ device_name += 4;
+ }
+
+ comma = strchr(device_name, ',');
+ if (comma == NULL) {
+ ctl_name = strdup(device_name);
+ if (ctl_name == NULL) {
+ jack_error("strdup(\"%s\") failed.", device_name);
+ }
+ } else {
+// ctl_name = strndup(device_name, comma - device_name);
+ ctl_name = strdup(device_name);
+ if (ctl_name == NULL) {
+ jack_error("strdup(\"%s\", %u) failed.", device_name, (unsigned int)(comma - device_name));
+ }
+ ctl_name[comma - device_name] = '\0';
+ }
+
+ return ctl_name;
+}
+
+static int card_to_num(const char* device)
+{
+ int err;
+ char* ctl_name;
+ snd_ctl_card_info_t *card_info;
+ snd_ctl_t* ctl_handle;
+ int i = -1;
+
+ snd_ctl_card_info_alloca (&card_info);
+
+ ctl_name = get_control_device_name(device);
+ if (ctl_name == NULL) {
+ jack_error("get_control_device_name() failed.");
+ goto fail;
+ }
+
+ if ((err = snd_ctl_open (&ctl_handle, ctl_name, 0)) < 0) {
+ jack_error ("control open \"%s\" (%s)", ctl_name,
+ snd_strerror(err));
+ goto free;
+ }
+
+ if ((err = snd_ctl_card_info(ctl_handle, card_info)) < 0) {
+ jack_error ("control hardware info \"%s\" (%s)",
+ device, snd_strerror (err));
+ goto close;
+ }
+
+ i = snd_ctl_card_info_get_card(card_info);
+
+close:
+ snd_ctl_close(ctl_handle);
+
+free:
+ free(ctl_name);
+
+fail:
+ return i;
+}
+
+int JackIoAudioDriver::Open(jack_nframes_t nframes,
+ jack_nframes_t user_nperiods,
+ jack_nframes_t samplerate,
+ bool hw_monitoring,
+ bool hw_metering,
+ bool capturing,
+ bool playing,
+ DitherAlgorithm dither,
+ bool soft_mode,
+ bool monitor,
+ int inchannels,
+ int outchannels,
+ bool shorts_first,
+ const char* capture_driver_name,
+ const char* playback_driver_name,
+ jack_nframes_t capture_latency,
+ jack_nframes_t playback_latency /*,
+ const char* midi_driver_name */
+ )
+{
+ // Generic JackAudioDriver Open
+ if (JackAudioDriver::Open(nframes, samplerate, capturing, playing,
+ inchannels, outchannels, monitor, capture_driver_name, playback_driver_name,
+ capture_latency, playback_latency) != 0) {
+ return -1;
+ }
+
+// ioaudio_midi_t *midi = 0;
+//#ifndef __ANDROID__
+// if (strcmp(midi_driver_name, "seq") == 0)
+// midi = ioaudio_seqmidi_new((jack_client_t*)this, 0);
+// else if (strcmp(midi_driver_name, "raw") == 0)
+// midi = ioaudio_rawmidi_new((jack_client_t*)this);
+//#endif
+
+ if (JackServerGlobals::on_device_acquire != NULL) {
+ int capture_card = card_to_num(capture_driver_name);
+ int playback_card = card_to_num(playback_driver_name);
+ char audio_name[32];
+
+ if (capture_card >= 0) {
+ snprintf(audio_name, sizeof(audio_name), "Audio%d", capture_card);
+ if (!JackServerGlobals::on_device_acquire(audio_name)) {
+ jack_error("Audio device %s cannot be acquired...", capture_driver_name);
+ return -1;
+ }
+ }
+
+ if (playback_card >= 0 && playback_card != capture_card) {
+ snprintf(audio_name, sizeof(audio_name), "Audio%d", playback_card);
+ if (!JackServerGlobals::on_device_acquire(audio_name)) {
+ jack_error("Audio device %s cannot be acquired...", playback_driver_name);
+ if (capture_card >= 0) {
+ snprintf(audio_name, sizeof(audio_name), "Audio%d", capture_card);
+ JackServerGlobals::on_device_release(audio_name);
+ }
+ return -1;
+ }
+ }
+ }
+
+ fDriver = ioaudio_driver_new ((char*)"ioaudio_pcm", (char*)playback_driver_name, (char*)capture_driver_name,
+ NULL,
+ nframes,
+ user_nperiods,
+ samplerate,
+ hw_monitoring,
+ hw_metering,
+ capturing,
+ playing,
+ dither,
+ soft_mode,
+ monitor,
+ inchannels,
+ outchannels,
+ shorts_first,
+ capture_latency,
+ playback_latency /*,
+ midi */
+ );
+ if (fDriver) {
+ // IoAudio driver may have changed the in/out values
+ fCaptureChannels = ((ioaudio_driver_t *)fDriver)->capture_nchannels;
+ fPlaybackChannels = ((ioaudio_driver_t *)fDriver)->playback_nchannels;
+ return 0;
+ } else {
+ JackAudioDriver::Close();
+ return -1;
+ }
+}
+
+int JackIoAudioDriver::Close()
+{
+ // Generic audio driver close
+ int res = JackAudioDriver::Close();
+
+ ioaudio_driver_delete((ioaudio_driver_t*)fDriver);
+
+ if (JackServerGlobals::on_device_release != NULL)
+ {
+ char audio_name[32];
+ int capture_card = card_to_num(fCaptureDriverName);
+ if (capture_card >= 0) {
+ snprintf(audio_name, sizeof(audio_name), "Audio%d", capture_card);
+ JackServerGlobals::on_device_release(audio_name);
+ }
+
+ int playback_card = card_to_num(fPlaybackDriverName);
+ if (playback_card >= 0 && playback_card != capture_card) {
+ snprintf(audio_name, sizeof(audio_name), "Audio%d", playback_card);
+ JackServerGlobals::on_device_release(audio_name);
+ }
+ }
+
+ return res;
+}
+
+int JackIoAudioDriver::Start()
+{
+ int res = JackAudioDriver::Start();
+ if (res >= 0) {
+ res = ioaudio_driver_start((ioaudio_driver_t *)fDriver);
+ if (res < 0) {
+ JackAudioDriver::Stop();
+ }
+ }
+ return res;
+}
+
+int JackIoAudioDriver::Stop()
+{
+ int res = ioaudio_driver_stop((ioaudio_driver_t *)fDriver);
+ if (JackAudioDriver::Stop() < 0) {
+ res = -1;
+ }
+ return res;
+}
+
+int JackIoAudioDriver::Read()
+{
+ /* Taken from ioaudio_driver_run_cycle */
+ int wait_status;
+ jack_nframes_t nframes;
+ fDelayedUsecs = 0.f;
+
+retry:
+
+ nframes = ioaudio_driver_wait((ioaudio_driver_t *)fDriver, -1, &wait_status, &fDelayedUsecs);
+
+ if (wait_status < 0)
+ return -1; /* driver failed */
+
+ if (nframes == 0) {
+ /* we detected an xrun and restarted: notify
+ * clients about the delay.
+ */
+ jack_log("IoAudio XRun wait_status = %d", wait_status);
+ NotifyXRun(fBeginDateUst, fDelayedUsecs);
+ goto retry; /* recoverable error*/
+ }
+
+ if (nframes != fEngineControl->fBufferSize)
+ jack_log("JackIoAudioDriver::Read warning fBufferSize = %ld nframes = %ld", fEngineControl->fBufferSize, nframes);
+
+ // Has to be done before read
+ JackDriver::CycleIncTime();
+
+ return ioaudio_driver_read((ioaudio_driver_t *)fDriver, fEngineControl->fBufferSize);
+}
+
+int JackIoAudioDriver::Write()
+{
+ return ioaudio_driver_write((ioaudio_driver_t *)fDriver, fEngineControl->fBufferSize);
+}
+
+void JackIoAudioDriver::ReadInputAux(jack_nframes_t orig_nframes, ssize_t contiguous, ssize_t nread)
+{
+ for (int chn = 0; chn < fCaptureChannels; chn++) {
+ if (fGraphManager->GetConnectionsNum(fCapturePortList[chn]) > 0) {
+ jack_default_audio_sample_t* buf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fCapturePortList[chn], orig_nframes);
+ ioaudio_driver_read_from_channel((ioaudio_driver_t *)fDriver, chn, buf + nread, contiguous);
+ }
+ }
+}
+
+void JackIoAudioDriver::MonitorInputAux()
+{
+ for (int chn = 0; chn < fCaptureChannels; chn++) {
+ JackPort* port = fGraphManager->GetPort(fCapturePortList[chn]);
+ if (port->MonitoringInput()) {
+ ((ioaudio_driver_t *)fDriver)->input_monitor_mask |= (1 << chn);
+ }
+ }
+}
+
+void JackIoAudioDriver::ClearOutputAux()
+{
+ for (int chn = 0; chn < fPlaybackChannels; chn++) {
+ jack_default_audio_sample_t* buf =
+ (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fPlaybackPortList[chn], fEngineControl->fBufferSize);
+ memset(buf, 0, sizeof (jack_default_audio_sample_t) * fEngineControl->fBufferSize);
+ }
+}
+
+void JackIoAudioDriver::SetTimetAux(jack_time_t time)
+{
+ fBeginDateUst = time;
+}
+
+void JackIoAudioDriver::WriteOutputAux(jack_nframes_t orig_nframes, ssize_t contiguous, ssize_t nwritten)
+{
+ for (int chn = 0; chn < fPlaybackChannels; chn++) {
+ // Output ports
+ if (fGraphManager->GetConnectionsNum(fPlaybackPortList[chn]) > 0) {
+ jack_default_audio_sample_t* buf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fPlaybackPortList[chn], orig_nframes);
+ ioaudio_driver_write_to_channel(((ioaudio_driver_t *)fDriver), chn, buf + nwritten, contiguous);
+ // Monitor ports
+ if (fWithMonitorPorts && fGraphManager->GetConnectionsNum(fMonitorPortList[chn]) > 0) {
+ jack_default_audio_sample_t* monbuf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fMonitorPortList[chn], orig_nframes);
+ memcpy(monbuf + nwritten, buf + nwritten, contiguous * sizeof(jack_default_audio_sample_t));
+ }
+ }
+ }
+}
+
+int JackIoAudioDriver::is_realtime() const
+{
+ return fEngineControl->fRealTime;
+}
+
+int JackIoAudioDriver::create_thread(pthread_t *thread, int priority, int realtime, void *(*start_routine)(void*), void *arg)
+{
+#ifdef __ANDROID__
+ return JackAndroidThread::StartImp(thread, priority, realtime, start_routine, arg);
+#else
+ return JackPosixThread::StartImp(thread, priority, realtime, start_routine, arg);
+#endif
+}
+
+jack_port_id_t JackIoAudioDriver::port_register(const char *port_name, const char *port_type, unsigned long flags, unsigned long buffer_size)
+{
+ jack_port_id_t port_index;
+ int res = fEngine->PortRegister(fClientControl.fRefNum, port_name, port_type, flags, buffer_size, &port_index);
+ return (res == 0) ? port_index : 0;
+}
+
+int JackIoAudioDriver::port_unregister(jack_port_id_t port_index)
+{
+ return fEngine->PortUnRegister(fClientControl.fRefNum, port_index);
+}
+
+void* JackIoAudioDriver::port_get_buffer(int port, jack_nframes_t nframes)
+{
+ return fGraphManager->GetBuffer(port, nframes);
+}
+
+int JackIoAudioDriver::port_set_alias(int port, const char* name)
+{
+ return fGraphManager->GetPort(port)->SetAlias(name);
+}
+
+jack_nframes_t JackIoAudioDriver::get_sample_rate() const
+{
+ return fEngineControl->fSampleRate;
+}
+
+jack_nframes_t JackIoAudioDriver::frame_time() const
+{
+ JackTimer timer;
+ fEngineControl->ReadFrameTime(&timer);
+ return timer.Time2Frames(GetMicroSeconds(), fEngineControl->fBufferSize);
+}
+
+jack_nframes_t JackIoAudioDriver::last_frame_time() const
+{
+ JackTimer timer;
+ fEngineControl->ReadFrameTime(&timer);
+ return timer.CurFrame();
+}
+
+} // end of namespace
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+static
+jack_driver_param_constraint_desc_t *
+enum_ioaudio_devices()
+{
+ snd_ctl_t * handle;
+ snd_ctl_hw_info_t info;
+ snd_pcm_info_t pcminfo_capture;
+ snd_pcm_info_t pcminfo_playback;
+ int card_no = -1;
+ jack_driver_param_value_t card_id;
+ jack_driver_param_value_t device_id;
+ char description[64];
+ int device_no;
+ bool has_capture;
+ bool has_playback;
+ jack_driver_param_constraint_desc_t * constraint_ptr;
+ uint32_t array_size = 0;
+
+ constraint_ptr = NULL;
+
+
+ int numcards = snd_cards_list( NULL, 0, NULL );
+ int* cards = malloc( numcards * sizeof(int) );
+ numcards = snd_cards_list( cards, numcards, NULL );
+
+ for( int c = 0; c < numcards; ++c )
+ {
+ card_no = cards[c];
+ snprintf(card_id.str, sizeof(card_id.str), "hw:%d", card_no);
+
+ if (snd_ctl_open(&handle, card_no) >= 0 &&
+ snd_ctl_hw_info(handle, &info) >= 0)
+ {
+ snprintf(card_id.str, sizeof(card_id.str), "hw:%s", snd_ctl_card_info_get_id(info));
+ if (!jack_constraint_add_enum(
+ &constraint_ptr,
+ &array_size,
+ &card_id,
+ snd_ctl_card_info_get_name(info)))
+ goto fail;
+
+ device_no = -1;
+
+ for( device_no = 0; device_no < info.pcmdevs; ++device_no )
+ {
+ snprintf(device_id.str, sizeof(device_id.str), "%s,%d", card_id.str, device_no);
+
+ snd_pcm_info_set_device(pcminfo_capture, device_no);
+ snd_pcm_info_set_subdevice(pcminfo_capture, 0);
+ snd_pcm_info_set_stream(pcminfo_capture, SND_PCM_CHANNEL_CAPTURE);
+ has_capture = snd_ctl_pcm_info(handle, pcminfo_capture) >= 0;
+
+ snd_pcm_info_set_device(pcminfo_playback, device_no);
+ snd_pcm_info_set_subdevice(pcminfo_playback, 0);
+ snd_pcm_info_set_stream(pcminfo_playback, SND_PCM_CHANNEL_PLAYBACK);
+ has_playback = snd_ctl_pcm_info(handle, pcminfo_playback) >= 0;
+
+ if (has_capture && has_playback)
+ {
+ snprintf(description, sizeof(description),"%s (duplex)", snd_pcm_info_get_name(pcminfo_capture));
+ }
+ else if (has_capture)
+ {
+ snprintf(description, sizeof(description),"%s (capture)", snd_pcm_info_get_name(pcminfo_capture));
+ }
+ else if (has_playback)
+ {
+ snprintf(description, sizeof(description),"%s (playback)", snd_pcm_info_get_name(pcminfo_playback));
+ }
+ else
+ {
+ continue;
+ }
+
+ if (!jack_constraint_add_enum(
+ &constraint_ptr,
+ &array_size,
+ &device_id,
+ description))
+ goto fail;
+ }
+
+ snd_ctl_close(handle);
+ }
+ }
+
+ return constraint_ptr;
+fail:
+ jack_constraint_free(constraint_ptr);
+ return NULL;
+}
+
+static int
+dither_opt (char c, DitherAlgorithm* dither)
+{
+ switch (c) {
+ case '-':
+ case 'n':
+ *dither = None;
+ break;
+
+ case 'r':
+ *dither = Rectangular;
+ break;
+
+ case 's':
+ *dither = Shaped;
+ break;
+
+ case 't':
+ *dither = Triangular;
+ break;
+
+ default:
+ fprintf (stderr, "IoAudio driver: illegal dithering mode %c\n", c);
+ return -1;
+ }
+ return 0;
+}
+
+SERVER_EXPORT const jack_driver_desc_t* driver_get_descriptor ()
+{
+ jack_driver_desc_t * desc;
+ jack_driver_desc_filler_t filler;
+ jack_driver_param_value_t value;
+
+ desc = jack_driver_descriptor_construct("alsa", JackDriverMaster, "QNX IoAudio API based audio backend", &filler);
+
+ strcpy(value.str, "pcmPreferredp");
+#ifdef __ANDROID__
+ jack_driver_descriptor_add_parameter(desc, &filler, "device", 'd', JackDriverParamString, &value, NULL, "IoAudio device name", NULL);
+#else
+ jack_driver_descriptor_add_parameter(desc, &filler, "device", 'd', JackDriverParamString, &value, enum_ioaudio_devices(), "IoAudio device name", NULL);
+#endif
+
+ strcpy(value.str, "none");
+ jack_driver_descriptor_add_parameter(desc, &filler, "capture", 'C', JackDriverParamString, &value, NULL, "Provide capture ports. Optionally set device", NULL);
+ jack_driver_descriptor_add_parameter(desc, &filler, "playback", 'P', JackDriverParamString, &value, NULL, "Provide playback ports. Optionally set device", NULL);
+
+ value.ui = 48000U;
+ jack_driver_descriptor_add_parameter(desc, &filler, "rate", 'r', JackDriverParamUInt, &value, NULL, "Sample rate", NULL);
+
+ value.ui = 1024U;
+ jack_driver_descriptor_add_parameter(desc, &filler, "period", 'p', JackDriverParamUInt, &value, NULL, "Frames per period", NULL);
+
+ value.ui = 2U;
+ jack_driver_descriptor_add_parameter(desc, &filler, "nperiods", 'n', JackDriverParamUInt, &value, NULL, "Number of periods of playback latency", NULL);
+
+ value.i = 0;
+ jack_driver_descriptor_add_parameter(desc, &filler, "hwmon", 'H', JackDriverParamBool, &value, NULL, "Hardware monitoring, if available", NULL);
+
+ value.i = 0;
+ jack_driver_descriptor_add_parameter(desc, &filler, "hwmeter", 'M', JackDriverParamBool, &value, NULL, "Hardware metering, if available", NULL);
+
+ value.i = 1;
+ jack_driver_descriptor_add_parameter(desc, &filler, "duplex", 'D', JackDriverParamBool, &value, NULL, "Provide both capture and playback ports", NULL);
+
+ value.i = 0;
+ jack_driver_descriptor_add_parameter(desc, &filler, "softmode", 's', JackDriverParamBool, &value, NULL, "Soft-mode, no xrun handling", NULL);
+
+ value.i = 0;
+ jack_driver_descriptor_add_parameter(desc, &filler, "monitor", 'm', JackDriverParamBool, &value, NULL, "Provide monitor ports for the output", NULL);
+
+ value.c = 'n';
+ jack_driver_descriptor_add_parameter(
+ desc,
+ &filler,
+ "dither",
+ 'z',
+ JackDriverParamChar,
+ &value,
+ jack_constraint_compose_enum_char(
+ JACK_CONSTRAINT_FLAG_STRICT | JACK_CONSTRAINT_FLAG_FAKE_VALUE,
+ dither_constraint_descr_array),
+ "Dithering mode",
+ NULL);
+
+ value.ui = 0;
+ jack_driver_descriptor_add_parameter(desc, &filler, "inchannels", 'i', JackDriverParamUInt, &value, NULL, "Number of capture channels (defaults to hardware max)", NULL);
+ jack_driver_descriptor_add_parameter(desc, &filler, "outchannels", 'o', JackDriverParamUInt, &value, NULL, "Number of playback channels (defaults to hardware max)", NULL);
+
+ value.i = FALSE;
+ jack_driver_descriptor_add_parameter(desc, &filler, "shorts", 'S', JackDriverParamBool, &value, NULL, "Try 16-bit samples before 32-bit", NULL);
+
+ value.ui = 0;
+ jack_driver_descriptor_add_parameter(desc, &filler, "input-latency", 'I', JackDriverParamUInt, &value, NULL, "Extra input latency (frames)", NULL);
+ jack_driver_descriptor_add_parameter(desc, &filler, "output-latency", 'O', JackDriverParamUInt, &value, NULL, "Extra output latency (frames)", NULL);
+
+ strcpy(value.str, "none");
+ jack_driver_descriptor_add_parameter(
+ desc,
+ &filler,
+ "midi-driver",
+ 'X',
+ JackDriverParamString,
+ &value,
+ jack_constraint_compose_enum_str(
+ JACK_CONSTRAINT_FLAG_STRICT | JACK_CONSTRAINT_FLAG_FAKE_VALUE,
+ midi_constraint_descr_array),
+ "IoAudio MIDI driver",
+ NULL);
+
+ return desc;
+}
+
+static Jack::JackIoAudioDriver* g_ioaudio_driver;
+
+SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
+{
+ jack_nframes_t srate = 48000;
+ jack_nframes_t frames_per_interrupt = 1024;
+ unsigned long user_nperiods = 2;
+ const char *playback_pcm_name = "pcmPreferredp";
+ const char *capture_pcm_name = "pcmPreferredc";
+ int hw_monitoring = FALSE;
+ int hw_metering = FALSE;
+ int capture = FALSE;
+ int playback = FALSE;
+ int soft_mode = FALSE;
+ int monitor = FALSE;
+ DitherAlgorithm dither = None;
+ int user_capture_nchnls = 0;
+ int user_playback_nchnls = 0;
+ int shorts_first = FALSE;
+ jack_nframes_t systemic_input_latency = 0;
+ jack_nframes_t systemic_output_latency = 0;
+ const JSList * node;
+ const jack_driver_param_t * param;
+ const char *midi_driver = "none";
+
+ for (node = params; node; node = jack_slist_next (node)) {
+ param = (const jack_driver_param_t *) node->data;
+
+ switch (param->character) {
+
+ case 'C':
+ capture = TRUE;
+ if (strcmp (param->value.str, "none") != 0) {
+ capture_pcm_name = strdup (param->value.str);
+ jack_log("capture device %s", capture_pcm_name);
+ }
+ break;
+
+ case 'P':
+ playback = TRUE;
+ if (strcmp (param->value.str, "none") != 0) {
+ playback_pcm_name = strdup (param->value.str);
+ jack_log("playback device %s", playback_pcm_name);
+ }
+ break;
+
+ case 'D':
+ playback = TRUE;
+ capture = TRUE;
+ break;
+
+ case 'd':
+ if (strcmp (param->value.str, "none") != 0) {
+ playback_pcm_name = strdup (param->value.str);
+ capture_pcm_name = strdup (param->value.str);
+ jack_log("playback device %s", playback_pcm_name);
+ jack_log("capture device %s", capture_pcm_name);
+ }
+ break;
+
+ case 'H':
+ hw_monitoring = param->value.i;
+ break;
+
+ case 'm':
+ monitor = param->value.i;
+ break;
+
+ case 'M':
+ hw_metering = param->value.i;
+ break;
+
+ case 'r':
+ srate = param->value.ui;
+ jack_log("apparent rate = %d", srate);
+ break;
+
+ case 'p':
+ frames_per_interrupt = param->value.ui;
+ jack_log("frames per period = %d", frames_per_interrupt);
+ break;
+
+ case 'n':
+ user_nperiods = param->value.ui;
+ if (user_nperiods < 2) { /* enforce minimum value */
+ user_nperiods = 2;
+ }
+ break;
+
+ case 's':
+ soft_mode = param->value.i;
+ break;
+
+ case 'z':
+ if (dither_opt (param->value.c, &dither)) {
+ return NULL;
+ }
+ break;
+
+ case 'i':
+ user_capture_nchnls = param->value.ui;
+ break;
+
+ case 'o':
+ user_playback_nchnls = param->value.ui;
+ break;
+
+ case 'S':
+ shorts_first = param->value.i;
+ break;
+
+ case 'I':
+ systemic_input_latency = param->value.ui;
+ break;
+
+ case 'O':
+ systemic_output_latency = param->value.ui;
+ break;
+
+ case 'X':
+ midi_driver = strdup(param->value.str);
+ break;
+ }
+ }
+
+ /* duplex is the default */
+ if (!capture && !playback) {
+ capture = TRUE;
+ playback = TRUE;
+ }
+
+ g_ioaudio_driver = new Jack::JackIoAudioDriver("system", "ioaudio_pcm", engine, table);
+ Jack::JackDriverClientInterface* threaded_driver = new Jack::JackThreadedDriver(g_ioaudio_driver);
+ // Special open for IoAudio driver...
+ if (g_ioaudio_driver->Open(frames_per_interrupt, user_nperiods, srate, hw_monitoring, hw_metering, capture, playback, dither, soft_mode, monitor,
+ user_capture_nchnls, user_playback_nchnls, shorts_first, capture_pcm_name, playback_pcm_name,
+ systemic_input_latency, systemic_output_latency, midi_driver ) == 0) {
+ return threaded_driver;
+ } else {
+ delete threaded_driver; // Delete the decorated driver
+ return NULL;
+ }
+}
+
+// Code to be used in ioaudio_driver.c
+
+void ReadInput(jack_nframes_t orig_nframes, ssize_t contiguous, ssize_t nread)
+{
+ g_ioaudio_driver->ReadInputAux(orig_nframes, contiguous, nread);
+}
+void MonitorInput()
+{
+ g_ioaudio_driver->MonitorInputAux();
+}
+void ClearOutput()
+{
+ g_ioaudio_driver->ClearOutputAux();
+}
+void WriteOutput(jack_nframes_t orig_nframes, ssize_t contiguous, ssize_t nwritten)
+{
+ g_ioaudio_driver->WriteOutputAux(orig_nframes, contiguous, nwritten);
+}
+void SetTime(jack_time_t time)
+{
+ g_ioaudio_driver->SetTimetAux(time);
+}
+
+int Restart()
+{
+ int res;
+ if ((res = g_ioaudio_driver->Stop()) == 0) {
+ res = g_ioaudio_driver->Start();
+ }
+ return res;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+
diff --git a/qnx/ioaudio/JackIoAudioDriver.h b/qnx/ioaudio/JackIoAudioDriver.h
new file mode 100644
index 00000000..d43a8446
--- /dev/null
+++ b/qnx/ioaudio/JackIoAudioDriver.h
@@ -0,0 +1,112 @@
+/*
+Copyright (C) 2001 Paul Davis
+Copyright (C) 2004 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 __JackIoAudioDriver__
+#define __JackIoAudioDriver__
+
+#include "JackAudioDriver.h"
+#include "JackThreadedDriver.h"
+#include "JackTime.h"
+#include "ioaudio_backend.h"
+
+namespace Jack
+{
+
+/*!
+\brief The IoAudio driver.
+*/
+
+class JackIoAudioDriver : public JackAudioDriver
+{
+
+ private:
+
+ jack_driver_t* fDriver;
+
+ void UpdateLatencies();
+
+ public:
+
+ JackIoAudioDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table)
+ : JackAudioDriver(name, alias, engine, table),fDriver(NULL)
+ {}
+ virtual ~JackIoAudioDriver()
+ {}
+
+ int Open(jack_nframes_t buffer_size,
+ jack_nframes_t user_nperiods,
+ jack_nframes_t samplerate,
+ bool hw_monitoring,
+ bool hw_metering,
+ bool capturing,
+ bool playing,
+ DitherAlgorithm dither,
+ bool soft_mode,
+ bool monitor,
+ int inchannels,
+ int outchannels,
+ bool shorts_first,
+ const char* capture_driver_name,
+ const char* playback_driver_name,
+ jack_nframes_t capture_latency,
+ jack_nframes_t playback_latency,
+ const char* midi_driver_name);
+
+ int Close();
+ int Attach();
+ int Detach();
+
+ int Start();
+ int Stop();
+
+ int Read();
+ int Write();
+
+ // BufferSize can be changed
+ bool IsFixedBufferSize()
+ {
+ return false;
+ }
+
+ int SetBufferSize(jack_nframes_t buffer_size);
+
+ void ReadInputAux(jack_nframes_t orig_nframes, ssize_t contiguous, ssize_t nread);
+ void MonitorInputAux();
+ void ClearOutputAux();
+ void WriteOutputAux(jack_nframes_t orig_nframes, ssize_t contiguous, ssize_t nwritten);
+ void SetTimetAux(jack_time_t time);
+
+ // JACK API emulation for the midi driver
+ int is_realtime() const;
+ int create_thread(pthread_t *thread, int prio, int rt, void *(*start_func)(void*), void *arg);
+
+ jack_port_id_t port_register(const char *port_name, const char *port_type, unsigned long flags, unsigned long buffer_size);
+ int port_unregister(jack_port_id_t port_index);
+ void* port_get_buffer(int port, jack_nframes_t nframes);
+ int port_set_alias(int port, const char* name);
+
+ jack_nframes_t get_sample_rate() const;
+ jack_nframes_t frame_time() const;
+ jack_nframes_t last_frame_time() const;
+};
+
+} // end of namespace
+
+#endif
diff --git a/qnx/ioaudio/bitset.h b/qnx/ioaudio/bitset.h
new file mode 100644
index 00000000..048b5fb2
--- /dev/null
+++ b/qnx/ioaudio/bitset.h
@@ -0,0 +1,132 @@
+/*
+* bitset.h -- some simple bit vector set operations.
+*
+* This is useful for sets of small non-negative integers. There are
+* some obvious set operations that are not implemented because I
+* don't need them right now.
+*
+* These functions represent sets as arrays of unsigned 32-bit
+* integers allocated on the heap. The first entry contains the set
+* cardinality (number of elements allowed), followed by one or more
+* words containing bit vectors.
+*
+* $Id: bitset.h,v 1.2 2005/11/23 11:24:29 letz Exp $
+*/
+
+/*
+ * Copyright (C) 2005 Jack O'Quin
+ *
+ * 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 __bitset_h__
+#define __bitset_h__
+
+#include /* POSIX standard fixed-size types */
+#include /* `#define NDEBUG' to disable */
+
+/* On some 64-bit machines, this implementation may be slightly
+ * inefficient, depending on how compilers allocate space for
+ * uint32_t. For the set sizes I currently need, this is acceptable.
+ * It should not be hard to pack the bits better, if that becomes
+ * worthwhile.
+ */
+typedef uint32_t _bitset_word_t;
+typedef _bitset_word_t *bitset_t;
+
+#define WORD_SIZE(cardinality) (1+((cardinality)+31)/32)
+#define BYTE_SIZE(cardinality) (WORD_SIZE(cardinality)*sizeof(_bitset_word_t))
+#define WORD_INDEX(element) (1+(element)/32)
+#define BIT_INDEX(element) ((element)&037)
+
+static inline void
+bitset_add(bitset_t set
+ , unsigned int element)
+{
+ assert(element < set
+ [0]);
+ set
+ [WORD_INDEX(element)] |= (1 << BIT_INDEX(element));
+}
+
+static inline void
+bitset_copy(bitset_t to_set, bitset_t from_set)
+{
+ assert(to_set[0] == from_set[0]);
+ memcpy(to_set, from_set, BYTE_SIZE(to_set[0]));
+}
+
+static inline void
+bitset_create(bitset_t *set
+ , unsigned int cardinality)
+{
+ *set
+ = (bitset_t) calloc(WORD_SIZE(cardinality),
+ sizeof(_bitset_word_t));
+ assert(*set
+ );
+ *set
+ [0] = cardinality;
+}
+
+static inline void
+bitset_destroy(bitset_t *set
+ )
+{
+ if (*set
+ ) {
+ free(*set
+ );
+ *set
+ = (bitset_t) 0;
+ }
+}
+
+static inline int
+bitset_empty(bitset_t set
+ )
+{
+ int i;
+ _bitset_word_t result = 0;
+ int nwords = WORD_SIZE(set
+ [0]);
+ for (i = 1; i < nwords; i++) {
+ result |= set
+ [i];
+ }
+ return (result == 0);
+}
+
+static inline int
+bitset_contains(bitset_t set
+ , unsigned int element)
+{
+ assert(element < set
+ [0]);
+ return (0 != (set
+ [WORD_INDEX(element)] & (1 << BIT_INDEX(element))));
+}
+
+static inline void
+bitset_remove(bitset_t set
+ , unsigned int element)
+{
+ assert(element < set
+ [0]);
+ set
+ [WORD_INDEX(element)] &= ~(1 << BIT_INDEX(element));
+}
+
+#endif /* __bitset_h__ */
diff --git a/qnx/ioaudio/ioaudio_backend.c b/qnx/ioaudio/ioaudio_backend.c
new file mode 100644
index 00000000..f974e48f
--- /dev/null
+++ b/qnx/ioaudio/ioaudio_backend.c
@@ -0,0 +1,2308 @@
+/* -*- mode: c; c-file-style: "linux"; -*- */
+/*
+ Copyright (C) 2001 Paul Davis
+
+ 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.
+
+*/
+
+
+#define __STDC_FORMAT_MACROS // For inttypes.h to work in C++
+#define _GNU_SOURCE /* for strcasestr() from string.h */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "ioaudio_backend.h"
+//#include "hammerfall.h"
+//#include "hdsp.h"
+//#include "ice1712.h"
+//#include "usx2y.h"
+//#include "generic.h"
+#include "memops.h"
+#include "JackError.h"
+
+//#include "ioaudio_midi_impl.h"
+
+extern void store_work_time (int);
+extern void store_wait_time (int);
+extern void show_wait_times ();
+extern void show_work_times ();
+
+#undef DEBUG_WAKEUP
+
+char* strcasestr(const char* haystack, const char* needle);
+
+/* Delay (in process calls) before jackd will report an xrun */
+#define XRUN_REPORT_DELAY 0
+
+void
+jack_driver_init (jack_driver_t *driver)
+{
+ memset (driver, 0, sizeof (*driver));
+
+ driver->attach = 0;
+ driver->detach = 0;
+ driver->write = 0;
+ driver->read = 0;
+ driver->null_cycle = 0;
+ driver->bufsize = 0;
+ driver->start = 0;
+ driver->stop = 0;
+}
+
+void
+jack_driver_nt_init (jack_driver_nt_t * driver)
+{
+ memset (driver, 0, sizeof (*driver));
+
+ jack_driver_init ((jack_driver_t *) driver);
+
+ driver->attach = 0;
+ driver->detach = 0;
+ driver->bufsize = 0;
+ driver->stop = 0;
+ driver->start = 0;
+
+ driver->nt_bufsize = 0;
+ driver->nt_start = 0;
+ driver->nt_stop = 0;
+ driver->nt_attach = 0;
+ driver->nt_detach = 0;
+ driver->nt_run_cycle = 0;
+}
+
+static void
+ioaudio_driver_release_channel_dependent_memory (ioaudio_driver_t *driver)
+{
+ bitset_destroy (&driver->channels_done);
+ bitset_destroy (&driver->channels_not_done);
+
+ if (driver->playback_addr) {
+ free (driver->playback_addr);
+ driver->playback_addr = 0;
+ }
+
+ if (driver->capture_addr) {
+ free (driver->capture_addr);
+ driver->capture_addr = 0;
+ }
+
+ if (driver->playback_interleave_skip) {
+ free (driver->playback_interleave_skip);
+ driver->playback_interleave_skip = NULL;
+ }
+
+ if (driver->capture_interleave_skip) {
+ free (driver->capture_interleave_skip);
+ driver->capture_interleave_skip = NULL;
+ }
+
+ if (driver->silent) {
+ free (driver->silent);
+ driver->silent = 0;
+ }
+
+ if (driver->dither_state) {
+ free (driver->dither_state);
+ driver->dither_state = 0;
+ }
+}
+
+static int
+ioaudio_driver_check_capabilities (ioaudio_driver_t *driver)
+{
+ return 0;
+}
+
+char* get_control_device_name(const char * device_name);
+
+static int
+ioaudio_driver_check_card_type (ioaudio_driver_t *driver)
+{
+ int err;
+ snd_ctl_hw_info_t card_info;
+ char * ctl_name;
+
+ ctl_name = get_control_device_name(driver->ioaudio_name_playback);
+
+ // XXX: I don't know the "right" way to do this. Which to use
+ // driver->ioaudio_name_playback or driver->ioaudio_name_capture.
+ if ((err = snd_ctl_open (&driver->ctl_handle, ctl_name, 0)) < 0) {
+ jack_error ("control open \"%s\" (%s)", ctl_name,
+ snd_strerror(err));
+ } else if ((err = snd_ctl_hw_info(driver->ctl_handle, &card_info)) < 0) {
+ jack_error ("control hardware info \"%s\" (%s)",
+ driver->ioaudio_name_playback, snd_strerror (err));
+ snd_ctl_close (driver->ctl_handle);
+ }
+
+ driver->ioaudio_driver = strdup(card_info.longname);
+
+ free(ctl_name);
+
+ return ioaudio_driver_check_capabilities (driver);
+}
+
+//static int
+//ioaudio_driver_hammerfall_hardware (ioaudio_driver_t *driver)
+//{
+// driver->hw = jack_ioaudio_hammerfall_hw_new (driver);
+// return 0;
+//}
+//
+//static int
+//ioaudio_driver_hdsp_hardware (ioaudio_driver_t *driver)
+//{
+// driver->hw = jack_ioaudio_hdsp_hw_new (driver);
+// return 0;
+//}
+//
+//static int
+//ioaudio_driver_ice1712_hardware (ioaudio_driver_t *driver)
+//{
+// driver->hw = jack_ioaudio_ice1712_hw_new (driver);
+// return 0;
+//}
+
+// JACK2
+/*
+static int
+ioaudio_driver_usx2y_hardware (ioaudio_driver_t *driver)
+{
+ driver->hw = jack_ioaudio_usx2y_hw_new (driver);
+ return 0;
+}
+*/
+
+//static int
+//ioaudio_driver_generic_hardware (ioaudio_driver_t *driver)
+//{
+// driver->hw = jack_ioaudio_generic_hw_new (driver);
+// return 0;
+//}
+
+static int
+ioaudio_driver_hw_specific (ioaudio_driver_t *driver, int hw_monitoring,
+ int hw_metering)
+{
+ int err;
+
+ if (!strcmp(driver->ioaudio_driver, "RME9652")) {
+ if ((err = ioaudio_driver_hammerfall_hardware (driver)) != 0) {
+ return err;
+ }
+ } else if (!strcmp(driver->ioaudio_driver, "H-DSP")) {
+ if ((err = ioaudio_driver_hdsp_hardware (driver)) !=0) {
+ return err;
+ }
+ } else if (!strcmp(driver->ioaudio_driver, "ICE1712")) {
+ if ((err = ioaudio_driver_ice1712_hardware (driver)) !=0) {
+ return err;
+ }
+ }
+ // JACK2
+ /*
+ else if (!strcmp(driver->ioaudio_driver, "USB US-X2Y")) {
+ if ((err = ioaudio_driver_usx2y_hardware (driver)) !=0) {
+ return err;
+ }
+ }
+ */
+ else {
+ if ((err = ioaudio_driver_generic_hardware (driver)) != 0) {
+ return err;
+ }
+ }
+
+ if (driver->hw->capabilities & Cap_HardwareMonitoring) {
+ driver->has_hw_monitoring = TRUE;
+ /* XXX need to ensure that this is really FALSE or
+ * TRUE or whatever*/
+ driver->hw_monitoring = hw_monitoring;
+ } else {
+ driver->has_hw_monitoring = FALSE;
+ driver->hw_monitoring = FALSE;
+ }
+
+ if (driver->hw->capabilities & Cap_ClockLockReporting) {
+ driver->has_clock_sync_reporting = TRUE;
+ } else {
+ driver->has_clock_sync_reporting = FALSE;
+ }
+
+ if (driver->hw->capabilities & Cap_HardwareMetering) {
+ driver->has_hw_metering = TRUE;
+ driver->hw_metering = hw_metering;
+ } else {
+ driver->has_hw_metering = FALSE;
+ driver->hw_metering = FALSE;
+ }
+
+ return 0;
+}
+
+static void
+ioaudio_driver_setup_io_function_pointers (ioaudio_driver_t *driver)
+{
+ if (driver->playback_handle) {
+ if (SND_PCM_FORMAT_FLOAT_LE == driver->playback_sample_format) {
+ driver->write_via_copy = sample_move_dS_floatLE;
+ } else {
+ switch (driver->playback_sample_bytes) {
+ case 2:
+ switch (driver->dither) {
+ case Rectangular:
+ jack_info("Rectangular dithering at 16 bits");
+ driver->write_via_copy = driver->quirk_bswap?
+ sample_move_dither_rect_d16_sSs:
+ sample_move_dither_rect_d16_sS;
+ break;
+
+ case Triangular:
+ jack_info("Triangular dithering at 16 bits");
+ driver->write_via_copy = driver->quirk_bswap?
+ sample_move_dither_tri_d16_sSs:
+ sample_move_dither_tri_d16_sS;
+ break;
+
+ case Shaped:
+ jack_info("Noise-shaped dithering at 16 bits");
+ driver->write_via_copy = driver->quirk_bswap?
+ sample_move_dither_shaped_d16_sSs:
+ sample_move_dither_shaped_d16_sS;
+ break;
+
+ default:
+ driver->write_via_copy = driver->quirk_bswap?
+ sample_move_d16_sSs :
+ sample_move_d16_sS;
+ break;
+ }
+ break;
+
+ case 3: /* NO DITHER */
+ driver->write_via_copy = driver->quirk_bswap?
+ sample_move_d24_sSs:
+ sample_move_d24_sS;
+
+ break;
+
+ case 4: /* NO DITHER */
+ driver->write_via_copy = driver->quirk_bswap?
+ sample_move_d32u24_sSs:
+ sample_move_d32u24_sS;
+ break;
+
+ default:
+ jack_error ("impossible sample width (%d) discovered!",
+ driver->playback_sample_bytes);
+ exit (1);
+ }
+ }
+ }
+
+ if (driver->capture_handle) {
+ if (SND_PCM_FORMAT_FLOAT_LE == driver->capture_sample_format) {
+ driver->read_via_copy = sample_move_floatLE_sSs;
+ } else {
+ switch (driver->capture_sample_bytes) {
+ case 2:
+ driver->read_via_copy = driver->quirk_bswap?
+ sample_move_dS_s16s:
+ sample_move_dS_s16;
+ break;
+ case 3:
+ driver->read_via_copy = driver->quirk_bswap?
+ sample_move_dS_s24s:
+ sample_move_dS_s24;
+ break;
+ case 4:
+ driver->read_via_copy = driver->quirk_bswap?
+ sample_move_dS_s32u24s:
+ sample_move_dS_s32u24;
+ break;
+ }
+ }
+ }
+}
+
+static int
+ioaudio_driver_configure_stream (ioaudio_driver_t *driver, char *device_name,
+ const char *stream_name,
+ snd_pcm_t *handle,
+ snd_pcm_channel_params_t *hw_params,
+ snd_pcm_channel_params_t *sw_params,
+ unsigned int *nperiodsp,
+ channel_t *nchns,
+ unsigned long sample_width)
+{
+ int err, format;
+ unsigned int frame_rate;
+ size_t stop_th;
+ static struct {
+ char Name[40];
+ snd_pcm_format_t format;
+ int swapped;
+ } formats[] = {
+ {"32bit float little-endian", SND_PCM_FORMAT_FLOAT_LE, IS_LE},
+ {"32bit integer little-endian", SND_PCM_FORMAT_S32_LE, IS_LE},
+ {"32bit integer big-endian", SND_PCM_FORMAT_S32_BE, IS_BE},
+ {"24bit little-endian in 3bytes format", SND_PCM_FORMAT_S24_3LE, IS_LE},
+ {"24bit big-endian in 3bytes format", SND_PCM_FORMAT_S24_3BE, IS_BE},
+ {"24bit little-endian", SND_PCM_FORMAT_S24_LE, IS_LE},
+ {"24bit big-endian", SND_PCM_FORMAT_S24_BE, IS_BE},
+ {"16bit little-endian", SND_PCM_FORMAT_S16_LE, IS_LE},
+ {"16bit big-endian", SND_PCM_FORMAT_S16_BE, IS_BE},
+ };
+#define NUMFORMATS (sizeof(formats)/sizeof(formats[0]))
+#define FIRST_16BIT_FORMAT 5
+
+ if ((err = snd_pcm_hw_params_any (handle, hw_params)) < 0) {
+ jack_error ("ALSA: no playback configurations available (%s)",
+ snd_strerror (err));
+ return -1;
+ }
+
+ if ((err = snd_pcm_hw_params_set_periods_integer (handle, hw_params))
+ < 0) {
+ jack_error ("ALSA: cannot restrict period size to integral"
+ " value.");
+ return -1;
+ }
+
+ if ((err = snd_pcm_hw_params_set_access (handle, hw_params, SND_PCM_ACCESS_MMAP_NONINTERLEAVED)) < 0) {
+ if ((err = snd_pcm_hw_params_set_access (handle, hw_params, SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0) {
+ if ((err = snd_pcm_hw_params_set_access (
+ handle, hw_params,
+ SND_PCM_ACCESS_MMAP_COMPLEX)) < 0) {
+ jack_error ("ALSA: mmap-based access is not possible"
+ " for the %s "
+ "stream of this audio interface",
+ stream_name);
+ return -1;
+ }
+ }
+ }
+
+ format = (sample_width == 4) ? 0 : NUMFORMATS - 1;
+
+ while (1) {
+ if ((err = snd_pcm_hw_params_set_format (
+ handle, hw_params, formats[format].format)) < 0) {
+
+ if ((sample_width == 4
+ ? format++ >= NUMFORMATS - 1
+ : format-- <= 0)) {
+ jack_error ("Sorry. The audio interface \"%s\""
+ " doesn't support any of the"
+ " hardware sample formats that"
+ " JACK's alsa-driver can use.",
+ device_name);
+ return -1;
+ }
+ } else {
+ if (formats[format].swapped) {
+ driver->quirk_bswap = 1;
+ } else {
+ driver->quirk_bswap = 0;
+ }
+ jack_info ("ALSA: final selected sample format for %s: %s", stream_name, formats[format].Name);
+ break;
+ }
+ }
+
+ frame_rate = driver->frame_rate ;
+ err = snd_pcm_hw_params_set_rate_near (handle, hw_params,
+ &frame_rate, NULL) ;
+ driver->frame_rate = frame_rate ;
+ if (err < 0) {
+ jack_error ("ALSA: cannot set sample/frame rate to %"
+ PRIu32 " for %s", driver->frame_rate,
+ stream_name);
+ return -1;
+ }
+ if (!*nchns) {
+ /*if not user-specified, try to find the maximum
+ * number of channels */
+ unsigned int channels_max ;
+ err = snd_pcm_hw_params_get_channels_max (hw_params,
+ &channels_max);
+ *nchns = channels_max ;
+
+ if (*nchns > 1024) {
+
+ /* the hapless user is an unwitting victim of
+ the "default" ALSA PCM device, which can
+ support up to 16 million channels. since
+ they can't be bothered to set up a proper
+ default device, limit the number of
+ channels for them to a sane default.
+ */
+
+ jack_error (
+"You appear to be using the ALSA software \"plug\" layer, probably\n"
+"a result of using the \"default\" ALSA device. This is less\n"
+"efficient than it could be. Consider using a hardware device\n"
+"instead rather than using the plug layer. Usually the name of the\n"
+"hardware device that corresponds to the first sound card is hw:0\n"
+ );
+ *nchns = 2;
+ }
+ }
+
+ if ((err = snd_pcm_hw_params_set_channels (handle, hw_params,
+ *nchns)) < 0) {
+ jack_error ("ALSA: cannot set channel count to %u for %s",
+ *nchns, stream_name);
+ return -1;
+ }
+
+ if ((err = snd_pcm_hw_params_set_period_size (handle, hw_params,
+ driver->frames_per_cycle,
+ 0))
+ < 0) {
+ jack_error ("ALSA: cannot set period size to %" PRIu32
+ " frames for %s", driver->frames_per_cycle,
+ stream_name);
+ return -1;
+ }
+
+ *nperiodsp = driver->user_nperiods;
+ snd_pcm_hw_params_set_periods_min (handle, hw_params, nperiodsp, NULL);
+ if (*nperiodsp < driver->user_nperiods)
+ *nperiodsp = driver->user_nperiods;
+ if (snd_pcm_hw_params_set_periods_near (handle, hw_params,
+ nperiodsp, NULL) < 0) {
+ jack_error ("ALSA: cannot set number of periods to %u for %s",
+ *nperiodsp, stream_name);
+ return -1;
+ }
+
+ if (*nperiodsp < driver->user_nperiods) {
+ jack_error ("ALSA: got smaller periods %u than %u for %s",
+ *nperiodsp, (unsigned int) driver->user_nperiods,
+ stream_name);
+ return -1;
+ }
+ jack_info ("ALSA: use %d periods for %s", *nperiodsp, stream_name);
+#if 0
+ if (!jack_power_of_two(driver->frames_per_cycle)) {
+ jack_error("JACK: frames must be a power of two "
+ "(64, 512, 1024, ...)\n");
+ return -1;
+ }
+#endif
+
+ if ((err = snd_pcm_hw_params_set_buffer_size (handle, hw_params,
+ *nperiodsp *
+ driver->frames_per_cycle))
+ < 0) {
+ jack_error ("ALSA: cannot set buffer length to %" PRIu32
+ " for %s",
+ *nperiodsp * driver->frames_per_cycle,
+ stream_name);
+ return -1;
+ }
+
+ if ((err = snd_pcm_hw_params (handle, hw_params)) < 0) {
+ jack_error ("ALSA: cannot set hardware parameters for %s",
+ stream_name);
+ return -1;
+ }
+
+ snd_pcm_sw_params_current (handle, sw_params);
+
+ if ((err = snd_pcm_sw_params_set_start_threshold (handle, sw_params,
+ 0U)) < 0) {
+ jack_error ("ALSA: cannot set start mode for %s", stream_name);
+ return -1;
+ }
+
+ stop_th = *nperiodsp * driver->frames_per_cycle;
+ if (driver->soft_mode) {
+ stop_th = (size_t)-1;
+ }
+
+ if ((err = snd_pcm_sw_params_set_stop_threshold (
+ handle, sw_params, stop_th)) < 0) {
+ jack_error ("ALSA: cannot set stop mode for %s",
+ stream_name);
+ return -1;
+ }
+
+ if ((err = snd_pcm_sw_params_set_silence_threshold (
+ handle, sw_params, 0)) < 0) {
+ jack_error ("ALSA: cannot set silence threshold for %s",
+ stream_name);
+ return -1;
+ }
+
+#if 0
+ jack_info ("set silence size to %lu * %lu = %lu",
+ driver->frames_per_cycle, *nperiodsp,
+ driver->frames_per_cycle * *nperiodsp);
+
+ if ((err = snd_pcm_sw_params_set_silence_size (
+ handle, sw_params,
+ driver->frames_per_cycle * *nperiodsp)) < 0) {
+ jack_error ("ALSA: cannot set silence size for %s",
+ stream_name);
+ return -1;
+ }
+#endif
+
+ if (handle == driver->playback_handle)
+ err = snd_pcm_sw_params_set_avail_min (
+ handle, sw_params,
+ driver->frames_per_cycle
+ * (*nperiodsp - driver->user_nperiods + 1));
+ else
+ err = snd_pcm_sw_params_set_avail_min (
+ handle, sw_params, driver->frames_per_cycle);
+
+ if (err < 0) {
+ jack_error ("ALSA: cannot set avail min for %s", stream_name);
+ return -1;
+ }
+
+ if ((err = snd_pcm_sw_params (handle, sw_params)) < 0) {
+ jack_error ("ALSA: cannot set software parameters for %s\n",
+ stream_name);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+ioaudio_driver_set_parameters (ioaudio_driver_t *driver,
+ jack_nframes_t frames_per_cycle,
+ jack_nframes_t user_nperiods,
+ jack_nframes_t rate)
+{
+ int dir;
+ size_t p_period_size = 0;
+ size_t c_period_size = 0;
+ channel_t chn;
+ unsigned int pr = 0;
+ unsigned int cr = 0;
+ int err;
+
+ driver->frame_rate = rate;
+ driver->frames_per_cycle = frames_per_cycle;
+ driver->user_nperiods = user_nperiods;
+
+ jack_info ("configuring for %" PRIu32 "Hz, period = %"
+ PRIu32 " frames (%.1f ms), buffer = %" PRIu32 " periods",
+ rate, frames_per_cycle, (((float)frames_per_cycle / (float) rate) * 1000.0f), user_nperiods);
+
+ if (driver->capture_handle) {
+ if (ioaudio_driver_configure_stream (
+ driver,
+ driver->ioaudio_name_capture,
+ "capture",
+ driver->capture_handle,
+ driver->capture_hw_params,
+ driver->capture_sw_params,
+ &driver->capture_nperiods,
+ &driver->capture_nchannels,
+ driver->capture_sample_bytes)) {
+ jack_error ("ALSA: cannot configure capture channel");
+ return -1;
+ }
+ }
+
+ if (driver->playback_handle) {
+ if (ioaudio_driver_configure_stream (
+ driver,
+ driver->ioaudio_name_playback,
+ "playback",
+ driver->playback_handle,
+ driver->playback_hw_params,
+ driver->playback_sw_params,
+ &driver->playback_nperiods,
+ &driver->playback_nchannels,
+ driver->playback_sample_bytes)) {
+ jack_error ("ALSA: cannot configure playback channel");
+ return -1;
+ }
+ }
+
+ /* check the rate, since thats rather important */
+
+ if (driver->playback_handle) {
+ snd_pcm_hw_params_get_rate (driver->playback_hw_params,
+ &pr, &dir);
+ }
+
+ if (driver->capture_handle) {
+ snd_pcm_hw_params_get_rate (driver->capture_hw_params,
+ &cr, &dir);
+ }
+
+ if (driver->capture_handle && driver->playback_handle) {
+ if (cr != pr) {
+ jack_error ("playback and capture sample rates do "
+ "not match (%d vs. %d)", pr, cr);
+ }
+
+ /* only change if *both* capture and playback rates
+ * don't match requested certain hardware actually
+ * still works properly in full-duplex with slightly
+ * different rate values between adc and dac
+ */
+ if (cr != driver->frame_rate && pr != driver->frame_rate) {
+ jack_error ("sample rate in use (%d Hz) does not "
+ "match requested rate (%d Hz)",
+ cr, driver->frame_rate);
+ driver->frame_rate = cr;
+ }
+
+ }
+ else if (driver->capture_handle && cr != driver->frame_rate) {
+ jack_error ("capture sample rate in use (%d Hz) does not "
+ "match requested rate (%d Hz)",
+ cr, driver->frame_rate);
+ driver->frame_rate = cr;
+ }
+ else if (driver->playback_handle && pr != driver->frame_rate) {
+ jack_error ("playback sample rate in use (%d Hz) does not "
+ "match requested rate (%d Hz)",
+ pr, driver->frame_rate);
+ driver->frame_rate = pr;
+ }
+
+
+ /* check the fragment size, since thats non-negotiable */
+
+ if (driver->playback_handle) {
+ snd_pcm_access_t access;
+
+ err = snd_pcm_hw_params_get_period_size (
+ driver->playback_hw_params, &p_period_size, &dir);
+ err = snd_pcm_hw_params_get_format (
+ driver->playback_hw_params,
+ &(driver->playback_sample_format));
+ err = snd_pcm_hw_params_get_access (driver->playback_hw_params,
+ &access);
+ driver->playback_interleaved =
+ (access == SND_PCM_ACCESS_MMAP_INTERLEAVED)
+ || (access == SND_PCM_ACCESS_MMAP_COMPLEX);
+
+ if (p_period_size != driver->frames_per_cycle) {
+ jack_error ("ioaudio_pcm: requested an interrupt every %"
+ PRIu32
+ " frames but got %u frames for playback",
+ driver->frames_per_cycle, p_period_size);
+ return -1;
+ }
+ }
+
+ if (driver->capture_handle) {
+ snd_pcm_access_t access;
+
+ err = snd_pcm_hw_params_get_period_size (
+ driver->capture_hw_params, &c_period_size, &dir);
+ err = snd_pcm_hw_params_get_format (
+ driver->capture_hw_params,
+ &(driver->capture_sample_format));
+ err = snd_pcm_hw_params_get_access (driver->capture_hw_params,
+ &access);
+ driver->capture_interleaved =
+ (access == SND_PCM_ACCESS_MMAP_INTERLEAVED)
+ || (access == SND_PCM_ACCESS_MMAP_COMPLEX);
+
+ if (c_period_size != driver->frames_per_cycle) {
+ jack_error ("ioaudio_pcm: requested an interrupt every %"
+ PRIu32
+ " frames but got %uc frames for capture",
+ driver->frames_per_cycle, p_period_size);
+ return -1;
+ }
+ }
+
+ driver->playback_sample_bytes =
+ snd_pcm_format_physical_width (driver->playback_sample_format)
+ / 8;
+ driver->capture_sample_bytes =
+ snd_pcm_format_physical_width (driver->capture_sample_format)
+ / 8;
+
+ if (driver->playback_handle) {
+ switch (driver->playback_sample_format) {
+ case SND_PCM_FORMAT_FLOAT_LE:
+ case SND_PCM_FORMAT_S32_LE:
+ case SND_PCM_FORMAT_S24_3LE:
+ case SND_PCM_FORMAT_S24_3BE:
+ case SND_PCM_FORMAT_S24_LE:
+ case SND_PCM_FORMAT_S24_BE:
+ case SND_PCM_FORMAT_S16_LE:
+ case SND_PCM_FORMAT_S32_BE:
+ case SND_PCM_FORMAT_S16_BE:
+ break;
+
+ default:
+ jack_error ("programming error: unhandled format "
+ "type for playback");
+ exit (1);
+ }
+ }
+
+ if (driver->capture_handle) {
+ switch (driver->capture_sample_format) {
+ case SND_PCM_FORMAT_FLOAT_LE:
+ case SND_PCM_FORMAT_S32_LE:
+ case SND_PCM_FORMAT_S24_3LE:
+ case SND_PCM_FORMAT_S24_3BE:
+ case SND_PCM_FORMAT_S24_LE:
+ case SND_PCM_FORMAT_S24_BE:
+ case SND_PCM_FORMAT_S16_LE:
+ case SND_PCM_FORMAT_S32_BE:
+ case SND_PCM_FORMAT_S16_BE:
+ break;
+
+ default:
+ jack_error ("programming error: unhandled format "
+ "type for capture");
+ exit (1);
+ }
+ }
+
+ if (driver->playback_interleaved) {
+ const snd_pcm_channel_area_t *my_areas;
+ size_t offset, frames;
+ if (snd_pcm_mmap_begin(driver->playback_handle,
+ &my_areas, &offset, &frames) < 0) {
+ jack_error ("ALSA: %s: mmap areas info error",
+ driver->ioaudio_name_playback);
+ return -1;
+ }
+ driver->interleave_unit =
+ snd_pcm_format_physical_width (
+ driver->playback_sample_format) / 8;
+ } else {
+ driver->interleave_unit = 0; /* NOT USED */
+ }
+
+ if (driver->capture_interleaved) {
+ const snd_pcm_channel_area_t *my_areas;
+ size_t offset, frames;
+ if (snd_pcm_mmap_begin(driver->capture_handle,
+ &my_areas, &offset, &frames) < 0) {
+ jack_error ("ALSA: %s: mmap areas info error",
+ driver->ioaudio_name_capture);
+ return -1;
+ }
+ }
+
+ if (driver->playback_nchannels > driver->capture_nchannels) {
+ driver->max_nchannels = driver->playback_nchannels;
+ driver->user_nchannels = driver->capture_nchannels;
+ } else {
+ driver->max_nchannels = driver->capture_nchannels;
+ driver->user_nchannels = driver->playback_nchannels;
+ }
+
+ ioaudio_driver_setup_io_function_pointers (driver);
+
+ /* Allocate and initialize structures that rely on the
+ channels counts.
+
+ Set up the bit pattern that is used to record which
+ channels require action on every cycle. any bits that are
+ not set after the engine's process() call indicate channels
+ that potentially need to be silenced.
+ */
+
+ bitset_create (&driver->channels_done, driver->max_nchannels);
+ bitset_create (&driver->channels_not_done, driver->max_nchannels);
+
+ if (driver->playback_handle) {
+ driver->playback_addr = (char **)
+ malloc (sizeof (char *) * driver->playback_nchannels);
+ memset (driver->playback_addr, 0,
+ sizeof (char *) * driver->playback_nchannels);
+ driver->playback_interleave_skip = (unsigned long *)
+ malloc (sizeof (unsigned long *) * driver->playback_nchannels);
+ memset (driver->playback_interleave_skip, 0,
+ sizeof (unsigned long *) * driver->playback_nchannels);
+ driver->silent = (unsigned long *)
+ malloc (sizeof (unsigned long)
+ * driver->playback_nchannels);
+
+ for (chn = 0; chn < driver->playback_nchannels; chn++) {
+ driver->silent[chn] = 0;
+ }
+
+ for (chn = 0; chn < driver->playback_nchannels; chn++) {
+ bitset_add (driver->channels_done, chn);
+ }
+
+ driver->dither_state = (dither_state_t *)
+ calloc ( driver->playback_nchannels,
+ sizeof (dither_state_t));
+ }
+
+ if (driver->capture_handle) {
+ driver->capture_addr = (char **)
+ malloc (sizeof (char *) * driver->capture_nchannels);
+ memset (driver->capture_addr, 0,
+ sizeof (char *) * driver->capture_nchannels);
+ driver->capture_interleave_skip = (unsigned long *)
+ malloc (sizeof (unsigned long *) * driver->capture_nchannels);
+ memset (driver->capture_interleave_skip, 0,
+ sizeof (unsigned long *) * driver->capture_nchannels);
+ }
+
+ driver->clock_sync_data = (ClockSyncStatus *)
+ malloc (sizeof (ClockSyncStatus) * driver->max_nchannels);
+
+ driver->period_usecs =
+ (jack_time_t) floor ((((float) driver->frames_per_cycle) /
+ driver->frame_rate) * 1000000.0f);
+ driver->poll_timeout = (int) floor (1.5f * driver->period_usecs);
+
+// JACK2
+/*
+ if (driver->engine) {
+ if (driver->engine->set_buffer_size (driver->engine,
+ driver->frames_per_cycle)) {
+ jack_error ("ALSA: Cannot set engine buffer size to %d (check MIDI)", driver->frames_per_cycle);
+ return -1;
+ }
+ }
+*/
+
+ return 0;
+}
+
+int
+ioaudio_driver_reset_parameters (ioaudio_driver_t *driver,
+ jack_nframes_t frames_per_cycle,
+ jack_nframes_t user_nperiods,
+ jack_nframes_t rate)
+{
+ /* XXX unregister old ports ? */
+ ioaudio_driver_release_channel_dependent_memory (driver);
+ return ioaudio_driver_set_parameters (driver,
+ frames_per_cycle,
+ user_nperiods, rate);
+}
+
+static int
+ioaudio_driver_get_channel_addresses (ioaudio_driver_t *driver,
+ size_t *capture_avail,
+ size_t *playback_avail,
+ size_t *capture_offset,
+ size_t *playback_offset)
+{
+ int err;
+ channel_t chn;
+
+ if (capture_avail) {
+ if ((err = snd_pcm_mmap_begin (
+ driver->capture_handle, &driver->capture_areas,
+ (size_t *) capture_offset,
+ (size_t *) capture_avail)) < 0) {
+ jack_error ("ALSA: %s: mmap areas info error",
+ driver->ioaudio_name_capture);
+ return -1;
+ }
+
+ for (chn = 0; chn < driver->capture_nchannels; chn++) {
+ const snd_pcm_channel_area_t *a =
+ &driver->capture_areas[chn];
+ driver->capture_addr[chn] = (char *) a->addr
+ + ((a->first + a->step * *capture_offset) / 8);
+ driver->capture_interleave_skip[chn] = (unsigned long ) (a->step / 8);
+ }
+ }
+
+ if (playback_avail) {
+ if ((err = snd_pcm_mmap_begin (
+ driver->playback_handle, &driver->playback_areas,
+ (size_t *) playback_offset,
+ (size_t *) playback_avail)) < 0) {
+ jack_error ("ALSA: %s: mmap areas info error ",
+ driver->ioaudio_name_playback);
+ return -1;
+ }
+
+ for (chn = 0; chn < driver->playback_nchannels; chn++) {
+ const snd_pcm_channel_area_t *a =
+ &driver->playback_areas[chn];
+ driver->playback_addr[chn] = (char *) a->addr
+ + ((a->first + a->step * *playback_offset) / 8);
+ driver->playback_interleave_skip[chn] = (unsigned long ) (a->step / 8);
+ }
+ }
+
+ return 0;
+}
+
+int
+ioaudio_driver_start (ioaudio_driver_t *driver)
+{
+ int err;
+ size_t poffset, pavail;
+ channel_t chn;
+
+ driver->poll_last = 0;
+ driver->poll_next = 0;
+
+ if (driver->playback_handle) {
+ if ((err = snd_pcm_prepare (driver->playback_handle)) < 0) {
+ jack_error ("ALSA: prepare error for playback on "
+ "\"%s\" (%s)", driver->ioaudio_name_playback,
+ snd_strerror(err));
+ return -1;
+ }
+ }
+
+ if ((driver->capture_handle && driver->capture_and_playback_not_synced)
+ || !driver->playback_handle) {
+ if ((err = snd_pcm_prepare (driver->capture_handle)) < 0) {
+ jack_error ("ALSA: prepare error for capture on \"%s\""
+ " (%s)", driver->ioaudio_name_capture,
+ snd_strerror(err));
+ return -1;
+ }
+ }
+
+ if (driver->hw_monitoring) {
+ if (driver->input_monitor_mask || driver->all_monitor_in) {
+ if (driver->all_monitor_in) {
+ driver->hw->set_input_monitor_mask (driver->hw, ~0U);
+ } else {
+ driver->hw->set_input_monitor_mask (
+ driver->hw, driver->input_monitor_mask);
+ }
+ } else {
+ driver->hw->set_input_monitor_mask (driver->hw,
+ driver->input_monitor_mask);
+ }
+ }
+
+ if (driver->playback_handle) {
+ driver->playback_nfds =
+ snd_pcm_poll_descriptors_count (driver->playback_handle);
+ } else {
+ driver->playback_nfds = 0;
+ }
+
+ if (driver->capture_handle) {
+ driver->capture_nfds =
+ snd_pcm_poll_descriptors_count (driver->capture_handle);
+ } else {
+ driver->capture_nfds = 0;
+ }
+
+ if (driver->pfd) {
+ free (driver->pfd);
+ }
+
+ driver->pfd = (struct pollfd *)
+ malloc (sizeof (struct pollfd) *
+ (driver->playback_nfds + driver->capture_nfds + 2));
+
+ if (driver->midi && !driver->xrun_recovery)
+ (driver->midi->start)(driver->midi);
+
+ if (driver->playback_handle) {
+ /* fill playback buffer with zeroes, and mark
+ all fragments as having data.
+ */
+
+ pavail = snd_pcm_avail_update (driver->playback_handle);
+
+ if (pavail !=
+ driver->frames_per_cycle * driver->playback_nperiods) {
+ jack_error ("ALSA: full buffer not available at start");
+ return -1;
+ }
+
+ if (ioaudio_driver_get_channel_addresses (driver,
+ 0, &pavail, 0, &poffset)) {
+ return -1;
+ }
+
+ /* XXX this is cheating. ALSA offers no guarantee that
+ we can access the entire buffer at any one time. It
+ works on most hardware tested so far, however, buts
+ its a liability in the long run. I think that
+ alsa-lib may have a better function for doing this
+ here, where the goal is to silence the entire
+ buffer.
+ */
+
+ for (chn = 0; chn < driver->playback_nchannels; chn++) {
+ ioaudio_driver_silence_on_channel (
+ driver, chn,
+ driver->user_nperiods
+ * driver->frames_per_cycle);
+ }
+
+ snd_pcm_mmap_commit (driver->playback_handle, poffset,
+ driver->user_nperiods
+ * driver->frames_per_cycle);
+
+ if ((err = snd_pcm_start (driver->playback_handle)) < 0) {
+ jack_error ("ALSA: could not start playback (%s)",
+ snd_strerror (err));
+ return -1;
+ }
+ }
+
+ if ((driver->capture_handle && driver->capture_and_playback_not_synced)
+ || !driver->playback_handle) {
+ if ((err = snd_pcm_start (driver->capture_handle)) < 0) {
+ jack_error ("ALSA: could not start capture (%s)",
+ snd_strerror (err));
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int
+ioaudio_driver_stop (ioaudio_driver_t *driver)
+{
+ int err;
+// JSList* node;
+// int chn;
+
+ /* silence all capture port buffers, because we might
+ be entering offline mode.
+ */
+
+// JACK2
+/*
+ for (chn = 0, node = driver->capture_ports; node;
+ node = jack_slist_next (node), chn++) {
+
+ jack_port_t* port;
+ char* buf;
+ jack_nframes_t nframes = driver->engine->control->buffer_size;
+
+ port = (jack_port_t *) node->data;
+ buf = jack_port_get_buffer (port, nframes);
+ memset (buf, 0, sizeof (jack_default_audio_sample_t) * nframes);
+ }
+*/
+
+// JACK2
+ ClearOutput();
+
+ if (driver->playback_handle) {
+ if ((err = snd_pcm_drop (driver->playback_handle)) < 0) {
+ jack_error ("ALSA: channel flush for playback "
+ "failed (%s)", snd_strerror (err));
+ return -1;
+ }
+ }
+
+ if (!driver->playback_handle
+ || driver->capture_and_playback_not_synced) {
+ if (driver->capture_handle) {
+ if ((err = snd_pcm_drop (driver->capture_handle)) < 0) {
+ jack_error ("ALSA: channel flush for "
+ "capture failed (%s)",
+ snd_strerror (err));
+ return -1;
+ }
+ }
+ }
+
+ if (driver->hw_monitoring) {
+ driver->hw->set_input_monitor_mask (driver->hw, 0);
+ }
+
+ if (driver->midi && !driver->xrun_recovery)
+ (driver->midi->stop)(driver->midi);
+
+ return 0;
+}
+
+static int
+ioaudio_driver_restart (ioaudio_driver_t *driver)
+{
+ int res;
+
+ driver->xrun_recovery = 1;
+ // JACK2
+ /*
+ if ((res = driver->nt_stop((struct _jack_driver_nt *) driver))==0)
+ res = driver->nt_start((struct _jack_driver_nt *) driver);
+ */
+ res = Restart();
+ driver->xrun_recovery = 0;
+
+ if (res && driver->midi)
+ (driver->midi->stop)(driver->midi);
+
+ return res;
+}
+
+static int
+ioaudio_driver_xrun_recovery (ioaudio_driver_t *driver, float *delayed_usecs)
+{
+ snd_pcm_status_t *status;
+ int res;
+
+ snd_pcm_status_alloca(&status);
+
+ if (driver->capture_handle) {
+ if ((res = snd_pcm_status(driver->capture_handle, status))
+ < 0) {
+ jack_error("status error: %s", snd_strerror(res));
+ }
+ } else {
+ if ((res = snd_pcm_status(driver->playback_handle, status))
+ < 0) {
+ jack_error("status error: %s", snd_strerror(res));
+ }
+ }
+
+ if (snd_pcm_status_get_state(status) == SND_PCM_STATE_SUSPENDED)
+ {
+ jack_log("**** ioaudio_pcm: pcm in suspended state, resuming it" );
+ if (driver->capture_handle) {
+ if ((res = snd_pcm_prepare(driver->capture_handle))
+ < 0) {
+ jack_error("error preparing after suspend: %s", snd_strerror(res));
+ }
+ } else {
+ if ((res = snd_pcm_prepare(driver->playback_handle))
+ < 0) {
+ jack_error("error preparing after suspend: %s", snd_strerror(res));
+ }
+ }
+ }
+
+ if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN
+ && driver->process_count > XRUN_REPORT_DELAY) {
+ struct timeval now, diff, tstamp;
+ driver->xrun_count++;
+ snd_pcm_status_get_tstamp(status,&now);
+ snd_pcm_status_get_trigger_tstamp(status, &tstamp);
+ timersub(&now, &tstamp, &diff);
+ *delayed_usecs = diff.tv_sec * 1000000.0 + diff.tv_usec;
+ jack_log("**** ioaudio_pcm: xrun of at least %.3f msecs",*delayed_usecs / 1000.0);
+ }
+
+ if (ioaudio_driver_restart (driver)) {
+ return -1;
+ }
+ return 0;
+}
+
+void
+ioaudio_driver_silence_untouched_channels (ioaudio_driver_t *driver,
+ jack_nframes_t nframes)
+{
+ channel_t chn;
+ jack_nframes_t buffer_frames =
+ driver->frames_per_cycle * driver->playback_nperiods;
+
+ for (chn = 0; chn < driver->playback_nchannels; chn++) {
+ if (bitset_contains (driver->channels_not_done, chn)) {
+ if (driver->silent[chn] < buffer_frames) {
+ ioaudio_driver_silence_on_channel_no_mark (
+ driver, chn, nframes);
+ driver->silent[chn] += nframes;
+ }
+ }
+ }
+}
+
+void
+ioaudio_driver_set_clock_sync_status (ioaudio_driver_t *driver, channel_t chn,
+ ClockSyncStatus status)
+{
+ driver->clock_sync_data[chn] = status;
+ ioaudio_driver_clock_sync_notify (driver, chn, status);
+}
+
+static int under_gdb = FALSE;
+
+jack_nframes_t
+ioaudio_driver_wait (ioaudio_driver_t *driver, int extra_fd, int *status, float
+ *delayed_usecs)
+{
+ ssize_t avail = 0;
+ ssize_t capture_avail = 0;
+ ssize_t playback_avail = 0;
+ int xrun_detected = FALSE;
+ int need_capture;
+ int need_playback;
+ unsigned int i;
+ jack_time_t poll_enter;
+ jack_time_t poll_ret = 0;
+
+ *status = -1;
+ *delayed_usecs = 0;
+
+ need_capture = driver->capture_handle ? 1 : 0;
+
+ if (extra_fd >= 0) {
+ need_playback = 0;
+ } else {
+ need_playback = driver->playback_handle ? 1 : 0;
+ }
+
+ again:
+
+ while (need_playback || need_capture) {
+
+ int poll_result;
+ unsigned int ci = 0;
+ unsigned int nfds;
+ unsigned short revents;
+
+ nfds = 0;
+
+ if (need_playback) {
+ snd_pcm_poll_descriptors (driver->playback_handle,
+ &driver->pfd[0],
+ driver->playback_nfds);
+ nfds += driver->playback_nfds;
+ }
+
+ if (need_capture) {
+ snd_pcm_poll_descriptors (driver->capture_handle,
+ &driver->pfd[nfds],
+ driver->capture_nfds);
+ ci = nfds;
+ nfds += driver->capture_nfds;
+ }
+
+ /* ALSA doesn't set POLLERR in some versions of 0.9.X */
+
+ for (i = 0; i < nfds; i++) {
+ driver->pfd[i].events |= POLLERR;
+ }
+
+ if (extra_fd >= 0) {
+ driver->pfd[nfds].fd = extra_fd;
+ driver->pfd[nfds].events =
+ POLLIN|POLLERR|POLLHUP|POLLNVAL;
+ nfds++;
+ }
+
+ poll_enter = jack_get_microseconds ();
+
+ if (poll_enter > driver->poll_next) {
+ /*
+ * This processing cycle was delayed past the
+ * next due interrupt! Do not account this as
+ * a wakeup delay:
+ */
+ driver->poll_next = 0;
+ driver->poll_late++;
+ }
+
+#ifdef __ANDROID__
+ poll_result = poll (driver->pfd, nfds, -1); //fix for sleep issue
+#else
+ poll_result = poll (driver->pfd, nfds, driver->poll_timeout);
+#endif
+ if (poll_result < 0) {
+
+ if (errno == EINTR) {
+ jack_info ("poll interrupt");
+ // this happens mostly when run
+ // under gdb, or when exiting due to a signal
+ if (under_gdb) {
+ goto again;
+ }
+ *status = -2;
+ return 0;
+ }
+
+ jack_error ("ALSA: poll call failed (%s)",
+ strerror (errno));
+ *status = -3;
+ return 0;
+
+ }
+
+ poll_ret = jack_get_microseconds ();
+
+ // JACK2
+ SetTime(poll_ret);
+
+ if (extra_fd < 0) {
+ if (driver->poll_next && poll_ret > driver->poll_next) {
+ *delayed_usecs = poll_ret - driver->poll_next;
+ }
+ driver->poll_last = poll_ret;
+ driver->poll_next = poll_ret + driver->period_usecs;
+// JACK2
+/*
+ driver->engine->transport_cycle_start (driver->engine,
+ poll_ret);
+*/
+ }
+
+#ifdef DEBUG_WAKEUP
+ fprintf (stderr, "%" PRIu64 ": checked %d fds, started at %" PRIu64 " %" PRIu64 " usecs since poll entered\n",
+ poll_ret, nfds, poll_enter, poll_ret - poll_enter);
+#endif
+
+ /* check to see if it was the extra FD that caused us
+ * to return from poll */
+
+ if (extra_fd >= 0) {
+
+ if (driver->pfd[nfds-1].revents == 0) {
+ /* we timed out on the extra fd */
+
+ *status = -4;
+ return -1;
+ }
+
+ /* if POLLIN was the only bit set, we're OK */
+
+ *status = 0;
+ return (driver->pfd[nfds-1].revents == POLLIN) ? 0 : -1;
+ }
+
+ if (need_playback) {
+ if (snd_pcm_poll_descriptors_revents
+ (driver->playback_handle, &driver->pfd[0],
+ driver->playback_nfds, &revents) < 0) {
+ jack_error ("ALSA: playback revents failed");
+ *status = -6;
+ return 0;
+ }
+
+ if (revents & POLLERR) {
+ xrun_detected = TRUE;
+ }
+
+ if (revents & POLLOUT) {
+ need_playback = 0;
+#ifdef DEBUG_WAKEUP
+ fprintf (stderr, "%" PRIu64
+ " playback stream ready\n",
+ poll_ret);
+#endif
+ }
+ }
+
+ if (need_capture) {
+ if (snd_pcm_poll_descriptors_revents
+ (driver->capture_handle, &driver->pfd[ci],
+ driver->capture_nfds, &revents) < 0) {
+ jack_error ("ALSA: capture revents failed");
+ *status = -6;
+ return 0;
+ }
+
+ if (revents & POLLERR) {
+ xrun_detected = TRUE;
+ }
+
+ if (revents & POLLIN) {
+ need_capture = 0;
+#ifdef DEBUG_WAKEUP
+ fprintf (stderr, "%" PRIu64
+ " capture stream ready\n",
+ poll_ret);
+#endif
+ }
+ }
+
+ if (poll_result == 0) {
+ jack_error ("ALSA: poll time out, polled for %" PRIu64
+ " usecs",
+ poll_ret - poll_enter);
+ *status = -5;
+ return 0;
+ }
+
+ }
+
+ if (driver->capture_handle) {
+ if ((capture_avail = snd_pcm_avail_update (
+ driver->capture_handle)) < 0) {
+ if (capture_avail == -EPIPE) {
+ xrun_detected = TRUE;
+ } else {
+ jack_error ("unknown ALSA avail_update return"
+ " value (%u)", capture_avail);
+ }
+ }
+ } else {
+ /* odd, but see min() computation below */
+ capture_avail = INT_MAX;
+ }
+
+ if (driver->playback_handle) {
+ if ((playback_avail = snd_pcm_avail_update (
+ driver->playback_handle)) < 0) {
+ if (playback_avail == -EPIPE) {
+ xrun_detected = TRUE;
+ } else {
+ jack_error ("unknown ALSA avail_update return"
+ " value (%u)", playback_avail);
+ }
+ }
+ } else {
+ /* odd, but see min() computation below */
+ playback_avail = INT_MAX;
+ }
+
+ if (xrun_detected) {
+ *status = ioaudio_driver_xrun_recovery (driver, delayed_usecs);
+ return 0;
+ }
+
+ *status = 0;
+ driver->last_wait_ust = poll_ret;
+
+ avail = capture_avail < playback_avail ? capture_avail : playback_avail;
+
+#ifdef DEBUG_WAKEUP
+ fprintf (stderr, "wakeup complete, avail = %lu, pavail = %lu "
+ "cavail = %lu\n",
+ avail, playback_avail, capture_avail);
+#endif
+
+ /* mark all channels not done for now. read/write will change this */
+
+ bitset_copy (driver->channels_not_done, driver->channels_done);
+
+ /* constrain the available count to the nearest (round down) number of
+ periods.
+ */
+
+ return avail - (avail % driver->frames_per_cycle);
+}
+
+
+int
+ioaudio_driver_read (ioaudio_driver_t *driver, jack_nframes_t nframes)
+{
+ ssize_t contiguous;
+ ssize_t nread;
+ size_t offset;
+ jack_nframes_t orig_nframes;
+// jack_default_audio_sample_t* buf;
+// channel_t chn;
+// JSList *node;
+// jack_port_t* port;
+ int err;
+
+ if (nframes > driver->frames_per_cycle) {
+ return -1;
+ }
+
+// JACK2
+/*
+ if (driver->engine->freewheeling) {
+ return 0;
+ }
+*/
+ if (driver->midi)
+ (driver->midi->read)(driver->midi, nframes);
+
+ if (!driver->capture_handle) {
+ return 0;
+ }
+
+ nread = 0;
+ contiguous = 0;
+ orig_nframes = nframes;
+
+ while (nframes) {
+
+ contiguous = nframes;
+
+ if (ioaudio_driver_get_channel_addresses (
+ driver,
+ (size_t *) &contiguous,
+ (size_t *) 0,
+ &offset, 0) < 0) {
+ return -1;
+ }
+// JACK2
+/*
+ for (chn = 0, node = driver->capture_ports; node;
+ node = jack_slist_next (node), chn++) {
+
+ port = (jack_port_t *) node->data;
+
+ if (!jack_port_connected (port)) {
+ // no-copy optimization
+ continue;
+ }
+ buf = jack_port_get_buffer (port, orig_nframes);
+ ioaudio_driver_read_from_channel (driver, chn,
+ buf + nread, contiguous);
+ }
+*/
+ ReadInput(orig_nframes, contiguous, nread);
+
+ if ((err = snd_pcm_mmap_commit (driver->capture_handle,
+ offset, contiguous)) < 0) {
+ jack_error ("ALSA: could not complete read of %"
+ PRIu32 " frames: error = %d", contiguous, err);
+ return -1;
+ }
+
+ nframes -= contiguous;
+ nread += contiguous;
+ }
+
+ return 0;
+}
+
+int
+ioaudio_driver_write (ioaudio_driver_t* driver, jack_nframes_t nframes)
+{
+// channel_t chn;
+// JSList *node;
+// JSList *mon_node;
+// jack_default_audio_sample_t* buf;
+// jack_default_audio_sample_t* monbuf;
+ jack_nframes_t orig_nframes;
+ ssize_t nwritten;
+ ssize_t contiguous;
+ size_t offset;
+// jack_port_t *port;
+ int err;
+
+ driver->process_count++;
+
+// JACK2
+/*
+ if (!driver->playback_handle || driver->engine->freewheeling) {
+ return 0;
+ }
+*/
+ if (!driver->playback_handle) {
+ return 0;
+ }
+
+ if (nframes > driver->frames_per_cycle) {
+ return -1;
+ }
+
+ if (driver->midi)
+ (driver->midi->write)(driver->midi, nframes);
+
+ nwritten = 0;
+ contiguous = 0;
+ orig_nframes = nframes;
+
+ /* check current input monitor request status */
+
+ driver->input_monitor_mask = 0;
+
+// JACK2
+/*
+ for (chn = 0, node = driver->capture_ports; node;
+ node = jack_slist_next (node), chn++) {
+ if (((jack_port_t *) node->data)->shared->monitor_requests) {
+ driver->input_monitor_mask |= (1<hw_monitoring) {
+ if ((driver->hw->input_monitor_mask
+ != driver->input_monitor_mask)
+ && !driver->all_monitor_in) {
+ driver->hw->set_input_monitor_mask (
+ driver->hw, driver->input_monitor_mask);
+ }
+ }
+
+ while (nframes) {
+
+ contiguous = nframes;
+
+ if (ioaudio_driver_get_channel_addresses (
+ driver,
+ (size_t *) 0,
+ (size_t *) &contiguous,
+ 0, &offset) < 0) {
+ return -1;
+ }
+
+// JACK2
+/*
+ for (chn = 0, node = driver->playback_ports, mon_node=driver->monitor_ports;
+ node;
+ node = jack_slist_next (node), chn++) {
+
+ port = (jack_port_t *) node->data;
+
+ if (!jack_port_connected (port)) {
+ continue;
+ }
+ buf = jack_port_get_buffer (port, orig_nframes);
+ ioaudio_driver_write_to_channel (driver, chn,
+ buf + nwritten, contiguous);
+
+ if (mon_node) {
+ port = (jack_port_t *) mon_node->data;
+ if (!jack_port_connected (port)) {
+ continue;
+ }
+ monbuf = jack_port_get_buffer (port, orig_nframes);
+ memcpy (monbuf + nwritten, buf + nwritten, contiguous * sizeof(jack_default_audio_sample_t));
+ mon_node = jack_slist_next (mon_node);
+ }
+ }
+*/
+
+ // JACK2
+ WriteOutput(orig_nframes, contiguous, nwritten);
+
+ if (!bitset_empty (driver->channels_not_done)) {
+ ioaudio_driver_silence_untouched_channels (driver,
+ contiguous);
+ }
+
+ if ((err = snd_pcm_mmap_commit (driver->playback_handle,
+ offset, contiguous)) < 0) {
+ jack_error ("ALSA: could not complete playback of %"
+ PRIu32 " frames: error = %d", contiguous, err);
+ if (err != -EPIPE && err != -ESTRPIPE)
+ return -1;
+ }
+
+ nframes -= contiguous;
+ nwritten += contiguous;
+ }
+
+ return 0;
+}
+
+#if 0
+static int /* UNUSED */
+ioaudio_driver_change_sample_clock (ioaudio_driver_t *driver, SampleClockMode mode)
+{
+ return driver->hw->change_sample_clock (driver->hw, mode);
+}
+
+static void /* UNUSED */
+ioaudio_driver_request_all_monitor_input (ioaudio_driver_t *driver, int yn)
+
+{
+ if (driver->hw_monitoring) {
+ if (yn) {
+ driver->hw->set_input_monitor_mask (driver->hw, ~0U);
+ } else {
+ driver->hw->set_input_monitor_mask (
+ driver->hw, driver->input_monitor_mask);
+ }
+ }
+
+ driver->all_monitor_in = yn;
+}
+
+static void /* UNUSED */
+ioaudio_driver_set_hw_monitoring (ioaudio_driver_t *driver, int yn)
+{
+ if (yn) {
+ driver->hw_monitoring = TRUE;
+
+ if (driver->all_monitor_in) {
+ driver->hw->set_input_monitor_mask (driver->hw, ~0U);
+ } else {
+ driver->hw->set_input_monitor_mask (
+ driver->hw, driver->input_monitor_mask);
+ }
+ } else {
+ driver->hw_monitoring = FALSE;
+ driver->hw->set_input_monitor_mask (driver->hw, 0);
+ }
+}
+
+static ClockSyncStatus /* UNUSED */
+ioaudio_driver_clock_sync_status (channel_t chn)
+{
+ return Lock;
+}
+#endif
+
+void
+ioaudio_driver_delete (ioaudio_driver_t *driver)
+{
+ JSList *node;
+
+ if (driver->midi)
+ (driver->midi->destroy)(driver->midi);
+
+ for (node = driver->clock_sync_listeners; node;
+ node = jack_slist_next (node)) {
+ free (node->data);
+ }
+ jack_slist_free (driver->clock_sync_listeners);
+
+ if (driver->ctl_handle) {
+ snd_ctl_close (driver->ctl_handle);
+ driver->ctl_handle = 0;
+ }
+
+ if (driver->capture_handle) {
+ snd_pcm_close (driver->capture_handle);
+ driver->capture_handle = 0;
+ }
+
+ if (driver->playback_handle) {
+ snd_pcm_close (driver->playback_handle);
+ driver->capture_handle = 0;
+ }
+
+ if (driver->capture_hw_params) {
+ snd_pcm_hw_params_free (driver->capture_hw_params);
+ driver->capture_hw_params = 0;
+ }
+
+ if (driver->playback_hw_params) {
+ snd_pcm_hw_params_free (driver->playback_hw_params);
+ driver->playback_hw_params = 0;
+ }
+
+ if (driver->capture_sw_params) {
+ snd_pcm_sw_params_free (driver->capture_sw_params);
+ driver->capture_sw_params = 0;
+ }
+
+ if (driver->playback_sw_params) {
+ snd_pcm_sw_params_free (driver->playback_sw_params);
+ driver->playback_sw_params = 0;
+ }
+
+ if (driver->pfd) {
+ free (driver->pfd);
+ }
+
+ if (driver->hw) {
+ driver->hw->release (driver->hw);
+ driver->hw = 0;
+ }
+ free(driver->ioaudio_name_playback);
+ free(driver->ioaudio_name_capture);
+ free(driver->ioaudio_driver);
+
+ ioaudio_driver_release_channel_dependent_memory (driver);
+ //JACK2
+ //jack_driver_nt_finish ((jack_driver_nt_t *) driver);
+ free (driver);
+}
+
+static char*
+discover_ioaudio_using_apps ()
+{
+ char found[2048];
+ char command[5192];
+ char* path = getenv ("PATH");
+ char* dir;
+ size_t flen = 0;
+ int card;
+ int device;
+ size_t cmdlen = 0;
+
+ if (!path) {
+ return NULL;
+ }
+
+ /* look for lsof and give up if its not in PATH */
+
+ path = strdup (path);
+ dir = strtok (path, ":");
+ while (dir) {
+ char maybe[PATH_MAX+1];
+ snprintf (maybe, sizeof(maybe), "%s/lsof", dir);
+ if (access (maybe, X_OK)) {
+ break;
+ }
+ dir = strtok (NULL, ":");
+ }
+ free (path);
+
+ if (!dir) {
+ return NULL;
+ }
+
+ snprintf (command, sizeof (command), "lsof -Fc0 ");
+ cmdlen = strlen (command);
+
+ for (card = 0; card < 8; ++card) {
+ for (device = 0; device < 8; ++device) {
+ char buf[32];
+
+ snprintf (buf, sizeof (buf), "/dev/snd/pcmC%dD%dp", card, device);
+ if (access (buf, F_OK) == 0) {
+ snprintf (command+cmdlen, sizeof(command)-cmdlen, "%s ", buf);
+ }
+ cmdlen = strlen (command);
+
+ snprintf (buf, sizeof (buf), "/dev/snd/pcmC%dD%dc", card, device);
+ if (access (buf, F_OK) == 0) {
+ snprintf (command+cmdlen, sizeof(command)-cmdlen, "%s ", buf);
+ }
+ cmdlen = strlen (command);
+ }
+ }
+
+ FILE* f = popen (command, "r");
+
+ if (!f) {
+ return NULL;
+ }
+
+ while (!feof (f)) {
+ char buf[1024]; /* lsof doesn't output much */
+
+ if (!fgets (buf, sizeof (buf), f)) {
+ break;
+ }
+
+ if (*buf != 'p') {
+ return NULL;
+ }
+
+ /* buf contains NULL as a separator between the process field and the command field */
+ char *pid = buf;
+ ++pid; /* skip leading 'p' */
+ char *cmd = pid;
+
+ /* skip to NULL */
+ while (*cmd) {
+ ++cmd;
+ }
+ ++cmd; /* skip to 'c' */
+ ++cmd; /* skip to first character of command */
+
+ snprintf (found+flen, sizeof (found)-flen, "%s (process ID %s)\n", cmd, pid);
+ flen = strlen (found);
+
+ if (flen >= sizeof (found)) {
+ break;
+ }
+ }
+
+ pclose (f);
+
+ if (flen) {
+ return strdup (found);
+ } else {
+ return NULL;
+ }
+}
+
+jack_driver_t *
+ioaudio_driver_new (char *name, char *playback_ioaudio_device,
+ char *capture_ioaudio_device,
+ jack_client_t *client,
+ jack_nframes_t frames_per_cycle,
+ jack_nframes_t user_nperiods,
+ jack_nframes_t rate,
+ int hw_monitoring,
+ int hw_metering,
+ int capturing,
+ int playing,
+ DitherAlgorithm dither,
+ int soft_mode,
+ int monitor,
+ int user_capture_nchnls,
+ int user_playback_nchnls,
+ int shorts_first,
+ jack_nframes_t capture_latency,
+ jack_nframes_t playback_latency,
+ ioaudio_midi_t *midi_driver
+ )
+{
+ int err;
+ char* current_apps;
+ ioaudio_driver_t *driver;
+
+ jack_info ("creating alsa driver ... %s|%s|%" PRIu32 "|%" PRIu32
+ "|%" PRIu32"|%" PRIu32"|%" PRIu32 "|%s|%s|%s|%s",
+ playing ? playback_ioaudio_device : "-",
+ capturing ? capture_ioaudio_device : "-",
+ frames_per_cycle, user_nperiods, rate,
+ user_capture_nchnls,user_playback_nchnls,
+ hw_monitoring ? "hwmon": "nomon",
+ hw_metering ? "hwmeter":"swmeter",
+ soft_mode ? "soft-mode":"-",
+ shorts_first ? "16bit":"32bit");
+
+ driver = (ioaudio_driver_t *) calloc (1, sizeof (ioaudio_driver_t));
+
+ jack_driver_nt_init ((jack_driver_nt_t *) driver);
+
+ // JACK2
+ /*
+ driver->nt_attach = (JackDriverNTAttachFunction) ioaudio_driver_attach;
+ driver->nt_detach = (JackDriverNTDetachFunction) ioaudio_driver_detach;
+ driver->read = (JackDriverReadFunction) ioaudio_driver_read;
+ driver->write = (JackDriverReadFunction) ioaudio_driver_write;
+ driver->null_cycle = (JackDriverNullCycleFunction) ioaudio_driver_null_cycle;
+ driver->nt_bufsize = (JackDriverNTBufSizeFunction) ioaudio_driver_bufsize;
+ driver->nt_start = (JackDriverNTStartFunction) ioaudio_driver_start;
+ driver->nt_stop = (JackDriverNTStopFunction) ioaudio_driver_stop;
+ driver->nt_run_cycle = (JackDriverNTRunCycleFunction) ioaudio_driver_run_cycle;
+ */
+
+ driver->playback_handle = NULL;
+ driver->capture_handle = NULL;
+ driver->ctl_handle = 0;
+ driver->hw = 0;
+ driver->capture_and_playback_not_synced = FALSE;
+ driver->max_nchannels = 0;
+ driver->user_nchannels = 0;
+ driver->playback_nchannels = user_playback_nchnls;
+ driver->capture_nchannels = user_capture_nchnls;
+ driver->playback_sample_bytes = (shorts_first ? 2:4);
+ driver->capture_sample_bytes = (shorts_first ? 2:4);
+ driver->capture_frame_latency = capture_latency;
+ driver->playback_frame_latency = playback_latency;
+
+ driver->playback_addr = 0;
+ driver->capture_addr = 0;
+ driver->playback_interleave_skip = NULL;
+ driver->capture_interleave_skip = NULL;
+
+
+ driver->silent = 0;
+ driver->all_monitor_in = FALSE;
+ driver->with_monitor_ports = monitor;
+
+ driver->clock_mode = ClockMaster; /* XXX is it? */
+ driver->input_monitor_mask = 0; /* XXX is it? */
+
+ driver->capture_ports = 0;
+ driver->playback_ports = 0;
+ driver->monitor_ports = 0;
+
+ driver->pfd = 0;
+ driver->playback_nfds = 0;
+ driver->capture_nfds = 0;
+
+ driver->dither = dither;
+ driver->soft_mode = soft_mode;
+
+ driver->quirk_bswap = 0;
+
+ pthread_mutex_init (&driver->clock_sync_lock, 0);
+ driver->clock_sync_listeners = 0;
+
+ driver->poll_late = 0;
+ driver->xrun_count = 0;
+ driver->process_count = 0;
+
+ driver->ioaudio_name_playback = strdup (playback_ioaudio_device);
+ driver->ioaudio_name_capture = strdup (capture_ioaudio_device);
+
+ driver->midi = midi_driver;
+ driver->xrun_recovery = 0;
+
+ if (ioaudio_driver_check_card_type (driver)) {
+ ioaudio_driver_delete (driver);
+ return NULL;
+ }
+
+ ioaudio_driver_hw_specific (driver, hw_monitoring, hw_metering);
+
+ if (playing) {
+ if (snd_pcm_open (&driver->playback_handle,
+ playback_ioaudio_device,
+ SND_PCM_STREAM_PLAYBACK,
+ SND_PCM_NONBLOCK) < 0) {
+ switch (errno) {
+ case EBUSY:
+#ifdef __ANDROID__
+ jack_error ("\n\nATTENTION: The playback device \"%s\" is "
+ "already in use. Please stop the"
+ " application using it and "
+ "run JACK again",
+ playback_ioaudio_device);
+#else
+ current_apps = discover_ioaudio_using_apps ();
+ if (current_apps) {
+ jack_error ("\n\nATTENTION: The playback device \"%s\" is "
+ "already in use. The following applications "
+ " are using your soundcard(s) so you should "
+ " check them and stop them as necessary before "
+ " trying to start JACK again:\n\n%s",
+ playback_ioaudio_device,
+ current_apps);
+ free (current_apps);
+ } else {
+ jack_error ("\n\nATTENTION: The playback device \"%s\" is "
+ "already in use. Please stop the"
+ " application using it and "
+ "run JACK again",
+ playback_ioaudio_device);
+ }
+#endif
+ ioaudio_driver_delete (driver);
+ return NULL;
+
+ case EPERM:
+ jack_error ("you do not have permission to open "
+ "the audio device \"%s\" for playback",
+ playback_ioaudio_device);
+ ioaudio_driver_delete (driver);
+ return NULL;
+ break;
+ }
+
+ driver->playback_handle = NULL;
+ }
+
+ if (driver->playback_handle) {
+ snd_pcm_nonblock (driver->playback_handle, 0);
+ }
+ }
+
+ if (capturing) {
+ if (snd_pcm_open (&driver->capture_handle,
+ capture_ioaudio_device,
+ SND_PCM_STREAM_CAPTURE,
+ SND_PCM_NONBLOCK) < 0) {
+ switch (errno) {
+ case EBUSY:
+#ifdef __ANDROID__
+ jack_error ("\n\nATTENTION: The capture (recording) device \"%s\" is "
+ "already in use",
+ capture_ioaudio_device);
+#else
+ current_apps = discover_ioaudio_using_apps ();
+ if (current_apps) {
+ jack_error ("\n\nATTENTION: The capture device \"%s\" is "
+ "already in use. The following applications "
+ " are using your soundcard(s) so you should "
+ " check them and stop them as necessary before "
+ " trying to start JACK again:\n\n%s",
+ capture_ioaudio_device,
+ current_apps);
+ free (current_apps);
+ } else {
+ jack_error ("\n\nATTENTION: The capture (recording) device \"%s\" is "
+ "already in use. Please stop the"
+ " application using it and "
+ "run JACK again",
+ capture_ioaudio_device);
+ }
+ ioaudio_driver_delete (driver);
+ return NULL;
+#endif
+ break;
+
+ case EPERM:
+ jack_error ("you do not have permission to open "
+ "the audio device \"%s\" for capture",
+ capture_ioaudio_device);
+ ioaudio_driver_delete (driver);
+ return NULL;
+ break;
+ }
+
+ driver->capture_handle = NULL;
+ }
+
+ if (driver->capture_handle) {
+ snd_pcm_nonblock (driver->capture_handle, 0);
+ }
+ }
+
+ if (driver->playback_handle == NULL) {
+ if (playing) {
+
+ /* they asked for playback, but we can't do it */
+
+ jack_error ("ALSA: Cannot open PCM device %s for "
+ "playback. Falling back to capture-only"
+ " mode", name);
+
+ if (driver->capture_handle == NULL) {
+ /* can't do anything */
+ ioaudio_driver_delete (driver);
+ return NULL;
+ }
+
+ playing = FALSE;
+ }
+ }
+
+ if (driver->capture_handle == NULL) {
+ if (capturing) {
+
+ /* they asked for capture, but we can't do it */
+
+ jack_error ("ALSA: Cannot open PCM device %s for "
+ "capture. Falling back to playback-only"
+ " mode", name);
+
+ if (driver->playback_handle == NULL) {
+ /* can't do anything */
+ ioaudio_driver_delete (driver);
+ return NULL;
+ }
+
+ capturing = FALSE;
+ }
+ }
+
+ driver->playback_hw_params = 0;
+ driver->capture_hw_params = 0;
+ driver->playback_sw_params = 0;
+ driver->capture_sw_params = 0;
+
+ if (driver->playback_handle) {
+ if ((err = snd_pcm_hw_params_malloc (
+ &driver->playback_hw_params)) < 0) {
+ jack_error ("ALSA: could not allocate playback hw"
+ " params structure");
+ ioaudio_driver_delete (driver);
+ return NULL;
+ }
+
+ if ((err = snd_pcm_sw_params_malloc (
+ &driver->playback_sw_params)) < 0) {
+ jack_error ("ALSA: could not allocate playback sw"
+ " params structure");
+ ioaudio_driver_delete (driver);
+ return NULL;
+ }
+ }
+
+ if (driver->capture_handle) {
+ if ((err = snd_pcm_hw_params_malloc (
+ &driver->capture_hw_params)) < 0) {
+ jack_error ("ALSA: could not allocate capture hw"
+ " params structure");
+ ioaudio_driver_delete (driver);
+ return NULL;
+ }
+
+ if ((err = snd_pcm_sw_params_malloc (
+ &driver->capture_sw_params)) < 0) {
+ jack_error ("ALSA: could not allocate capture sw"
+ " params structure");
+ ioaudio_driver_delete (driver);
+ return NULL;
+ }
+ }
+
+ if (ioaudio_driver_set_parameters (driver, frames_per_cycle,
+ user_nperiods, rate)) {
+ ioaudio_driver_delete (driver);
+ return NULL;
+ }
+
+ driver->capture_and_playback_not_synced = FALSE;
+
+ if (driver->capture_handle && driver->playback_handle) {
+ if (snd_pcm_link (driver->playback_handle,
+ driver->capture_handle) != 0) {
+ driver->capture_and_playback_not_synced = TRUE;
+ }
+ }
+
+ driver->client = client;
+
+ return (jack_driver_t *) driver;
+}
+
+int
+ioaudio_driver_listen_for_clock_sync_status (ioaudio_driver_t *driver,
+ ClockSyncListenerFunction func,
+ void *arg)
+{
+ ClockSyncListener *csl;
+
+ csl = (ClockSyncListener *) malloc (sizeof (ClockSyncListener));
+ csl->function = func;
+ csl->arg = arg;
+ csl->id = driver->next_clock_sync_listener_id++;
+
+ pthread_mutex_lock (&driver->clock_sync_lock);
+ driver->clock_sync_listeners =
+ jack_slist_prepend (driver->clock_sync_listeners, csl);
+ pthread_mutex_unlock (&driver->clock_sync_lock);
+ return csl->id;
+}
+
+int
+ioaudio_driver_stop_listening_to_clock_sync_status (ioaudio_driver_t *driver,
+ unsigned int which)
+
+{
+ JSList *node;
+ int ret = -1;
+ pthread_mutex_lock (&driver->clock_sync_lock);
+ for (node = driver->clock_sync_listeners; node;
+ node = jack_slist_next (node)) {
+ if (((ClockSyncListener *) node->data)->id == which) {
+ driver->clock_sync_listeners =
+ jack_slist_remove_link (
+ driver->clock_sync_listeners, node);
+ free (node->data);
+ jack_slist_free_1 (node);
+ ret = 0;
+ break;
+ }
+ }
+ pthread_mutex_unlock (&driver->clock_sync_lock);
+ return ret;
+}
+
+void
+ioaudio_driver_clock_sync_notify (ioaudio_driver_t *driver, channel_t chn,
+ ClockSyncStatus status)
+{
+ JSList *node;
+
+ pthread_mutex_lock (&driver->clock_sync_lock);
+ for (node = driver->clock_sync_listeners; node;
+ node = jack_slist_next (node)) {
+ ClockSyncListener *csl = (ClockSyncListener *) node->data;
+ csl->function (chn, status, csl->arg);
+ }
+ pthread_mutex_unlock (&driver->clock_sync_lock);
+
+}
+
+/* DRIVER "PLUGIN" INTERFACE */
+
+const char driver_client_name[] = "ioaudio_pcm";
+
+void
+driver_finish (jack_driver_t *driver)
+{
+ ioaudio_driver_delete ((ioaudio_driver_t *) driver);
+}
diff --git a/qnx/ioaudio/ioaudio_backend.h b/qnx/ioaudio/ioaudio_backend.h
new file mode 100644
index 00000000..f227fc80
--- /dev/null
+++ b/qnx/ioaudio/ioaudio_backend.h
@@ -0,0 +1,295 @@
+/*
+ Copyright (C) 2001 Paul Davis
+
+ 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.
+
+ $Id: ioaudio_driver.h 945 2006-05-04 15:14:45Z pbd $
+*/
+
+#ifndef __jack_ioaudio_driver_h__
+#define __jack_ioaudio_driver_h__
+
+#include
+#include "bitset.h"
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define IS_LE 0
+#define IS_BE 1
+#elif __BYTE_ORDER == __BIG_ENDIAN
+#define IS_LE 1
+#define IS_BE 0
+#endif
+
+#define TRUE 1
+#define FALSE 0
+
+#include "types.h"
+//#include "hardware.h"
+#include "driver.h"
+#include "memops.h"
+//#include "ioaudio_midi.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef void (*ReadCopyFunction) (jack_default_audio_sample_t *dst, char *src,
+ unsigned long src_bytes,
+ unsigned long src_skip_bytes);
+typedef void (*WriteCopyFunction) (char *dst, jack_default_audio_sample_t *src,
+ unsigned long src_bytes,
+ unsigned long dst_skip_bytes,
+ dither_state_t *state);
+
+typedef struct _snd_pcm_channel_area {
+ void *addr;
+ unsigned int first;
+ unsigned int step;
+} snd_pcm_channel_area_t;
+
+typedef struct _ioaudio_driver {
+
+ JACK_DRIVER_NT_DECL
+
+ int poll_timeout;
+ jack_time_t poll_last;
+ jack_time_t poll_next;
+ char **playback_addr;
+ char **capture_addr;
+ const snd_pcm_channel_area_t *capture_areas;
+ const snd_pcm_channel_area_t *playback_areas;
+ struct pollfd *pfd;
+ unsigned int playback_nfds;
+ unsigned int capture_nfds;
+ unsigned long interleave_unit;
+ unsigned long *capture_interleave_skip;
+ unsigned long *playback_interleave_skip;
+ channel_t max_nchannels;
+ channel_t user_nchannels;
+ channel_t playback_nchannels;
+ channel_t capture_nchannels;
+ unsigned long playback_sample_bytes;
+ unsigned long capture_sample_bytes;
+
+ jack_nframes_t frame_rate;
+ jack_nframes_t frames_per_cycle;
+ jack_nframes_t capture_frame_latency;
+ jack_nframes_t playback_frame_latency;
+
+ unsigned long *silent;
+ char *ioaudio_name_playback;
+ char *ioaudio_name_capture;
+ char *ioaudio_driver;
+ bitset_t channels_not_done;
+ bitset_t channels_done;
+ snd_pcm_format_t playback_sample_format;
+ snd_pcm_format_t capture_sample_format;
+ float max_sample_val;
+ unsigned long user_nperiods;
+ unsigned int playback_nperiods;
+ unsigned int capture_nperiods;
+ unsigned long last_mask;
+ snd_ctl_t *ctl_handle;
+ snd_pcm_t *playback_handle;
+ snd_pcm_t *capture_handle;
+ snd_pcm_channel_params_t *playback_hw_params;
+ snd_pcm_channel_params_t *playback_sw_params;
+ snd_pcm_channel_params_t *capture_hw_params;
+ snd_pcm_channel_params_t *capture_sw_params;
+ jack_hardware_t *hw;
+ ClockSyncStatus *clock_sync_data;
+ jack_client_t *client;
+ JSList *capture_ports;
+ JSList *playback_ports;
+ JSList *monitor_ports;
+
+ unsigned long input_monitor_mask;
+
+ char soft_mode;
+ char hw_monitoring;
+ char hw_metering;
+ char all_monitor_in;
+ char capture_and_playback_not_synced;
+ char playback_interleaved;
+ char capture_interleaved;
+ char with_monitor_ports;
+ char has_clock_sync_reporting;
+ char has_hw_monitoring;
+ char has_hw_metering;
+ char quirk_bswap;
+
+ ReadCopyFunction read_via_copy;
+ WriteCopyFunction write_via_copy;
+
+ int dither;
+ dither_state_t *dither_state;
+
+ SampleClockMode clock_mode;
+ JSList *clock_sync_listeners;
+ pthread_mutex_t clock_sync_lock;
+ unsigned long next_clock_sync_listener_id;
+
+ int running;
+ int run;
+
+ int poll_late;
+ int xrun_count;
+ int process_count;
+
+// ioaudio_midi_t *midi;
+ char *midi;
+ int xrun_recovery;
+
+} ioaudio_driver_t;
+
+static inline void
+ioaudio_driver_mark_channel_done (ioaudio_driver_t *driver, channel_t chn) {
+ bitset_remove (driver->channels_not_done, chn);
+ driver->silent[chn] = 0;
+}
+
+static inline void
+ioaudio_driver_silence_on_channel (ioaudio_driver_t *driver, channel_t chn,
+ jack_nframes_t nframes) {
+ if (driver->playback_interleaved) {
+ memset_interleave
+ (driver->playback_addr[chn],
+ 0, nframes * driver->playback_sample_bytes,
+ driver->interleave_unit,
+ driver->playback_interleave_skip[chn]);
+ } else {
+ memset (driver->playback_addr[chn], 0,
+ nframes * driver->playback_sample_bytes);
+ }
+ ioaudio_driver_mark_channel_done (driver,chn);
+}
+
+static inline void
+ioaudio_driver_silence_on_channel_no_mark (ioaudio_driver_t *driver, channel_t chn,
+ jack_nframes_t nframes) {
+ if (driver->playback_interleaved) {
+ memset_interleave
+ (driver->playback_addr[chn],
+ 0, nframes * driver->playback_sample_bytes,
+ driver->interleave_unit,
+ driver->playback_interleave_skip[chn]);
+ } else {
+ memset (driver->playback_addr[chn], 0,
+ nframes * driver->playback_sample_bytes);
+ }
+}
+
+static inline void
+ioaudio_driver_read_from_channel (ioaudio_driver_t *driver,
+ channel_t channel,
+ jack_default_audio_sample_t *buf,
+ jack_nframes_t nsamples)
+{
+ driver->read_via_copy (buf,
+ driver->capture_addr[channel],
+ nsamples,
+ driver->capture_interleave_skip[channel]);
+}
+
+static inline void
+ioaudio_driver_write_to_channel (ioaudio_driver_t *driver,
+ channel_t channel,
+ jack_default_audio_sample_t *buf,
+ jack_nframes_t nsamples)
+{
+ driver->write_via_copy (driver->playback_addr[channel],
+ buf,
+ nsamples,
+ driver->playback_interleave_skip[channel],
+ driver->dither_state+channel);
+ ioaudio_driver_mark_channel_done (driver, channel);
+}
+
+void ioaudio_driver_silence_untouched_channels (ioaudio_driver_t *driver,
+ jack_nframes_t nframes);
+void ioaudio_driver_set_clock_sync_status (ioaudio_driver_t *driver, channel_t chn,
+ ClockSyncStatus status);
+int ioaudio_driver_listen_for_clock_sync_status (ioaudio_driver_t *,
+ ClockSyncListenerFunction,
+ void *arg);
+int ioaudio_driver_stop_listen_for_clock_sync_status (ioaudio_driver_t *,
+ unsigned int);
+void ioaudio_driver_clock_sync_notify (ioaudio_driver_t *, channel_t chn,
+ ClockSyncStatus);
+
+int
+ioaudio_driver_reset_parameters (ioaudio_driver_t *driver,
+ jack_nframes_t frames_per_cycle,
+ jack_nframes_t user_nperiods,
+ jack_nframes_t rate);
+
+jack_driver_t *
+ioaudio_driver_new (char *name, char *playback_ioaudio_device,
+ char *capture_ioaudio_device,
+ jack_client_t *client,
+ jack_nframes_t frames_per_cycle,
+ jack_nframes_t user_nperiods,
+ jack_nframes_t rate,
+ int hw_monitoring,
+ int hw_metering,
+ int capturing,
+ int playing,
+ DitherAlgorithm dither,
+ int soft_mode,
+ int monitor,
+ int user_capture_nchnls,
+ int user_playback_nchnls,
+ int shorts_first,
+ jack_nframes_t capture_latency,
+ jack_nframes_t playback_latency /*,
+ ioaudio_midi_t *midi_driver */
+ );
+void
+ioaudio_driver_delete (ioaudio_driver_t *driver);
+
+int
+ioaudio_driver_start (ioaudio_driver_t *driver);
+
+int
+ioaudio_driver_stop (ioaudio_driver_t *driver);
+
+jack_nframes_t
+ioaudio_driver_wait (ioaudio_driver_t *driver, int extra_fd, int *status, float
+ *delayed_usecs);
+
+int
+ioaudio_driver_read (ioaudio_driver_t *driver, jack_nframes_t nframes);
+
+int
+ioaudio_driver_write (ioaudio_driver_t* driver, jack_nframes_t nframes);
+
+jack_time_t jack_get_microseconds(void);
+
+// Code implemented in JackioaudioDriver.cpp
+
+void ReadInput(jack_nframes_t orig_nframes, ssize_t contiguous, ssize_t nread);
+void MonitorInput();
+void ClearOutput();
+void WriteOutput(jack_nframes_t orig_nframes, ssize_t contiguous, ssize_t nwritten);
+void SetTime(jack_time_t time);
+int Restart();
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* __jack_ioaudio_driver_h__ */
diff --git a/qnx/wscript b/qnx/wscript
index 00f23e50..ff8c045e 100644
--- a/qnx/wscript
+++ b/qnx/wscript
@@ -41,3 +41,11 @@ def build(bld):
deva = create_jack_driver_obj(bld, 'jack', 'ioaudio/ioaudio_driver.c', ['IOAUDIO', 'clientlib', 'PTHREAD'])
deva.env['cxxshlib_PATTERN'] = 'deva-ctrl-%s.so'
deva.install_path = '/lib/dll'
+
+ ioaudio_driver_src = [
+ 'ioaudio/JackIoAudioDriver.cpp',
+ '../common/memops.c',
+ 'ioaudio/ioaudio_backend.c',
+ ]
+ create_jack_driver_obj(bld, 'ioaudio', ioaudio_driver_src, ['IOAUDIO', 'PTHREAD'])
+
\ No newline at end of file