From 70573282a5bb11796d5448173593646455e83aef Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Tue, 15 Dec 2015 15:54:38 -0600 Subject: [PATCH 1/6] Add Jack IoAudio Driver Backend --- .cproject | 54 + .project | 27 + qnx/driver.h | 300 ++++ qnx/ioaudio/JackIoAudioDriver.cpp | 940 ++++++++++++ qnx/ioaudio/JackIoAudioDriver.h | 112 ++ qnx/ioaudio/bitset.h | 132 ++ qnx/ioaudio/ioaudio_backend.c | 2308 +++++++++++++++++++++++++++++ qnx/ioaudio/ioaudio_backend.h | 295 ++++ qnx/wscript | 8 + 9 files changed, 4176 insertions(+) create mode 100644 .cproject create mode 100644 .project create mode 100644 qnx/driver.h create mode 100644 qnx/ioaudio/JackIoAudioDriver.cpp create mode 100644 qnx/ioaudio/JackIoAudioDriver.h create mode 100644 qnx/ioaudio/bitset.h create mode 100644 qnx/ioaudio/ioaudio_backend.c create mode 100644 qnx/ioaudio/ioaudio_backend.h 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 From fc788c9c6a0b98e9ef0fd8dcc961d43d66100439 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Wed, 6 Jan 2016 14:55:17 -0600 Subject: [PATCH 2/6] Iteration 2 --- .cproject | 96 +- .project | 13 + .settings/language.settings.xml | 11 + .settings/org.eclipse.cdt.codan.core.prefs | 69 + .settings/org.eclipse.cdt.core.prefs | 18 + .settings/org.eclipse.core.resources.prefs | 7 + install.sh | 4 + jack2.sh | 173 + qnx/ioaudio/JackIoAudioDriver.cpp | 1929 ++++++---- qnx/ioaudio/JackIoAudioDriver.h | 19 +- qnx/ioaudio/bitset.h | 2 + qnx/ioaudio/generic.h | 37 + qnx/ioaudio/generic_hw.c | 56 + qnx/ioaudio/hardware.h | 75 + qnx/ioaudio/ioaudio_backend.c | 3855 ++++++++++---------- qnx/ioaudio/ioaudio_backend.h | 593 +-- qnx/wscript | 3 +- 17 files changed, 4002 insertions(+), 2958 deletions(-) create mode 100644 .settings/language.settings.xml create mode 100644 .settings/org.eclipse.cdt.codan.core.prefs create mode 100644 .settings/org.eclipse.cdt.core.prefs create mode 100644 .settings/org.eclipse.core.resources.prefs create mode 100755 install.sh create mode 100755 jack2.sh create mode 100644 qnx/ioaudio/generic.h create mode 100644 qnx/ioaudio/generic_hw.c create mode 100644 qnx/ioaudio/hardware.h diff --git a/.cproject b/.cproject index 3cad824b..b326155f 100644 --- a/.cproject +++ b/.cproject @@ -7,48 +7,108 @@ - + + + - + - - + + + + + + + + + + + + + + + + + + sh + jack2.sh + install + true + true + true + + - diff --git a/.project b/.project index 819bdba9..bc6650cf 100644 --- a/.project +++ b/.project @@ -5,6 +5,11 @@ + + org.python.pydev.PyDevBuilder + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder clean,full,incremental, @@ -23,5 +28,13 @@ org.eclipse.cdt.core.ccnature org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + org.python.pydev.pythonNature + + + out + 2 + /home/coopera/Developer/gear/out/sdkbuild/build/target/jack2 + + diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml new file mode 100644 index 00000000..37a3b954 --- /dev/null +++ b/.settings/language.settings.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/.settings/org.eclipse.cdt.codan.core.prefs b/.settings/org.eclipse.cdt.codan.core.prefs new file mode 100644 index 00000000..1b60eb09 --- /dev/null +++ b/.settings/org.eclipse.cdt.codan.core.prefs @@ -0,0 +1,69 @@ +eclipse.preferences.version=1 +org.eclipse.cdt.codan.checkers.errnoreturn=-Warning +org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} +org.eclipse.cdt.codan.checkers.errreturnvalue=-Error +org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.checkers.noreturn=-Error +org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} +org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=-Error +org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem=-Error +org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=-Error +org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false} +org.eclipse.cdt.codan.internal.checkers.CatchByReference=-Warning +org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},unknown\=>false,exceptions\=>()} +org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=-Error +org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization=-Warning +org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},skip\=>true} +org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem=-Error +org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem=-Error +org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.InvalidArguments=-Error +org.eclipse.cdt.codan.internal.checkers.InvalidArguments.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem=-Error +org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem=-Error +org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem=-Error +org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem=-Error +org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker=-Info +org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},pattern\=>"^[a-z]",macro\=>true,exceptions\=>()} +org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.OverloadProblem=-Error +org.eclipse.cdt.codan.internal.checkers.OverloadProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem=-Error +org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem=-Error +org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true,exceptions\=>()} +org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},paramNot\=>false} +org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},else\=>false,afterelse\=>false} +org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem=-Error +org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true} +org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true} +org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem=-Warning +org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true,exceptions\=>("@(\#)","$Id")} +org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem=-Error +org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} +org.eclipse.cdt.qt.core.qtproblem=-Warning +org.eclipse.cdt.qt.core.qtproblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>false,RUN_ON_INC_BUILD\=>false,RUN_ON_FILE_OPEN\=>true,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} diff --git a/.settings/org.eclipse.cdt.core.prefs b/.settings/org.eclipse.cdt.core.prefs new file mode 100644 index 00000000..cbf998b3 --- /dev/null +++ b/.settings/org.eclipse.cdt.core.prefs @@ -0,0 +1,18 @@ +eclipse.preferences.version=1 +environment/project/cdt.managedbuild.toolchain.gnu.base.60399999/MAKEFLAGS/delimiter=\: +environment/project/cdt.managedbuild.toolchain.gnu.base.60399999/MAKEFLAGS/operation=append +environment/project/cdt.managedbuild.toolchain.gnu.base.60399999/MAKEFLAGS/value=-I/opt/qnx660/target/qnx6/usr/include +environment/project/cdt.managedbuild.toolchain.gnu.base.60399999/PATH/delimiter=\: +environment/project/cdt.managedbuild.toolchain.gnu.base.60399999/PATH/operation=replace +environment/project/cdt.managedbuild.toolchain.gnu.base.60399999/PATH/value=/opt/qnx660/host/linux/x86/usr/bin\:/opt/qnx660/.qnx/bin\:/opt/qnx660/jre/bin\:/opt/qnx660/host/linux/x86/usr/bin\:/opt/qnx660/.qnx/bin\:/opt/qnx660/jre/bin\:/home/coopera/.local/bin\:/usr/lib/qt-3.3/bin\:/usr/local/bin\:/usr/local/sbin\:/usr/bin\:/usr/sbin\:/bin\:/sbin +environment/project/cdt.managedbuild.toolchain.gnu.base.60399999/QNX_CONFIGURATION/delimiter=\: +environment/project/cdt.managedbuild.toolchain.gnu.base.60399999/QNX_CONFIGURATION/operation=replace +environment/project/cdt.managedbuild.toolchain.gnu.base.60399999/QNX_CONFIGURATION/value=/opt/qnx660/.qnx +environment/project/cdt.managedbuild.toolchain.gnu.base.60399999/QNX_HOST/delimiter=\: +environment/project/cdt.managedbuild.toolchain.gnu.base.60399999/QNX_HOST/operation=replace +environment/project/cdt.managedbuild.toolchain.gnu.base.60399999/QNX_HOST/value=/opt/qnx660/host/linux/x86 +environment/project/cdt.managedbuild.toolchain.gnu.base.60399999/QNX_TARGET/delimiter=\: +environment/project/cdt.managedbuild.toolchain.gnu.base.60399999/QNX_TARGET/operation=append +environment/project/cdt.managedbuild.toolchain.gnu.base.60399999/QNX_TARGET/value=/opt/qnx660/target/qnx6 +environment/project/cdt.managedbuild.toolchain.gnu.base.60399999/append=true +environment/project/cdt.managedbuild.toolchain.gnu.base.60399999/appendContributed=false diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 00000000..c2de88c1 --- /dev/null +++ b/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +encoding//common/wscript=utf-8 +encoding//example-clients/wscript=utf-8 +encoding//linux/wscript=utf-8 +encoding//tests/wscript=utf-8 +encoding/waf=ISO8859-1 +encoding/wscript=utf-8 diff --git a/install.sh b/install.sh new file mode 100755 index 00000000..501a5e6a --- /dev/null +++ b/install.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +rsync -ai --exclude=usr/share /home/coopera/Developer/gear/out/sdkbuild/install/target/jack2/ /home/coopera/Developer/gear/out/sdkbuild/staging/target/ +rsync -ai --exclude=usr/share --exclude='*.sym' --exclude='*.h' /home/coopera/Developer/gear/out/sdkbuild/install/target/jack2/ /mnt/gear/ diff --git a/jack2.sh b/jack2.sh new file mode 100755 index 00000000..a15e5800 --- /dev/null +++ b/jack2.sh @@ -0,0 +1,173 @@ +#!/bin/sh + +export NOCLIMB=1 +export OUT_DIR=/home/coopera/Developer/gear/out/sdkbuild +export PKG=jack2 + +if [ -z $QNX_VERSION ]; then + QNX_VERSION=660 +fi + +setup_dirs() { + # Set up the package's fetch and build directories + FETCH_ROOT=$OUT_DIR/fetch + BUILD_ROOT=$OUT_DIR/build + HOST_BUILD_ROOT=$BUILD_ROOT/host + TARGET_BUILD_ROOT=$BUILD_ROOT/target + INSTALL_ROOT=$OUT_DIR/install + HOST_INSTALL_ROOT=$INSTALL_ROOT/host + TARGET_INSTALL_ROOT=$INSTALL_ROOT/target + STAGING_DIR=$OUT_DIR/staging + HOST_STAGING_DIR=$STAGING_DIR/host + TARGET_STAGING_DIR=$STAGING_DIR/target + ARCHIVE_DIR=$OUT_DIR/archive + mkdir -p $HOST_INSTALL_ROOT $TARGET_INSTALL_ROOT +} + +setup_platform() { + + # Determine the platform we are running on + case $(uname -s) in + *MINGW* ) + if [ -z $(which gcc) ]; then + echo "This script must be run from a MinGW shell." + exit 1 + fi + PLATFORM=win32 + + # Put the win32 wrapper directory into the path + WIN32=$ROOT/win32 + QNX_PATH=$WIN32/qnx${QNX_VERSION} + export PATH=$WIN32:$QNX_PATH:$PATH + + ;; + + *Linux* ) + PLATFORM=linux + QNX_PATH=/opt/qnx${QNX_VERSION} + ;; + esac + + # Aggressively error out (even if the current command is for a host + # portion of the build) + if [ ! -d $QNX_PATH ]; then + echo "Unsupported QNX version $QNX_VERSION" + exit 1 + fi + + # SDP 6.6.0 has a shell programming construct in its /opt/qnx660-env.sh + # script that 'set -e' doesn't like. We have to temporarily disable it. + case "$-" in + *e* ) + set +e + . $QNX_PATH/qnx${QNX_VERSION}-env.sh + set -e + ;; + * ) + . $QNX_PATH/qnx${QNX_VERSION}-env.sh + ;; + esac +} + +# Set up the build environment for either a host- or cross-build +setup_env() { + local type=$1 + case $type in + host ) + export PKG_CONFIG_LIBDIR=$HOST_STAGING_DIR/usr/lib/pkgconfig + if [ $PLATFORM != win32 ]; then + # Windows pkg-config will auto-guess the sysroot + export PKG_CONFIG_SYSROOT_DIR=$HOST_STAGING_DIR + fi + export CPPFLAGS=-I$HOST_STAGING_DIR/usr/include + export LDFLAGS=-L$HOST_STAGING_DIR/usr/lib + export OBJCOPY=objcopy + export STRIP=strip + export READELF=readelf + unset CC + unset CXX + unset LD + + case $PLATFORM in + linux ) + export CFLAGS="-m32" + export CXXFLAGS="-m32" + export LDFLAGS="$LDFLAGS -m32" + ;; + * ) + unset CFLAGS + unset CXXFLAGS + esac + ;; + target ) + case $QNX_VERSION in + platform8 ) + export QNX_TRIPLET=arm-unknown-nto-qnx8.0.0eabi + ;; + 660 ) + export QNX_TRIPLET=arm-unknown-nto-qnx6.6.0eabi + ;; + * ) + echo "Unsupported QNX version $QNX_VERSION" + exit 1 + ;; + esac + + export PKG_CONFIG_LIBDIR=$TARGET_STAGING_DIR/usr/lib/pkgconfig + if [ $PLATFORM != win32 ]; then + # Windows pkg-config will auto-guess the sysroot + export PKG_CONFIG_SYSROOT_DIR=$TARGET_STAGING_DIR + fi + export AR=${QNX_TRIPLET}-ar + export CPPFLAGS=-I$TARGET_STAGING_DIR/usr/include + export LDFLAGS=-L$TARGET_STAGING_DIR/usr/lib + + #export CC="qcc -Vgcc_ntoarmv7le" + #export CXX="qcc -Vgcc_ntoarmv7le -lang-c++" + export CC=${QNX_TRIPLET}-gcc + export CXX=${QNX_TRIPLET}-g++ + export LD=${QNX_TRIPLET}-ld + export OBJCOPY=${QNX_TRIPLET}-objcopy + export STRIP=${QNX_TRIPLET}-strip + export READELF=${QNX_TRIPLET}-readelf + export CFLAGS="-g -funwind-tables" + unset CXXFLAGS + ;; + esac + + export PKG_CONFIG_ALLOW_SYSTEM_CFLAGS=1 + export PKG_CONFIG_ALLOW_SYSTEM_LIBS=1 + export PATH=$HOST_STAGING_DIR/usr/bin:$PATH + + if [ $PLATFORM = win32 ]; then + # Windows pkg-config does not supply a pkg.m4 file to aclocal, so we must supply our own + export ACLOCAL_FLAGS="-I $ROOT/aclocal" + fi +} + +setup_dirs +setup_platform +setup_env target + +# Set up all of the directories +FETCH_DIR=$FETCH_ROOT/$PKG +HOST_BUILD_DIR=$HOST_BUILD_ROOT/$PKG +TARGET_BUILD_DIR=$TARGET_BUILD_ROOT/$PKG +HOST_INSTALL_DIR=$HOST_INSTALL_ROOT/$PKG +TARGET_INSTALL_DIR=$TARGET_INSTALL_ROOT/$PKG +mkdir -p $HOST_BUILD_DIR $TARGET_BUILD_DIR $HOST_INSTALL_DIR $TARGET_INSTALL_DIR $HOST_STAGING_DIR $TARGET_STAGING_DIR + +exec ./waf \ + --debug\ + --out=${TARGET_BUILD_DIR}\ + --prefix=/usr\ + --destdir=${TARGET_INSTALL_DIR}\ + --dist-target=qnx\ + --doxygen=no\ + --samplerate=yes\ + --sndfile=yes\ + --ioaudio=yes\ + --check-cxx-compiler=qcc\ + --check-c-compiler=qcc\ + --ports-per-application=16\ + configure "$@" diff --git a/qnx/ioaudio/JackIoAudioDriver.cpp b/qnx/ioaudio/JackIoAudioDriver.cpp index 7e2d22be..a4e313c3 100644 --- a/qnx/ioaudio/JackIoAudioDriver.cpp +++ b/qnx/ioaudio/JackIoAudioDriver.cpp @@ -1,25 +1,24 @@ /* -Copyright (C) 2001 Paul Davis -Copyright (C) 2004 Grame + 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 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. + 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. + 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 @@ -48,248 +47,322 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #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 } -}; + { + { + "none", + "no MIDI driver" + }, + { + "seq", + "io-audio Sequencer driver" + }, + { + "raw", + "io-audio RawMIDI driver" + }, + { + 0 + } + }; static struct jack_constraint_enum_char_descriptor dither_constraint_descr_array[] = -{ - { 'n', "none" }, - { 'r', "rectangular" }, - { 's', "shaped" }, - { 't', "triangular" }, - { 0 } -}; + { + { + '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); + 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 + // io-audio 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; } - return res; -} + void JackIoAudioDriver::UpdateLatencies() + { + jack_latency_range_t range; + ioaudio_driver_t* ioaudio_driver = (ioaudio_driver_t*)fDriver; -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 < 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 ); + } + } } - 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]; -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 ); - assert(fCaptureChannels < DRIVER_PORT_NUM); - assert(fPlaybackChannels < DRIVER_PORT_NUM); + ioaudio_driver_t* ioaudio_driver = (ioaudio_driver_t*)fDriver; - ioaudio_driver_t* ioaudio_driver = (ioaudio_driver_t*)fDriver; + if( ioaudio_driver->has_hw_monitoring ) + port_flags |= JackPortCanMonitor; - if (ioaudio_driver->has_hw_monitoring) - port_flags |= JackPortCanMonitor; + // io-audio driver may have changed the values + JackAudioDriver::SetBufferSize( ioaudio_driver->frames_per_cycle ); + JackAudioDriver::SetSampleRate( ioaudio_driver->frame_rate ); - // 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 ); - 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 ); + } - 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; - 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 ); - 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; + // 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("io-audio: cannot register monitor port for %s", name); + } + else + { + fMonitorPortList[i] = port_index; + } + } } - } - } - UpdateLatencies(); + UpdateLatencies(); // if (ioaudio_driver->midi) { // int err = (ioaudio_driver->midi->attach)(ioaudio_driver->midi); // if (err) -// jack_error ("IoAudio: cannot attach MIDI: %d", err); +// jack_error ("io-audio: cannot attach MIDI: %d", err); // } - return 0; -} + return 0; + } -int JackIoAudioDriver::Detach() -{ - ioaudio_driver_t* ioaudio_driver = (ioaudio_driver_t*)fDriver; + 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; + return JackAudioDriver::Detach(); } - 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; - } +//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) + int JackIoAudioDriver::Open( + ioaudio_driver_args_t args ) + { + // Generic JackAudioDriver Open + if( JackAudioDriver::Open( args.frames_per_interrupt, + args.srate, + args.capture, + args.playback, + args.user_capture_nchnls, + args.user_playback_nchnls, + args.monitor, + args.capture_pcm_name, + args.playback_pcm_name, + args.systemic_input_latency, + args.systemic_output_latency ) != 0 ) + { + return -1; + } // ioaudio_midi_t *midi = 0; //#ifndef __ANDROID__ @@ -299,642 +372,952 @@ int JackIoAudioDriver::Open(jack_nframes_t nframes, // 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( JackServerGlobals::on_device_acquire != NULL ) + { + int capture_card = snd_card_name( args.capture_pcm_name ); + int playback_card = snd_card_name( args.playback_pcm_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); + 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...", + args.capture_pcm_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...", + args.playback_pcm_name ); + if( capture_card >= 0 ) + { + snprintf( audio_name, + sizeof( audio_name ), + "Audio%d", + capture_card ); + JackServerGlobals::on_device_release( audio_name ); + } + return -1; + } } - 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; + + fDriver = ioaudio_driver_new( (char*)"ioaudio_pcm", + NULL, + args ); +// (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 ) + { + // io-audio driver may have changed the in/out values + fCaptureChannels = + ( (ioaudio_driver_t *)fDriver )->capture_setup.format.voices; + fPlaybackChannels = + ( (ioaudio_driver_t *)fDriver )->playback_setup.format.voices; + return 0; + } + else + { + JackAudioDriver::Close(); + return -1; + } } -} -int JackIoAudioDriver::Close() -{ - // Generic audio driver close - int res = JackAudioDriver::Close(); + int JackIoAudioDriver::Close() + { + // Generic audio driver close + int res = JackAudioDriver::Close(); - ioaudio_driver_delete((ioaudio_driver_t*)fDriver); + 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); - } + if( JackServerGlobals::on_device_release != NULL ) + { + char audio_name[32]; + int capture_card = snd_card_name( 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); - } - } + int playback_card = snd_card_name( 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; -} + 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::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; + int JackIoAudioDriver::Stop() + { + int res = ioaudio_driver_stop( (ioaudio_driver_t *)fDriver ); + if( JackAudioDriver::Stop() < 0 ) + { + res = -1; + } + return res; } - return res; -} -int JackIoAudioDriver::Read() -{ - /* Taken from ioaudio_driver_run_cycle */ - int wait_status; - jack_nframes_t nframes; - fDelayedUsecs = 0.f; + int JackIoAudioDriver::Read() + { + /* Taken from ioaudio_driver_run_cycle */ + int wait_status; + jack_nframes_t nframes; + fDelayedUsecs = 0.f; -retry: + retry: - nframes = ioaudio_driver_wait((ioaudio_driver_t *)fDriver, -1, &wait_status, &fDelayedUsecs); + nframes = ioaudio_driver_wait( (ioaudio_driver_t *)fDriver, + -1, + &wait_status, + &fDelayedUsecs ); - if (wait_status < 0) - return -1; /* driver failed */ + 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 == 0 ) + { + /* we detected an xrun and restarted: notify + * clients about the delay. + */ + jack_log( "io-audio 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); + if( nframes != fEngineControl->fBufferSize ) + jack_log( + "JackIoAudioDriver::Read warning fBufferSize = %ld nframes = %ld", + fEngineControl->fBufferSize, + nframes ); - // Has to be done before read - JackDriver::CycleIncTime(); + // Has to be done before read + JackDriver::CycleIncTime(); - return ioaudio_driver_read((ioaudio_driver_t *)fDriver, fEngineControl->fBufferSize); -} + return ioaudio_driver_read( (ioaudio_driver_t *)fDriver, + fEngineControl->fBufferSize ); + } -int JackIoAudioDriver::Write() -{ - return ioaudio_driver_write((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::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::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::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::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)); + 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::is_realtime() const + { + return fEngineControl->fRealTime; + } -int JackIoAudioDriver::create_thread(pthread_t *thread, int priority, int realtime, void *(*start_routine)(void*), void *arg) -{ + 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); + return JackAndroidThread::StartImp(thread, priority, realtime, start_routine, arg); #else - return JackPosixThread::StartImp(thread, priority, realtime, start_routine, arg); + 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; -} + 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); -} + 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); -} + 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); -} + 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::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::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(); -} + 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 ) + static jack_driver_param_constraint_desc_t * + enum_ioaudio_devices() + { + snd_ctl_t * handle; + snd_ctl_hw_info_t hwinfo; + snd_pcm_info_t pcminfo; + int card_no = -1; + jack_driver_param_value_t card_id; + jack_driver_param_value_t device_id; + char description[64]; + uint32_t 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 cards_over = 0; + int numcards = snd_cards_list( NULL, + 0, + &cards_over ); + int* cards = static_cast( malloc( cards_over * sizeof(int) ) ); + numcards = snd_cards_list( cards, + cards_over, + &cards_over ); + + for( int c = 0; c < numcards; ++c ) { - 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; + card_no = cards[c]; - 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) + if( snd_ctl_open( &handle, + card_no ) >= 0 + && snd_ctl_hw_info( handle, + &hwinfo ) >= 0 ) { - 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)) + strncpy( card_id.str, + hwinfo.id, + sizeof( card_id.str ) ); + strncpy( description, + hwinfo.longname, + sizeof( description ) ); + if( !jack_constraint_add_enum( &constraint_ptr, + &array_size, + &card_id, + description ) ) goto fail; - } - - snd_ctl_close(handle); - } - } - return constraint_ptr; -fail: - jack_constraint_free(constraint_ptr); - return NULL; -} + device_no = -1; + + for( device_no = 0; device_no < hwinfo.pcmdevs; ++device_no ) + { + snprintf( device_id.str, + sizeof( device_id.str ), + "%s,%d", + card_id.str, + device_no ); + + snd_ctl_pcm_info( handle, + device_no, + &pcminfo ); + has_capture = pcminfo.flags & SND_PCM_INFO_CAPTURE; + has_playback = pcminfo.flags & SND_PCM_INFO_PLAYBACK; + + if( has_capture && has_playback ) + { + snprintf( description, + sizeof( description ), + "%s (duplex)", + pcminfo.name ); + } + else if( has_capture ) + { + snprintf( description, + sizeof( description ), + "%s (capture)", + pcminfo.name ); + } + else if( has_playback ) + { + snprintf( description, + sizeof( description ), + "%s (playback)", + pcminfo.name ); + } + else + { + continue; + } + + if( !jack_constraint_add_enum( &constraint_ptr, + &array_size, + &device_id, + description ) ) + goto fail; + } + + snd_ctl_close( handle ); + } + } -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 constraint_ptr; + fail: jack_constraint_free( constraint_ptr ); + return NULL; } - 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); - } + static int dither_opt( + char c, + DitherAlgorithm* dither ) + { + switch( c ) + { + case '-': + case 'n': + *dither = None; break; - case 'D': - playback = TRUE; - capture = TRUE; + case 'r': + *dither = Rectangular; 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); - } + case 's': + *dither = Shaped; break; - case 'H': - hw_monitoring = param->value.i; + case 't': + *dither = Triangular; break; - case 'm': - monitor = param->value.i; - break; + default: + fprintf( stderr, + "io-audio driver: illegal dithering mode %c\n", + c ); + return -1; + } + return 0; + } - case 'M': - hw_metering = param->value.i; - break; + 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( "io-audio", + JackDriverMaster, + "QNX io-audio API based audio backend", + &filler ); + + strcpy( value.str, + "pcmPreferredp" ); +#ifdef __ANDROID__ + jack_driver_descriptor_add_parameter(desc, &filler, "device", 'd', JackDriverParamString, &value, NULL, "io-audio device name", NULL); +#else + jack_driver_descriptor_add_parameter( desc, + &filler, + "device", + 'd', + JackDriverParamString, + &value, + enum_ioaudio_devices(), + "io-audio device name", + NULL ); +#endif - case 'r': - srate = param->value.ui; - jack_log("apparent rate = %d", srate); - break; + 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 ), + "io-audio MIDI driver", + NULL ); + + return desc; + } - case 'p': - frames_per_interrupt = param->value.ui; - jack_log("frames per period = %d", frames_per_interrupt); - break; + static Jack::JackIoAudioDriver* g_ioaudio_driver; - case 'n': - user_nperiods = param->value.ui; - if (user_nperiods < 2) { /* enforce minimum value */ - user_nperiods = 2; - } - break; + SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize( + Jack::JackLockedEngine* engine, + Jack::JackSynchro* table, + const JSList* params ) + { + ioaudio_driver_args_t args; + args.srate = 48000; + args.frames_per_interrupt = 1024; + args.user_nperiods = 2; + args.playback_pcm_name = "pcmPreferredp"; + args.capture_pcm_name = "pcmPreferredc"; + args.hw_monitoring = FALSE; + args.hw_metering = FALSE; + args.capture = FALSE; + args.playback = FALSE; + args.soft_mode = FALSE; + args.monitor = FALSE; + args.dither = None; + args.user_capture_nchnls = 0; + args.user_playback_nchnls = 0; + args.shorts_first = FALSE; + args.systemic_input_latency = 0; + args.systemic_output_latency = 0; + args.midi_driver = "none"; + + const JSList * node; + const jack_driver_param_t * param; + + for( node = params; node; node = jack_slist_next( node ) ) + { + param = (const jack_driver_param_t *)node->data; - case 's': - soft_mode = param->value.i; - break; + switch( param->character ) + { - case 'z': - if (dither_opt (param->value.c, &dither)) { - return NULL; + case 'C': + args.capture = TRUE; + if( strcmp( param->value.str, + "none" ) != 0 ) + { + args.capture_pcm_name = strdup( param->value.str ); + jack_log( "capture device %s", + args.capture_pcm_name ); + } + break; + + case 'P': + args.playback = TRUE; + if( strcmp( param->value.str, + "none" ) != 0 ) + { + args.playback_pcm_name = strdup( param->value.str ); + jack_log( "playback device %s", + args.playback_pcm_name ); + } + break; + + case 'D': + args.playback = TRUE; + args.capture = TRUE; + break; + + case 'd': + if( strcmp( param->value.str, + "none" ) != 0 ) + { + args.playback_pcm_name = strdup( param->value.str ); + args.capture_pcm_name = strdup( param->value.str ); + jack_log( "playback device %s", + args.playback_pcm_name ); + jack_log( "capture device %s", + args.capture_pcm_name ); + } + break; + + case 'H': + args.hw_monitoring = param->value.i; + break; + + case 'm': + args.monitor = param->value.i; + break; + + case 'M': + args.hw_metering = param->value.i; + break; + + case 'r': + args.srate = param->value.ui; + jack_log( "apparent rate = %d", + args.srate ); + break; + + case 'p': + args.frames_per_interrupt = param->value.ui; + jack_log( "frames per period = %d", + args.frames_per_interrupt ); + break; + + case 'n': + args.user_nperiods = param->value.ui; + if( args.user_nperiods < 2 ) + { /* enforce minimum value */ + args.user_nperiods = 2; + } + break; + + case 's': + args.soft_mode = param->value.i; + break; + + case 'z': + if( dither_opt( param->value.c, + &args.dither ) ) + { + return NULL; + } + break; + + case 'i': + args.user_capture_nchnls = param->value.ui; + break; + + case 'o': + args.user_playback_nchnls = param->value.ui; + break; + + case 'S': + args.shorts_first = param->value.i; + break; + + case 'I': + args.systemic_input_latency = param->value.ui; + break; + + case 'O': + args.systemic_output_latency = param->value.ui; + break; + + case 'X': + args.midi_driver = strdup( param->value.str ); + break; } - 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; + /* duplex is the default */ + if( !args.capture && !args.playback ) + { + args.capture = TRUE; + args.playback = TRUE; + } - case 'I': - systemic_input_latency = param->value.ui; - break; + g_ioaudio_driver = new Jack::JackIoAudioDriver( "system", + "ioaudio_pcm", + engine, + table ); + Jack::JackDriverClientInterface* threaded_driver = + new Jack::JackThreadedDriver( g_ioaudio_driver ); + // Special open for io-audio driver... + if( g_ioaudio_driver->Open( args ) == 0 ) + { + return threaded_driver; + } + else + { + delete threaded_driver; // Delete the decorated driver + return NULL; + } + } - case 'O': - systemic_output_latency = param->value.ui; - break; +// Code to be used in ioaudio_driver.c - case 'X': - midi_driver = strdup(param->value.str); - break; - } + void ReadInput( + jack_nframes_t orig_nframes, + ssize_t contiguous, + ssize_t nread ) + { + g_ioaudio_driver->ReadInputAux( orig_nframes, + contiguous, + nread ); } - - /* duplex is the default */ - if (!capture && !playback) { - capture = TRUE; - playback = TRUE; + void MonitorInput() + { + g_ioaudio_driver->MonitorInputAux(); } - - 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; + 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 ); } -} - -// 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(); + int Restart() + { + int res; + if( ( res = g_ioaudio_driver->Stop() ) == 0 ) + { + res = g_ioaudio_driver->Start(); + } + return res; } - return res; -} #ifdef __cplusplus } #endif - diff --git a/qnx/ioaudio/JackIoAudioDriver.h b/qnx/ioaudio/JackIoAudioDriver.h index d43a8446..bbb34e19 100644 --- a/qnx/ioaudio/JackIoAudioDriver.h +++ b/qnx/ioaudio/JackIoAudioDriver.h @@ -50,24 +50,7 @@ class JackIoAudioDriver : public JackAudioDriver 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 Open(ioaudio_driver_args_t args); int Close(); int Attach(); diff --git a/qnx/ioaudio/bitset.h b/qnx/ioaudio/bitset.h index 048b5fb2..434f7f60 100644 --- a/qnx/ioaudio/bitset.h +++ b/qnx/ioaudio/bitset.h @@ -34,6 +34,8 @@ #ifndef __bitset_h__ #define __bitset_h__ +#include +#include #include /* POSIX standard fixed-size types */ #include /* `#define NDEBUG' to disable */ diff --git a/qnx/ioaudio/generic.h b/qnx/ioaudio/generic.h new file mode 100644 index 00000000..ee1a8290 --- /dev/null +++ b/qnx/ioaudio/generic.h @@ -0,0 +1,37 @@ +/* + 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: generic.h,v 1.3 2005/11/23 11:24:29 letz Exp $ +*/ + +#ifndef __jack_generic_h__ +#define __jack_generic_h__ + +#ifdef __cplusplus +extern "C" +{ +#endif + + jack_hardware_t * + jack_ioaudio_generic_hw_new (ioaudio_driver_t *driver); + +#ifdef __cplusplus +} +#endif + + +#endif /* __jack_generic_h__*/ diff --git a/qnx/ioaudio/generic_hw.c b/qnx/ioaudio/generic_hw.c new file mode 100644 index 00000000..f50c90e5 --- /dev/null +++ b/qnx/ioaudio/generic_hw.c @@ -0,0 +1,56 @@ +/* + 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: generic_hw.c,v 1.2 2005/08/29 10:36:28 letz Exp $ +*/ + +#include "hardware.h" +#include "ioaudio_backend.h" + +static int generic_set_input_monitor_mask (jack_hardware_t *hw, unsigned long mask) +{ + return -1; +} + +static int generic_change_sample_clock (jack_hardware_t *hw, SampleClockMode mode) +{ + return -1; +} + +static void +generic_release (jack_hardware_t *hw) +{ + return; +} + +jack_hardware_t * +jack_ioaudio_generic_hw_new (ioaudio_driver_t *driver) + +{ + jack_hardware_t *hw; + + hw = (jack_hardware_t *) malloc (sizeof (jack_hardware_t)); + + hw->capabilities = 0; + hw->input_monitor_mask = 0; + + hw->set_input_monitor_mask = generic_set_input_monitor_mask; + hw->change_sample_clock = generic_change_sample_clock; + hw->release = generic_release; + + return hw; +} diff --git a/qnx/ioaudio/hardware.h b/qnx/ioaudio/hardware.h new file mode 100644 index 00000000..b77dc859 --- /dev/null +++ b/qnx/ioaudio/hardware.h @@ -0,0 +1,75 @@ +/* + 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: hardware.h,v 1.3 2005/11/23 11:24:29 letz Exp $ +*/ + +#ifndef __jack_hardware_h__ +#define __jack_hardware_h__ + +#include "types.h" + +typedef enum { + AutoSync, + WordClock, + ClockMaster +} SampleClockMode; + +typedef enum { + Cap_HardwareMonitoring = 0x1, + Cap_AutoSync = 0x2, + Cap_WordClock = 0x4, + Cap_ClockMaster = 0x8, + Cap_ClockLockReporting = 0x10, + Cap_HardwareMetering = 0x20 +} Capabilities; + +struct _jack_hardware; + +typedef void (*JackHardwareReleaseFunction)(struct _jack_hardware *); +typedef int (*JackHardwareSetInputMonitorMaskFunction)(struct _jack_hardware *, unsigned long); +typedef int (*JackHardwareChangeSampleClockFunction)(struct _jack_hardware *, SampleClockMode); +typedef double (*JackHardwareGetHardwarePeak)(jack_port_t *port, jack_nframes_t frames); +typedef double (*JackHardwareGetHardwarePower)(jack_port_t *port, jack_nframes_t frames); + +typedef struct _jack_hardware +{ + unsigned long capabilities; + unsigned long input_monitor_mask; + + JackHardwareChangeSampleClockFunction change_sample_clock; + JackHardwareSetInputMonitorMaskFunction set_input_monitor_mask; + JackHardwareReleaseFunction release; + JackHardwareGetHardwarePeak get_hardware_peak; + JackHardwareGetHardwarePower get_hardware_power; + void *private_hw; +} +jack_hardware_t; + +#ifdef __cplusplus +extern "C" +{ +#endif + + jack_hardware_t * jack_hardware_new (); + +#ifdef __cplusplus +} +#endif + + +#endif /* __jack_hardware_h__ */ diff --git a/qnx/ioaudio/ioaudio_backend.c b/qnx/ioaudio/ioaudio_backend.c index f974e48f..7a832ab7 100644 --- a/qnx/ioaudio/ioaudio_backend.c +++ b/qnx/ioaudio/ioaudio_backend.c @@ -1,27 +1,27 @@ /* -*- mode: c; c-file-style: "linux"; -*- */ /* - Copyright (C) 2001 Paul Davis + 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 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. + 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. - -*/ + 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 @@ -30,2270 +30,2331 @@ #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 "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 (); +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); +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) +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; + memset( driver, + 0, + sizeof( *driver ) ); } -void -jack_driver_nt_init (jack_driver_nt_t * driver) +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; + memset( driver, + 0, + sizeof( *driver ) ); } -static void -ioaudio_driver_release_channel_dependent_memory (ioaudio_driver_t *driver) +static void ioaudio_driver_release_channel_dependent_memory( + ioaudio_driver_t *driver ) { - bitset_destroy (&driver->channels_done); - bitset_destroy (&driver->channels_not_done); + 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->playback_addr ) + { + free( driver->playback_addr ); + driver->playback_addr = 0; } - if (driver->capture_addr) { - free (driver->capture_addr); - driver->capture_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->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->capture_interleave_skip ) + { + free( driver->capture_interleave_skip ); + driver->capture_interleave_skip = NULL; } - if (driver->silent) { - free (driver->silent); - driver->silent = 0; + if( driver->silent ) + { + free( driver->silent ); + driver->silent = 0; } - if (driver->dither_state) { - free (driver->dither_state); - driver->dither_state = 0; + if( driver->dither_state ) + { + free( driver->dither_state ); + driver->dither_state = 0; } } -static int -ioaudio_driver_check_capabilities (ioaudio_driver_t *driver) +static int ioaudio_driver_check_capabilities( + ioaudio_driver_t *driver ) { - return 0; + return 0; } -char* get_control_device_name(const char * device_name); - -static int -ioaudio_driver_check_card_type (ioaudio_driver_t *driver) +char* +get_control_device_name( + const char * device_name ) { - int err; - snd_ctl_hw_info_t card_info; - char * ctl_name; + char * ctl_name; + const char * comma; - ctl_name = get_control_device_name(driver->ioaudio_name_playback); + /* 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 */ - // 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); + if( strncasecmp( device_name, + "plughw:", + 7 ) == 0 ) + { + /* skip the "plug" prefix" */ + device_name += 4; } - driver->ioaudio_driver = strdup(card_info.longname); - - free(ctl_name); + 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 = strdup( device_name ); + if( ctl_name == NULL ) + { + jack_error( "strdup(\"%s\") failed.", + device_name ); + return NULL; + } + ctl_name[comma - device_name] = '\0'; + } - return ioaudio_driver_check_capabilities (driver); + return ctl_name; } -//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; -//} +static int ioaudio_driver_check_card_type( + ioaudio_driver_t *driver ) +{ + int err; + snd_ctl_hw_info_t card_info; + int play_card; + int cap_card; + + play_card = snd_card_name( driver->ioaudio_name_playback ); + cap_card = snd_card_name( driver->ioaudio_name_capture ); + + // 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, + play_card ) ) < 0 ) + { + jack_error( "control open %d:\"%s\" (%s)", + play_card, + driver->ioaudio_name_playback, + snd_strerror( err ) ); + } + else if( ( err = snd_ctl_hw_info( driver->ctl_handle, + &card_info ) ) < 0 ) + { + jack_error( "control hardware info %d:\"%s\" (%s)", + play_card, + driver->ioaudio_name_playback, + snd_strerror( err ) ); + snd_ctl_close( driver->ctl_handle ); + } -// JACK2 -/* -static int -ioaudio_driver_usx2y_hardware (ioaudio_driver_t *driver) + driver->ioaudio_driver = strdup( card_info.longname ); + + return ioaudio_driver_check_capabilities( driver ); +} + +static int ioaudio_driver_generic_hardware( + ioaudio_driver_t *driver ) { - driver->hw = jack_ioaudio_usx2y_hw_new (driver); + driver->hw = jack_ioaudio_generic_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) +static int ioaudio_driver_hw_specific( + ioaudio_driver_t *driver, + int hw_monitoring, + int hw_metering ) { - int err; + 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; - } + if( ( err = ioaudio_driver_generic_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; - } + + 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 { - if ((err = ioaudio_driver_generic_hardware (driver)) != 0) { - return err; - } + else + { + driver->has_hw_monitoring = FALSE; + driver->hw_monitoring = FALSE; } - 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; } - - if (driver->hw->capabilities & Cap_ClockLockReporting) { - driver->has_clock_sync_reporting = TRUE; - } else { - driver->has_clock_sync_reporting = FALSE; + 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; + 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; + return 0; } -static void -ioaudio_driver_setup_io_function_pointers (ioaudio_driver_t *driver) +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; + if( driver->playback_handle ) + { + if( SND_PCM_FMT_FLOAT_LE == driver->playback_setup.format.format ) + { + driver->write_via_copy = sample_move_dS_floatLE; + } + else + { + ssize_t bytes = + snd_pcm_format_size( + driver->playback_setup.format.format, + 1 ); + switch( 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: - jack_error ("impossible sample width (%d) discovered!", - driver->playback_sample_bytes); - exit (1); + 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!", + 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; - } - } + if( driver->capture_handle ) + { + if( SND_PCM_FMT_FLOAT_LE == driver->capture_setup.format.format ) + { + driver->read_via_copy = sample_move_floatLE_sSs; + } + else + { + ssize_t bytes = + snd_pcm_format_size( + driver->capture_setup.format.format, + 1 ); + switch( 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) +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 *params, + unsigned int *nperiodsp ) { - 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}, + int err, format; + snd_pcm_channel_info_t info; + int32_t formats[] = + { + SND_PCM_SFMT_FLOAT_LE, + SND_PCM_SFMT_S32_LE, + SND_PCM_SFMT_S32_BE, + SND_PCM_SFMT_S24_LE, + SND_PCM_SFMT_S24_BE, + SND_PCM_SFMT_S16_LE, + SND_PCM_SFMT_S16_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; + info.channel = params->channel; - 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; - } - } + err = snd_pcm_channel_info( handle, + &info ); - 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( SND_PCM_CHNINFO_NONINTERLEAVE & info.flags ) + { + params->format.interleave = 0; } - - 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; + else if( SND_PCM_CHNINFO_INTERLEAVE & info.flags ) + { + params->format.interleave = 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; + if( !( SND_PCM_CHNINFO_MMAP & info.flags ) ) + { + jack_error( "io-audio: mmap-based access is not possible" + " for the %s " + "stream of this audio interface", + 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; - } + params->mode = SND_PCM_MODE_BLOCK; - 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; - } + for( format = 0; format < NUMFORMATS; ++format ) + { + if( info.formats & ( 1 << formats[format] ) ) + { + jack_info( "io-audio: final selected sample format for %s: %s", + stream_name, + snd_pcm_get_format_name( formats[format] ) ); + params->format.format = formats[format]; + break; + } + } + if( NUMFORMATS == format ) + { + jack_error( "Sorry. The audio interface \"%s\"" + " doesn't support any of the" + " hardware sample formats that" + " JACK's ioaudio-driver can use.", + device_name ); + return -1; + } + +#if defined(SND_LITTLE_ENDIAN) + driver->quirk_bswap = snd_pcm_format_big_endian(formats[format]); +#elif defined(SND_BIG_ENDIAN) + driver->quirk_bswap = snd_pcm_format_little_endian( formats[format] ); +#else + driver->quick_bswap = 0; #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; - } + params->format.rate = driver->frame_rate; - if ((err = snd_pcm_hw_params (handle, hw_params)) < 0) { - jack_error ("ALSA: cannot set hardware parameters for %s", - stream_name); - return -1; + if( 0 == params->format.voices ) + { + /*if not user-specified, try to find the maximum + * number of channels */ + params->format.voices = info.max_voices; } - 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; - } + params->start_mode = SND_PCM_START_DATA; - stop_th = *nperiodsp * driver->frames_per_cycle; - if (driver->soft_mode) { - stop_th = (size_t)-1; - } + params->stop_mode = SND_PCM_STOP_STOP; - 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; - } + params->time = 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; - } + params->buf.block.frag_size = + snd_pcm_format_size( formats[format], + driver->frames_per_cycle ); -#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 + *nperiodsp = driver->user_nperiods; + params->buf.block.frags_min = driver->user_nperiods; + params->buf.block.frags_max = driver->user_nperiods; - 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); + jack_info( "io-audio: use %d periods for %s", + *nperiodsp, + stream_name ); - if (err < 0) { - jack_error ("ALSA: cannot set avail min for %s", stream_name); - return -1; - } + int subchn_len = sizeof( params->sw_mixer_subchn_name ); + strncpy( params->sw_mixer_subchn_name, + stream_name, + subchn_len ); + params->sw_mixer_subchn_name[subchn_len - 1] = '\0'; - if ((err = snd_pcm_sw_params (handle, sw_params)) < 0) { - jack_error ("ALSA: cannot set software parameters for %s\n", - stream_name); - return -1; + if( ( err = snd_pcm_channel_params( handle, + params ) ) < 0 ) + { + jack_error( + "io-audio: cannot set hardware parameters for %s, why_failed=%d", + stream_name, + params->why_failed ); + return -1; } - return 0; + 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) +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); - } + 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 ) + { + memset( &driver->capture_params, + 0, + sizeof(snd_pcm_channel_params_t) ); + driver->capture_params.channel = SND_PCM_CHANNEL_CAPTURE; + if( ioaudio_driver_configure_stream( driver, + driver->ioaudio_name_capture, + "capture", + driver->capture_handle, + &driver->capture_params, + &driver->capture_nperiods ) ) + { + jack_error( "io-audio: cannot configure capture channel" ); + return -1; + } + driver->capture_setup.channel = SND_PCM_CHANNEL_CAPTURE; + snd_pcm_channel_setup( driver->capture_handle, + &driver->capture_setup ); + cr = driver->capture_setup.format.rate; - /* 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; + /* check the fragment size, since thats non-negotiable */ + c_period_size = driver->capture_setup.buf.block.frag_size; + + 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; + } + + /* check the sample format */ + switch( driver->capture_setup.format.format ) + { + case SND_PCM_SFMT_FLOAT_LE: + case SND_PCM_SFMT_S32_LE: + case SND_PCM_SFMT_S24_LE: + case SND_PCM_SFMT_S24_BE: + case SND_PCM_SFMT_S16_LE: + case SND_PCM_SFMT_S32_BE: + case SND_PCM_SFMT_S16_BE: + break; + + default: + jack_error( "programming error: unhandled format " + "type for capture" ); + return -1; + } + + if( driver->capture_setup.format.interleave ) + { + if( ( err = snd_pcm_mmap( driver->capture_handle, + SND_PCM_CHANNEL_CAPTURE, + &driver->capture_mmap, + &driver->capture_buffer ) ) < 0 ) + { + jack_error( "io-audio: %s: mmap areas info error", + driver->ioaudio_name_capture ); + return -1; } - - } - 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; + } } + if( driver->playback_handle ) + { + memset( &driver->playback_params, + 0, + sizeof(snd_pcm_channel_params_t) ); + driver->playback_params.channel = SND_PCM_CHANNEL_PLAYBACK; + + if( ioaudio_driver_configure_stream( driver, + driver->ioaudio_name_playback, + "playback", + driver->playback_handle, + &driver->playback_params, + &driver->playback_nperiods ) ) + { + jack_error( "io-audio: cannot configure playback channel" ); + return -1; + } + + driver->playback_setup.channel = SND_PCM_CHANNEL_PLAYBACK; + snd_pcm_channel_setup( driver->playback_handle, + &driver->playback_setup ); + pr = driver->playback_setup.format.rate; /* 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; + p_period_size = driver->playback_setup.buf.block.frag_size; + + if( p_period_size + != snd_pcm_format_size( driver->playback_setup.format.format, + 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; + } + + /* check the sample format */ + switch( driver->playback_setup.format.format ) + { + case SND_PCM_SFMT_FLOAT_LE: + case SND_PCM_SFMT_S32_LE: + case SND_PCM_SFMT_S24_LE: + case SND_PCM_SFMT_S24_BE: + case SND_PCM_SFMT_S16_LE: + case SND_PCM_SFMT_S32_BE: + case SND_PCM_SFMT_S16_BE: + break; + + default: + jack_error( "programming error: unhandled format " + "type for playback" ); + return -1; + } + + if( driver->playback_setup.format.interleave ) + { + if( ( err = snd_pcm_mmap( driver->playback_handle, + SND_PCM_CHANNEL_PLAYBACK, + &driver->playback_mmap, + &driver->playback_buffer ) ) < 0 ) + { + jack_error( "io-audio: %s: mmap areas info error", + driver->ioaudio_name_playback ); + return -1; } + driver->interleave_unit = + snd_pcm_format_size( + driver->playback_setup.format.format, + 1 ); + } + else + { + driver->interleave_unit = 0; /* NOT USED */ + } } - 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); - } + /* check the rate, since thats rather important */ + 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; } - - 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); - } + 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; } - 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_setup.format.voices + > driver->capture_setup.format.voices ) + { + driver->max_nchannels = driver->playback_setup.format.voices; + driver->user_nchannels = driver->capture_setup.format.voices; } - - 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; + else + { + driver->max_nchannels = driver->capture_setup.format.voices; + driver->user_nchannels = driver->playback_setup.format.voices; } - 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)); - } + ioaudio_driver_setup_io_function_pointers( driver ); - 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); - } + /* Allocate and initialize structures that rely on the + channels counts. - driver->clock_sync_data = (ClockSyncStatus *) - malloc (sizeof (ClockSyncStatus) * driver->max_nchannels); + 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. + */ - 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); + bitset_create( &driver->channels_done, + driver->max_nchannels ); + bitset_create( &driver->channels_not_done, + driver->max_nchannels ); -// 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; - } - } -*/ + if( driver->playback_handle ) + { + driver->playback_addr = + (char **)malloc( + sizeof(char *) + * driver->playback_setup.format.voices ); + memset( driver->playback_addr, + 0, + sizeof(char *) * driver->playback_setup.format.voices ); + driver->playback_interleave_skip = + (unsigned long *)malloc( + sizeof(unsigned long *) + * driver->playback_setup.format.voices ); + memset( driver->playback_interleave_skip, + 0, + sizeof(unsigned long *) + * driver->playback_setup.format.voices ); + driver->silent = + (unsigned long *)malloc( + sizeof(unsigned long) + * driver->playback_setup.format.voices ); + + for( chn = 0; chn < driver->playback_setup.format.voices; chn++ ) + { + driver->silent[chn] = 0; + } + + for( chn = 0; chn < driver->playback_setup.format.voices; chn++ ) + { + bitset_add( driver->channels_done, + chn ); + } + + driver->dither_state = + (dither_state_t *)calloc( + driver->playback_setup.format.voices, + sizeof(dither_state_t) ); + } + + if( driver->capture_handle ) + { + driver->capture_addr = + (char **)malloc( + sizeof(char *) + * driver->capture_setup.format.voices ); + memset( driver->capture_addr, + 0, + sizeof(char *) * driver->capture_setup.format.voices ); + driver->capture_interleave_skip = + (unsigned long *)malloc( + sizeof(unsigned long *) + * driver->capture_setup.format.voices ); + memset( driver->capture_interleave_skip, + 0, + sizeof(unsigned long *) * driver->capture_setup.format.voices ); + } + + 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_msecs = (int)floor( 1.5f * driver->period_usecs / 1000.0f ); - return 0; + 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) +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); + /* 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) +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; - } + int err; + channel_t chn; - 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); - } + if( capture_avail ) + { + if( ( err = snd_pcm_mmap( driver->capture_handle, + SND_PCM_CHANNEL_CAPTURE, + &driver->capture_mmap, + &driver->capture_buffer ) ) < 0 ) + { + jack_error( "io-audio: %s: mmap areas info error", + driver->ioaudio_name_capture ); + return -1; + } + + for( chn = 0; chn < driver->capture_setup.format.voices; chn++ ) + { + driver->capture_addr[chn] = driver->capture_buffer; + driver->capture_interleave_skip[chn] = + (unsigned long)driver->capture_mmap->status.voices; + } + } + + if( playback_avail ) + { + if( ( err = snd_pcm_mmap( driver->playback_handle, + SND_PCM_CHANNEL_PLAYBACK, + &driver->playback_mmap, + &driver->playback_buffer ) ) < 0 ) + { + jack_error( "io-audio: %s: mmap areas info error ", + driver->ioaudio_name_playback ); + return -1; + } + + for( chn = 0; chn < driver->playback_setup.format.voices; chn++ ) + { + driver->playback_addr[chn] = driver->playback_buffer; + driver->playback_interleave_skip[chn] = + (unsigned long)driver->playback_mmap->status.voices; + } } - return 0; + return 0; } -int -ioaudio_driver_start (ioaudio_driver_t *driver) +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); - } - } + int err; + size_t poffset, pavail; + channel_t chn; - if (driver->playback_handle) { - driver->playback_nfds = - snd_pcm_poll_descriptors_count (driver->playback_handle); - } else { - driver->playback_nfds = 0; - } + driver->poll_last = 0; + driver->poll_next = 0; - if (driver->capture_handle) { - driver->capture_nfds = - snd_pcm_poll_descriptors_count (driver->capture_handle); - } else { - driver->capture_nfds = 0; + if( driver->playback_handle ) + { + if( ( err = snd_pcm_playback_prepare( driver->playback_handle ) ) < 0 ) + { + jack_error( "io-audio: 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_capture_prepare( driver->capture_handle ) ) < 0 ) + { + jack_error( "io-audio: prepare error for capture on \"%s\"" + " (%s)", + driver->ioaudio_name_capture, + snd_strerror( err ) ); + return -1; + } } - if (driver->pfd) { - free (driver->pfd); + 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 ); + } } - 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( driver->playback_handle ) + { + /* fill playback buffer with zeroes, and mark + all fragments as having data. + */ - if ((err = snd_pcm_start (driver->playback_handle)) < 0) { - jack_error ("ALSA: could not start playback (%s)", - snd_strerror (err)); - return -1; - } - } +#if 0 + pavail = snd_pcm_avail_update (driver->playback_handle); +#else + pavail = driver->frames_per_cycle * driver->playback_nperiods; +#endif - 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; - } - } + if( pavail != driver->frames_per_cycle * driver->playback_nperiods ) + { + jack_error( "io-audio: 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. io-audio 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 + ioaudio-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_setup.format.voices; chn++ ) + { + ioaudio_driver_silence_on_channel( driver, + chn, + driver->user_nperiods + * driver->frames_per_cycle ); + } + + msync( driver->playback_addr, + snd_pcm_format_size( driver->playback_setup.format.format, + driver->user_nperiods + * driver->frames_per_cycle ), + MS_SYNC ); + +// if( ( err = snd_pcm_playback_go( driver->playback_handle ) ) < 0 ) +// { +// jack_error( "io-audio: 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_capture_go( driver->capture_handle ) ) < 0 ) +// { +// jack_error( "io-audio: could not start capture (%s)", +// snd_strerror( err ) ); +// return -1; +// } +// } - return 0; + return 0; } -int -ioaudio_driver_stop (ioaudio_driver_t *driver) +int ioaudio_driver_stop( + ioaudio_driver_t *driver ) { - int err; + int err; // JSList* node; // int chn; - /* silence all capture port buffers, because we might - be entering offline mode. - */ + /* 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++) { + /* + 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; + 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); - } -*/ + 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 ) + { + if( ( err = snd_pcm_playback_flush( driver->playback_handle ) ) < 0 ) + { + jack_error( "io-audio: 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->playback_handle || driver->capture_and_playback_not_synced ) + { + if( driver->capture_handle ) + { + if( ( err = snd_pcm_capture_flush( driver->capture_handle ) ) < 0 ) + { + jack_error( "io-audio: 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->hw_monitoring ) + { + driver->hw->set_input_monitor_mask( driver->hw, + 0 ); } - if (driver->midi && !driver->xrun_recovery) - (driver->midi->stop)(driver->midi); +// if (driver->midi && !driver->xrun_recovery) +// (driver->midi->stop)(driver->midi); - return 0; + return 0; } -static int -ioaudio_driver_restart (ioaudio_driver_t *driver) +static int ioaudio_driver_restart( + ioaudio_driver_t *driver ) { - int res; + int res; - driver->xrun_recovery = 1; + 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); - */ + 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; + driver->xrun_recovery = 0; - if (res && driver->midi) - (driver->midi->stop)(driver->midi); +// if (res && driver->midi) +// (driver->midi->stop)(driver->midi); - return res; + return res; } -static int -ioaudio_driver_xrun_recovery (ioaudio_driver_t *driver, float *delayed_usecs) +static int ioaudio_driver_xrun_recovery( + ioaudio_driver_t *driver, + float *delayed_usecs ) { - snd_pcm_status_t *status; - int res; + snd_pcm_channel_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( driver->capture_handle ) + { + status.channel = SND_PCM_CHANNEL_CAPTURE; + if( ( res = snd_pcm_channel_status( driver->capture_handle, + &status ) ) < 0 ) + { + jack_error( "status error: %s", + snd_strerror( res ) ); + } + } + else + { + status.channel = SND_PCM_CHANNEL_PLAYBACK; + if( ( res = snd_pcm_channel_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) + if( status.status == SND_PCM_STATUS_READY ) { - 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)); - } + jack_log( "**** ioaudio_pcm: pcm in suspended state, resuming it" ); + if( driver->capture_handle ) + { + if( ( res = snd_pcm_capture_prepare( driver->capture_handle ) ) + < 0 ) + { + jack_error( "error preparing after suspend: %s", + snd_strerror( res ) ); + } + } + else + { + if( ( res = snd_pcm_playback_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( status.status == SND_PCM_STATUS_OVERRUN + && driver->process_count > XRUN_REPORT_DELAY ) + { + struct timeval now, diff, tstamp; + driver->xrun_count++; + gettimeofday( &now, + NULL ); + tstamp = status.stop_time; + 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; } - - if (ioaudio_driver_restart (driver)) { - return -1; - } - return 0; + return 0; } -void -ioaudio_driver_silence_untouched_channels (ioaudio_driver_t *driver, - jack_nframes_t nframes) +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; - } - } + channel_t chn; + jack_nframes_t buffer_frames = driver->frames_per_cycle + * driver->playback_nperiods; + + for( chn = 0; chn < driver->playback_setup.format.voices; 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) +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); + 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) +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: + ssize_t avail = 0; + ssize_t capture_avail = 0; + ssize_t playback_avail = 0; + int xrun_detected = FALSE; + int need_capture; + int need_playback; + jack_time_t poll_enter; + jack_time_t poll_ret = 0; - while (need_playback || need_capture) { + *status = -1; + *delayed_usecs = 0; - int poll_result; - unsigned int ci = 0; - unsigned int nfds; - unsigned short revents; + need_capture = driver->capture_handle ? 1 : 0; - 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; - } + if( extra_fd >= 0 ) + { + need_playback = 0; + } + else + { + need_playback = driver->playback_handle ? 1 : 0; + } - /* ALSA doesn't set POLLERR in some versions of 0.9.X */ + again: - for (i = 0; i < nfds; i++) { - driver->pfd[i].events |= POLLERR; - } + while( need_playback || need_capture ) + { - if (extra_fd >= 0) { - driver->pfd[nfds].fd = extra_fd; - driver->pfd[nfds].events = - POLLIN|POLLERR|POLLHUP|POLLNVAL; - nfds++; - } + int poll_result; + unsigned short revents; - poll_enter = jack_get_microseconds (); + if( need_playback ) + { + int fd = snd_pcm_file_descriptor( driver->playback_handle, + SND_PCM_CHANNEL_PLAYBACK ); - 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++; + driver->pfd[SND_PCM_CHANNEL_PLAYBACK].fd = fd; + driver->pfd[SND_PCM_CHANNEL_PLAYBACK].events = POLLOUT; + } + else + { + driver->pfd[SND_PCM_CHANNEL_PLAYBACK].fd = -1; + } + + if( extra_fd >= 0 ) + { + driver->pfd[SND_PCM_CHANNEL_PLAYBACK].fd = extra_fd; + driver->pfd[SND_PCM_CHANNEL_PLAYBACK].events = POLLIN; + } + + if( need_capture ) + { + int fd = snd_pcm_file_descriptor( driver->capture_handle, + SND_PCM_CHANNEL_CAPTURE ); + + driver->pfd[SND_PCM_CHANNEL_CAPTURE].fd = fd; + driver->pfd[SND_PCM_CHANNEL_PLAYBACK].events = POLLIN; + } + else + { + driver->pfd[SND_PCM_CHANNEL_CAPTURE].fd = -1; + } + + 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++; + } + + poll_result = poll( driver->pfd, + SND_PCM_CHANNEL_MAX, + driver->poll_timeout_msecs ); + + 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; } -#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; + jack_error( "io-audio: poll call failed (%s)", + strerror( errno ) ); + *status = -3; + return 0; - } + } - poll_ret = jack_get_microseconds (); + poll_ret = jack_get_microseconds(); // JACK2 - SetTime(poll_ret); + 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); -*/ + 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); + 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 */ + /* check to see if it was the extra FD that caused us + * to return from poll */ - if (extra_fd >= 0) { + if( extra_fd >= 0 ) + { - if (driver->pfd[nfds-1].revents == 0) { - /* we timed out on the extra fd */ + if( driver->pfd[SND_PCM_CHANNEL_PLAYBACK].revents == 0 ) + // if( !FD_ISSET( extra_fd, &writefds ) ) + { + /* we timed out on the extra fd */ - *status = -4; - return -1; - } + *status = -4; + return -1; + } - /* if POLLIN was the only bit set, we're OK */ + /* if POLLIN was the only bit set, we're OK */ - *status = 0; - return (driver->pfd[nfds-1].revents == POLLIN) ? 0 : -1; - } + *status = 0; + return + ( driver->pfd[SND_PCM_CHANNEL_PLAYBACK].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( need_playback ) + { + snd_pcm_channel_status_t chstatus; + chstatus.channel = SND_PCM_CHANNEL_PLAYBACK; + snd_pcm_channel_status( driver->playback_handle, + &chstatus ); - if (revents & POLLERR) { - xrun_detected = TRUE; - } + revents = driver->pfd[SND_PCM_CHANNEL_PLAYBACK].revents; - if (revents & POLLOUT) { - need_playback = 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); + 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( need_capture ) + { + snd_pcm_channel_status_t chstatus; + chstatus.channel = SND_PCM_CHANNEL_CAPTURE; + snd_pcm_channel_status( driver->playback_handle, + &chstatus ); - if (revents & POLLERR) { - xrun_detected = TRUE; - } + revents = driver->pfd[SND_PCM_CHANNEL_CAPTURE].revents; - if (revents & POLLIN) { - need_capture = 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); + 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( poll_result == 0 ) + { + jack_error( "io-audio: 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( driver->capture_handle ) + { + capture_avail = driver->capture_setup.buf.block.frag_size + / snd_pcm_format_size( driver->capture_setup.format.format, + 1 ); + } + else + { + capture_avail = INT_MAX; } - if (xrun_detected) { - *status = ioaudio_driver_xrun_recovery (driver, delayed_usecs); - return 0; + if( driver->playback_handle ) + { + playback_avail = driver->playback_setup.buf.block.frag_size + / snd_pcm_format_size( driver->playback_setup.format.format, + 1 ); + } + else + { + /* odd, but see min() computation below */ + playback_avail = INT_MAX; } - *status = 0; - driver->last_wait_ust = poll_ret; + if( xrun_detected ) + { + *status = ioaudio_driver_xrun_recovery( driver, + delayed_usecs ); + return 0; + } - avail = capture_avail < playback_avail ? capture_avail : playback_avail; + *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); + 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 */ + /* mark all channels not done for now. read/write will change this */ - bitset_copy (driver->channels_not_done, driver->channels_done); + bitset_copy( driver->channels_not_done, + driver->channels_done ); - /* constrain the available count to the nearest (round down) number of - periods. - */ + /* constrain the available count to the nearest (round down) number of + periods. + */ - return avail - (avail % driver->frames_per_cycle); + return avail - ( avail % driver->frames_per_cycle ); } - -int -ioaudio_driver_read (ioaudio_driver_t *driver, jack_nframes_t nframes) +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; + ssize_t contiguous; + ssize_t nread; + size_t offset = 0; + jack_nframes_t orig_nframes; // jack_default_audio_sample_t* buf; // channel_t chn; // JSList *node; // jack_port_t* port; - int err; + int err; - if (nframes > driver->frames_per_cycle) { - return -1; + 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; + /* + 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; + nread = 0; + contiguous = 0; + orig_nframes = nframes; - while (nframes) { + while( nframes ) + { - contiguous = nframes; + contiguous = nframes; - if (ioaudio_driver_get_channel_addresses ( - driver, - (size_t *) &contiguous, - (size_t *) 0, - &offset, 0) < 0) { - return -1; - } + 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; + /* + 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 = msync( driver->capture_addr + offset, + contiguous, + MS_SYNC ) ) + < 0 ) + { + jack_error( "io-audio: could not complete read of %" + PRIu32 " frames: error = %d", + contiguous, + err ); + return -1; + } + + nframes -= contiguous; + nread += contiguous; } - return 0; + return 0; } -int -ioaudio_driver_write (ioaudio_driver_t* driver, jack_nframes_t nframes) +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_nframes_t orig_nframes; + ssize_t nwritten; + ssize_t contiguous; + size_t offset = 0; // jack_port_t *port; - int err; + int err; - driver->process_count++; + driver->process_count++; // JACK2 -/* - if (!driver->playback_handle || driver->engine->freewheeling) { - return 0; - } -*/ - if (!driver->playback_handle) { - return 0; + /* + if (!driver->playback_handle || driver->engine->freewheeling) { + return 0; + } + */ + if( !driver->playback_handle ) + { + return 0; } - if (nframes > driver->frames_per_cycle) { - return -1; + if( nframes > driver->frames_per_cycle ) + { + return -1; } - if (driver->midi) - (driver->midi->write)(driver->midi, nframes); +// if (driver->midi) +// (driver->midi->write)(driver->midi, nframes); - nwritten = 0; - contiguous = 0; - orig_nframes = nframes; + nwritten = 0; + contiguous = 0; + orig_nframes = nframes; - /* check current input monitor request status */ + /* check current input monitor request status */ - driver->input_monitor_mask = 0; + 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<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); - } + if( driver->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) { + while( nframes ) + { - contiguous = nframes; + contiguous = nframes; - if (ioaudio_driver_get_channel_addresses ( - driver, - (size_t *) 0, - (size_t *) &contiguous, - 0, &offset) < 0) { - return -1; - } + 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); - } - } -*/ + /* + 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; - } + WriteOutput( orig_nframes, + contiguous, + nwritten ); + + if( !bitset_empty( driver->channels_not_done ) ) + { + ioaudio_driver_silence_untouched_channels( driver, + contiguous ); + } + + if( ( err = msync( driver->playback_buffer + offset, + contiguous, + MS_SYNC ) ) + < 0 ) + { + jack_error( "io-audio: could not complete playback of %" + PRIu32 " frames: error = %d", + contiguous, + err ); + if( err != -EPIPE && err != -ESTRPIPE ) + return -1; + } - nframes -= contiguous; - nwritten += contiguous; + nframes -= contiguous; + nwritten += contiguous; } - return 0; + return 0; } #if 0 -static int /* UNUSED */ +static int /* UNUSED */ ioaudio_driver_change_sample_clock (ioaudio_driver_t *driver, SampleClockMode mode) -{ - return driver->hw->change_sample_clock (driver->hw, mode); -} + { + return driver->hw->change_sample_clock (driver->hw, mode); + } -static void /* UNUSED */ +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); - } + { + 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; -} + driver->all_monitor_in = yn; + } -static void /* UNUSED */ +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); + { + 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 */ +static ClockSyncStatus /* UNUSED */ ioaudio_driver_clock_sync_status (channel_t chn) -{ - return Lock; -} + { + return Lock; + } #endif -void -ioaudio_driver_delete (ioaudio_driver_t *driver) +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; - } + JSList *node; - if (driver->playback_handle) { - snd_pcm_close (driver->playback_handle); - driver->capture_handle = 0; - } +// if (driver->midi) +// (driver->midi->destroy)(driver->midi); - if (driver->capture_hw_params) { - snd_pcm_hw_params_free (driver->capture_hw_params); - driver->capture_hw_params = 0; + for( node = driver->clock_sync_listeners; node; + node = jack_slist_next( node ) ) + { + free( node->data ); } + jack_slist_free( driver->clock_sync_listeners ); - if (driver->playback_hw_params) { - snd_pcm_hw_params_free (driver->playback_hw_params); - driver->playback_hw_params = 0; + if( driver->ctl_handle ) + { + snd_ctl_close( driver->ctl_handle ); + driver->ctl_handle = 0; } - if (driver->capture_sw_params) { - snd_pcm_sw_params_free (driver->capture_sw_params); - driver->capture_sw_params = 0; + if( driver->capture_handle ) + { + snd_pcm_close( driver->capture_handle ); + driver->capture_handle = 0; } - if (driver->playback_sw_params) { - snd_pcm_sw_params_free (driver->playback_sw_params); - driver->playback_sw_params = 0; + if( driver->playback_handle ) + { + snd_pcm_close( driver->playback_handle ); + driver->capture_handle = 0; } - if (driver->pfd) { - free (driver->pfd); - } +// if( driver->pfd ) +// { +// free( driver->pfd ); +// } - if (driver->hw) { - driver->hw->release (driver->hw); - driver->hw = 0; + 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); + free( driver->ioaudio_name_playback ); + free( driver->ioaudio_name_capture ); + free( driver->ioaudio_driver ); - ioaudio_driver_release_channel_dependent_memory (driver); + ioaudio_driver_release_channel_dependent_memory( driver ); //JACK2 //jack_driver_nt_finish ((jack_driver_nt_t *) driver); - free (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; - } -} +//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 - ) +ioaudio_driver_new( + char *name, + jack_client_t *client, + ioaudio_driver_args_t args ) +//ioaudio_driver_new( +// char *name, +// char *playback_pcm_name, +// char *capture_pcm_name, +// jack_client_t *client, +// jack_nframes_t frames_per_interrupt, +// jack_nframes_t user_nperiods, +// jack_nframes_t srate, +// int hw_monitoring, +// int hw_metering, +// int capture, +// int playback, +// DitherAlgorithm dither, +// int soft_mode, +// int monitor, +// int user_capture_nchnls, +// int user_playback_nchnls, +// int shorts_first, +// jack_nframes_t systemic_input_latency, +// jack_nframes_t systemic_output_latency /*, +// ioaudio_midi_t *midi_driver */ +// ) { - int err; +// 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); + ioaudio_driver_t *driver; + + jack_info( "creating ioaudio driver ... %s|%s|%" PRIu32 "|%" PRIu32 + "|%" PRIu32"|%" PRIu32"|%" PRIu32 "|%s|%s|%s|%s", + args.playback ? args.playback_pcm_name : "-", + args.capture ? args.capture_pcm_name : "-", + args.frames_per_interrupt, + args.user_nperiods, + args.srate, + args.user_capture_nchnls, + args.user_playback_nchnls, + args.hw_monitoring ? "hwmon" : "nomon", + args.hw_metering ? "hwmeter" : "swmeter", + args.soft_mode ? "soft-mode" : "-", + args.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); - } + 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->user_playback_nchnls = args.user_playback_nchnls; + driver->user_capture_nchnls = args.user_capture_nchnls; + driver->capture_frame_latency = args.systemic_input_latency; + driver->playback_frame_latency = args.systemic_output_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 = args.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; + + memset( driver->pfd, + 0, + sizeof( driver->pfd ) ); + + driver->dither = args.dither; + driver->soft_mode = args.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( args.playback_pcm_name ); + driver->ioaudio_name_capture = strdup( args.capture_pcm_name ); + +// driver->midi = midi_driver; + driver->xrun_recovery = 0; + + if( ioaudio_driver_check_card_type( driver ) ) + { + ioaudio_driver_delete( driver ); + return NULL; } - if (driver->playback_handle == NULL) { - if (playing) { + ioaudio_driver_hw_specific( driver, + args.hw_monitoring, + args.hw_metering ); - /* they asked for playback, but we can't do it */ + if( args.playback ) + { + if( snd_pcm_open_name( &driver->playback_handle, + args.playback_pcm_name, + SND_PCM_OPEN_PLAYBACK | SND_PCM_OPEN_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", +// args.playback_pcm_name ); +//#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_pcm_name, +// 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_pcm_name ); +// } + jack_error( "\n\nATTENTION: The playback device \"%s\" is " + "already in use. Please stop the" + " application using it and " + "run JACK again", + args.playback_pcm_name ); + ioaudio_driver_delete( driver ); + return NULL; +//#endif + + case EPERM: + jack_error( "you do not have permission to open " + "the audio device \"%s\" for playback", + args.playback_pcm_name ); + ioaudio_driver_delete( driver ); + return NULL; + break; + } + + driver->playback_handle = NULL; + } + + if( driver->playback_handle ) + { + snd_pcm_nonblock_mode( driver->playback_handle, + 0 ); + } + } + + if( args.capture ) + { + if( snd_pcm_open_name( &driver->capture_handle, + args.capture_pcm_name, + SND_PCM_OPEN_CAPTURE | SND_PCM_OPEN_NONBLOCK ) + < 0 ) + { + switch( + errno ) + { + case EBUSY: + //#ifdef __ANDROID__ +// jack_error ("\n\nATTENTION: The capture (recording) device \"%s\" is " +// "already in use", +// capture_pcm_name); +//#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", +// args.capture_pcm_name, +// 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", +// args.capture_pcm_name ); +// } +//#endif + jack_error( + "\n\nATTENTION: The capture (recording) device \"%s\" is " + "already in use. Please stop the" + " application using it and " + "run JACK again", + args.capture_pcm_name ); + ioaudio_driver_delete( driver ); + return NULL; + break; + + case EPERM: + jack_error( "you do not have permission to open " + "the audio device \"%s\" for capture", + args.capture_pcm_name ); + ioaudio_driver_delete( driver ); + return NULL; + break; + } + + driver->capture_handle = NULL; + } + + if( driver->capture_handle ) + { + snd_pcm_nonblock_mode( driver->capture_handle, + 0 ); + } + } + + if( driver->playback_handle == NULL ) + { + if( args.playback ) + { - jack_error ("ALSA: Cannot open PCM device %s for " - "playback. Falling back to capture-only" - " mode", name); + /* they asked for playback, but we can't do it */ - if (driver->capture_handle == NULL) { - /* can't do anything */ - ioaudio_driver_delete (driver); - return NULL; - } + jack_error( "io-audio: Cannot open PCM device %s for " + "playback. Falling back to capture-only" + " mode", + name ); - playing = FALSE; + if( driver->capture_handle == NULL ) + { + /* can't do anything */ + ioaudio_driver_delete( driver ); + return NULL; } - } - - 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; - } + args.playback = FALSE; + } } - driver->playback_hw_params = 0; - driver->capture_hw_params = 0; - driver->playback_sw_params = 0; - driver->capture_sw_params = 0; + if( driver->capture_handle == NULL ) + { + if( args.capture ) + { - 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; - } + /* they asked for capture, but we can't do it */ - 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; - } - } + jack_error( "io-audio: Cannot open PCM device %s for " + "capture. Falling back to playback-only" + " mode", + name ); - 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( driver->playback_handle == NULL ) + { + /* can't do anything */ + 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; - } + args.capture = FALSE; + } } - if (ioaudio_driver_set_parameters (driver, frames_per_cycle, - user_nperiods, rate)) { - ioaudio_driver_delete (driver); - return NULL; + if( ioaudio_driver_set_parameters( driver, + args.frames_per_interrupt, + args.user_nperiods, + args.srate ) ) + { + ioaudio_driver_delete( driver ); + return NULL; } - driver->capture_and_playback_not_synced = FALSE; + 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; - } + 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; + driver->client = client; - return (jack_driver_t *) driver; + return (jack_driver_t *)driver; } -int -ioaudio_driver_listen_for_clock_sync_status (ioaudio_driver_t *driver, - ClockSyncListenerFunction func, - void *arg) +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; + 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) +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; + 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) +void ioaudio_driver_clock_sync_notify( + ioaudio_driver_t *driver, + channel_t chn, + ClockSyncStatus status ) { - JSList *node; + 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_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); + pthread_mutex_unlock( &driver->clock_sync_lock ); } @@ -2301,8 +2362,8 @@ ioaudio_driver_clock_sync_notify (ioaudio_driver_t *driver, channel_t chn, const char driver_client_name[] = "ioaudio_pcm"; -void -driver_finish (jack_driver_t *driver) +void driver_finish( + jack_driver_t *driver ) { - ioaudio_driver_delete ((ioaudio_driver_t *) driver); + ioaudio_driver_delete( (ioaudio_driver_t *)driver ); } diff --git a/qnx/ioaudio/ioaudio_backend.h b/qnx/ioaudio/ioaudio_backend.h index f227fc80..f351d085 100644 --- a/qnx/ioaudio/ioaudio_backend.h +++ b/qnx/ioaudio/ioaudio_backend.h @@ -1,27 +1,28 @@ /* - Copyright (C) 2001 Paul Davis + 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 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. + 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. + 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 $ -*/ + $Id: ioaudio_driver.h 945 2006-05-04 15:14:45Z pbd $ + */ #ifndef __jack_ioaudio_driver_h__ #define __jack_ioaudio_driver_h__ #include +#include #include "bitset.h" #if __BYTE_ORDER == __LITTLE_ENDIAN @@ -36,7 +37,7 @@ #define FALSE 0 #include "types.h" -//#include "hardware.h" +#include "hardware.h" #include "driver.h" #include "memops.h" //#include "ioaudio_midi.h" @@ -46,250 +47,340 @@ 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; + 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 _ioaudio_driver_args + { + char* device; + + char capture; + const char* capture_pcm_name; + size_t user_capture_nchnls; + + char playback; + const char* playback_pcm_name; + size_t user_playback_nchnls; + + size_t srate; + size_t frames_per_interrupt; + size_t user_nperiods; + DitherAlgorithm dither; + char hw_monitoring; + char hw_metering; + char duplex; + char soft_mode; + char monitor; + char shorts_first; + size_t systemic_input_latency; + size_t systemic_output_latency; + const char* midi_driver; + } ioaudio_driver_args_t; + + typedef struct _ioaudio_driver + { + + JACK_DRIVER_NT_DECL + + int poll_timeout_msecs; + jack_time_t poll_last; + jack_time_t poll_next; + char **playback_addr; + char **capture_addr; + struct pollfd pfd[SND_PCM_CHANNEL_MAX]; + unsigned long interleave_unit; + unsigned long *capture_interleave_skip; + unsigned long *playback_interleave_skip; + channel_t max_nchannels; + channel_t user_nchannels; + int user_capture_nchnls; + int user_playback_nchnls; + + 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; + 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_channel_params_t playback_params; + snd_pcm_channel_setup_t playback_setup; + snd_pcm_mmap_control_t *playback_mmap; + void *playback_buffer; + + snd_pcm_t *capture_handle; + snd_pcm_channel_params_t capture_params; + snd_pcm_channel_setup_t capture_setup; + snd_pcm_mmap_control_t *capture_mmap; + void *capture_buffer; + + 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 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); + 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_setup.format.interleave ) + { + memset_interleave + ( driver->playback_addr[chn], + 0, + snd_pcm_format_size( + driver->playback_setup.format.format, + nframes ), + driver->interleave_unit, + driver->playback_interleave_skip[chn] ); + } + else + { + memset( driver->playback_addr[chn], + 0, + snd_pcm_format_size( + driver->playback_setup.format.format, + nframes ) ); + } + 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_setup.format.interleave ) + { + memset_interleave + ( driver->playback_addr[chn], + 0, + snd_pcm_format_size( + driver->playback_setup.format.format, + nframes ), + driver->interleave_unit, + driver->playback_interleave_skip[chn] ); + } + else + { + memset( driver->playback_addr[chn], + 0, + snd_pcm_format_size( + driver->playback_setup.format.format, + nframes ) ); + } + } + + 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, + jack_client_t *client, + ioaudio_driver_args_t args + ); + +// 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(); + 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 ff8c045e..600dd653 100644 --- a/qnx/wscript +++ b/qnx/wscript @@ -43,9 +43,10 @@ def build(bld): deva.install_path = '/lib/dll' ioaudio_driver_src = [ - 'ioaudio/JackIoAudioDriver.cpp', '../common/memops.c', + 'ioaudio/generic_hw.c', 'ioaudio/ioaudio_backend.c', + 'ioaudio/JackIoAudioDriver.cpp', ] create_jack_driver_obj(bld, 'ioaudio', ioaudio_driver_src, ['IOAUDIO', 'PTHREAD']) \ No newline at end of file From 873de3cd5165113151ee590466d99ffcb08d65f7 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Thu, 14 Jan 2016 16:04:28 -0600 Subject: [PATCH 3/6] Iteration 3 --- .cproject | 5 +- qnx/JackTime.h | 24 + qnx/driver.h | 9 + qnx/ioaudio/JackIoAudioDriver.cpp | 3780 +++++++++++++++++++++-------- qnx/ioaudio/JackIoAudioDriver.h | 226 +- qnx/ioaudio/generic.h | 37 - qnx/ioaudio/generic_hw.c | 56 - qnx/ioaudio/hardware.h | 87 +- qnx/ioaudio/ioaudio_backend.c | 2369 ------------------ qnx/ioaudio/ioaudio_backend.h | 386 --- qnx/wscript | 4 +- 11 files changed, 2974 insertions(+), 4009 deletions(-) create mode 100644 qnx/JackTime.h delete mode 100644 qnx/ioaudio/generic.h delete mode 100644 qnx/ioaudio/generic_hw.c delete mode 100644 qnx/ioaudio/ioaudio_backend.c delete mode 100644 qnx/ioaudio/ioaudio_backend.h diff --git a/.cproject b/.cproject index b326155f..2e8a70c9 100644 --- a/.cproject +++ b/.cproject @@ -1,7 +1,5 @@ - - - + @@ -46,6 +44,7 @@ +