Browse Source

Add Jack IoAudio Driver Backend

pull/244/head^2
Andrew Cooper 10 years ago
parent
commit
70573282a5
9 changed files with 4176 additions and 0 deletions
  1. +54
    -0
      .cproject
  2. +27
    -0
      .project
  3. +300
    -0
      qnx/driver.h
  4. +940
    -0
      qnx/ioaudio/JackIoAudioDriver.cpp
  5. +112
    -0
      qnx/ioaudio/JackIoAudioDriver.h
  6. +132
    -0
      qnx/ioaudio/bitset.h
  7. +2308
    -0
      qnx/ioaudio/ioaudio_backend.c
  8. +295
    -0
      qnx/ioaudio/ioaudio_backend.h
  9. +8
    -0
      qnx/wscript

+ 54
- 0
.cproject View File

@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?fileVersion 4.0.0?>

<cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
<storageModule moduleId="org.eclipse.cdt.core.settings">
<cconfiguration id="com.qnx.qcc.toolChain.1426688628">
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.qnx.qcc.toolChain.1426688628" moduleId="org.eclipse.cdt.core.settings" name="Default">
<externalSettings/>
<extensions>
<extension id="com.qnx.tools.ide.qde.core.QDEBynaryParser" point="org.eclipse.cdt.core.BinaryParser"/>
<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
</extensions>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<configuration artifactName="${ProjName}" buildProperties="" id="com.qnx.qcc.toolChain.1426688628" name="Default" parent="org.eclipse.cdt.build.core.emptycfg">
<folderInfo id="com.qnx.qcc.toolChain.1426688628.2053955807" name="/" resourcePath="">
<toolChain id="com.qnx.qcc.toolChain.438169716" name="com.qnx.qcc.toolChain" superClass="com.qnx.qcc.toolChain">
<option id="com.qnx.qcc.option.os.1677980343" name="Target OS:" superClass="com.qnx.qcc.option.os"/>
<option id="com.qnx.qcc.option.cpu.56565625" name="Target CPU:" superClass="com.qnx.qcc.option.cpu"/>
<option id="com.qnx.qcc.option.compiler.742352083" name="Compiler:" superClass="com.qnx.qcc.option.compiler"/>
<option id="com.qnx.qcc.option.runtime.1596137464" name="Runtime:" superClass="com.qnx.qcc.option.runtime"/>
<targetPlatform archList="all" binaryParser="com.qnx.tools.ide.qde.core.QDEBynaryParser" id="com.qnx.qcc.targetPlatform.1124193828" osList="all" superClass="com.qnx.qcc.targetPlatform"/>
<builder id="com.qnx.qcc.toolChain.1426688628.655316141" managedBuildOn="false" name="Gnu Make Builder.Preference Configuration" superClass="org.eclipse.cdt.build.core.settings.default.builder"/>
<tool id="com.qnx.qcc.tool.compiler.938460844" name="QCC Compiler" superClass="com.qnx.qcc.tool.compiler">
<option id="com.qnx.qcc.option.compiler.optlevel.1413154425" superClass="com.qnx.qcc.option.compiler.optlevel" value="com.qnx.qcc.option.compiler.optlevel.0" valueType="enumerated"/>
<inputType id="com.qnx.qcc.inputType.compiler.775408002" superClass="com.qnx.qcc.inputType.compiler"/>
</tool>
<tool id="com.qnx.qcc.tool.assembler.1741326744" name="QCC Assembler" superClass="com.qnx.qcc.tool.assembler">
<inputType id="com.qnx.qcc.inputType.assembler.969556839" superClass="com.qnx.qcc.inputType.assembler"/>
</tool>
<tool id="com.qnx.qcc.tool.linker.1638240831" name="QCC Linker" superClass="com.qnx.qcc.tool.linker">
<option id="com.qnx.qcc.option.linker.langcpp.1442166281" superClass="com.qnx.qcc.option.linker.langcpp" value="true" valueType="boolean"/>
</tool>
<tool id="com.qnx.qcc.tool.archiver.594954823" name="QCC Archiver" superClass="com.qnx.qcc.tool.archiver"/>
</toolChain>
</folderInfo>
</configuration>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
</cconfiguration>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<project id="jack2.null.1473030055" name="jack2"/>
</storageModule>
<storageModule moduleId="scannerConfiguration">
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="com.qnx.tools.ide.qde.managedbuilder.core.qccScannerInfo"/>
<scannerConfigBuildInfo instanceId="com.qnx.qcc.toolChain.1426688628">
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="com.qnx.tools.ide.qde.managedbuilder.core.qccScannerInfo"/>
</scannerConfigBuildInfo>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
</cproject>

+ 27
- 0
.project View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>jack2</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
<triggers>clean,full,incremental,</triggers>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
<triggers>full,incremental,</triggers>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.cdt.core.cnature</nature>
<nature>org.eclipse.cdt.core.ccnature</nature>
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
</natures>
</projectDescription>

+ 300
- 0
qnx/driver.h View File

@@ -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 <pthread.h>
#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__ */

+ 940
- 0
qnx/ioaudio/JackIoAudioDriver.cpp View File

@@ -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 <iostream>
#include <math.h>
#include <stdio.h>
#include <memory.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <stdarg.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/time.h>
#include <string.h>

#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



+ 112
- 0
qnx/ioaudio/JackIoAudioDriver.h View File

@@ -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

+ 132
- 0
qnx/ioaudio/bitset.h View File

@@ -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 <inttypes.h> /* POSIX standard fixed-size types */
#include <assert.h> /* `#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__ */

+ 2308
- 0
qnx/ioaudio/ioaudio_backend.c
File diff suppressed because it is too large
View File


+ 295
- 0
qnx/ioaudio/ioaudio_backend.h View File

@@ -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 <sys/asoundlib.h>
#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__ */

+ 8
- 0
qnx/wscript View File

@@ -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'])

Loading…
Cancel
Save