Browse Source

Merge pull request #8 from AndrewCooper/ioaudio-backend

Add native io-audio backend for jackd
pull/244/head
Shaun Tierney 10 years ago
parent
commit
6846ee83b1
9 changed files with 3131 additions and 10 deletions
  1. +3
    -3
      common/JackAudioDriver.cpp
  2. +1
    -1
      common/JackAudioDriver.h
  3. +0
    -6
      qnx/JackQnxTime.c
  4. +309
    -0
      qnx/driver.h
  5. +2323
    -0
      qnx/ioaudio/JackIoAudioDriver.cpp
  6. +277
    -0
      qnx/ioaudio/JackIoAudioDriver.h
  7. +134
    -0
      qnx/ioaudio/bitset.h
  8. +76
    -0
      qnx/ioaudio/hardware.h
  9. +8
    -0
      qnx/wscript

+ 3
- 3
common/JackAudioDriver.cpp View File

@@ -48,7 +48,7 @@ int JackAudioDriver::SetBufferSize(jack_nframes_t buffer_size)
fGraphManager->SetBufferSize(buffer_size);
fEngineControl->UpdateTimeOut();
UpdateLatencies();
update_latencies();

// Redirected on slaves drivers...
return JackDriver::SetBufferSize(buffer_size);
@@ -85,7 +85,7 @@ int JackAudioDriver::Open(jack_nframes_t buffer_size,
monitor, capture_driver_name, playback_driver_name, capture_latency, playback_latency);
}

void JackAudioDriver::UpdateLatencies()
void JackAudioDriver::update_latencies()
{
jack_latency_range_t input_range;
jack_latency_range_t output_range;
@@ -159,7 +159,7 @@ int JackAudioDriver::Attach()
}
}

UpdateLatencies();
update_latencies();
return 0;
}



+ 1
- 1
common/JackAudioDriver.h View File

@@ -49,7 +49,7 @@ class SERVER_EXPORT JackAudioDriver : public JackDriver
jack_default_audio_sample_t* GetMonitorBuffer(int port_index);

void HandleLatencyCallback(int status);
virtual void UpdateLatencies();
virtual void update_latencies();

int ProcessAsync();
void ProcessGraphAsync();


+ 0
- 6
qnx/JackQnxTime.c View File

@@ -208,9 +208,3 @@ SERVER_EXPORT jack_time_t GetMicroSeconds()
{
return _jack_get_microseconds();
}

SERVER_EXPORT jack_time_t jack_get_microseconds()
{
return _jack_get_microseconds();
}


+ 309
- 0
qnx/driver.h View File

@@ -0,0 +1,309 @@
/*
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"

#ifdef __cplusplus
extern "C"
{
#endif

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);

#ifdef __cplusplus
}
#endif

#endif /* __jack_driver_h__ */

+ 2323
- 0
qnx/ioaudio/JackIoAudioDriver.cpp
File diff suppressed because it is too large
View File


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

@@ -0,0 +1,277 @@
/*
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 "driver.h"
#include "memops.h"
#include <sys/poll.h>

namespace Jack
{

///////////////////////////////////////////////////////////////////////////////
// CONSTANTS
///////////////////////////////////////////////////////////////////////////////

enum IoAudioDriverChannels
{
Playback = SND_PCM_CHANNEL_PLAYBACK,
Capture = SND_PCM_CHANNEL_CAPTURE,
Extra = SND_PCM_CHANNEL_MAX,
IoAudioDriverChannels_COUNT
};

///////////////////////////////////////////////////////////////////////////////
// TYPES
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
// IMPLEMENTATIONS
///////////////////////////////////////////////////////////////////////////////

/*!
\brief The IoAudio driver.
*/

class JackIoAudioDriver: public JackAudioDriver
{
public:
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 );

struct Args
{
const char* jack_name;
const char* jack_alias;

char* device;

bool capture;
const char* capture_pcm_name;
size_t user_capture_nchnls;

bool 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;
bool hw_monitoring;
bool hw_metering;
bool duplex;
bool soft_mode;
bool monitor;
bool shorts_first;
size_t systemic_input_latency;
size_t systemic_output_latency;
};

struct Voice
{
unsigned long interleave_skip;
char* addr;
unsigned long silent;
dither_state_t dither_state;
};

struct Channel
{
Voice* voices;
unsigned int nperiods;
snd_pcm_t *handle;
snd_pcm_channel_params_t params;
snd_pcm_channel_setup_t setup;
snd_pcm_mmap_control_t *mmap;
void *mmap_buf;
void *buffer;

ReadCopyFunction read;
WriteCopyFunction write;

ssize_t sample_bytes()
{
return snd_pcm_format_size( setup.format.format,
1 );
}
ssize_t frame_bytes()
{
return snd_pcm_format_size( setup.format.format,
setup.format.voices );
}

ssize_t frag_bytes()
{
return setup.buf.block.frag_size;
}

ssize_t frag_frames()
{
return frag_bytes() / frame_bytes();
}

};

public:

JackIoAudioDriver(
Args args,
JackLockedEngine* engine,
JackSynchro* table );

virtual ~JackIoAudioDriver();

int Attach();

int Close();

int Detach();

// BufferSize can be changed
bool IsFixedBufferSize()
{
return false;
}

int Open();

int Read();

int SetBufferSize(
jack_nframes_t buffer_size );

int Start();

int Stop();

int Write();

private:
Args fArgs;

int poll_timeout_msecs;
jack_time_t poll_last;
jack_time_t poll_next;
int poll_late;

struct pollfd pfd[IoAudioDriverChannels_COUNT];
unsigned long interleave_unit;
unsigned int max_nchannels;
unsigned int user_nchannels;

jack_nframes_t frame_rate;

Channel playback;

Channel capture;

jack_hardware_t *hw;

bool capture_and_playback_not_synced;
bool has_clock_sync_reporting;

bool has_hw_monitoring;
bool do_hw_monitoring;
unsigned long input_monitor_mask;

bool has_hw_metering;
bool do_hw_metering;
bool quirk_bswap;

int xrun_count;
int process_count;

int in_xrun_recovery;

int check_capabilities(
const char *devicename,
int mode );

int check_card_type();

void clear_output_aux();

int configure_stream(
const char *device_name,
const char *stream_name,
snd_pcm_t *handle,
snd_pcm_channel_params_t *params,
unsigned int *nperiodsp );

int create(
jack_client_t *client );

int generic_hardware();

int get_channel_addresses(
size_t *capture_avail,
size_t *playback_avail,
size_t *capture_offset,
size_t *playback_offset );

int hw_specific();

void monitor_input_aux();

int read(
jack_nframes_t nframes );

void read_input_aux(
jack_nframes_t orig_nframes,
ssize_t contiguous,
ssize_t nread );

int set_parameters();

void setup_io_function_pointers();

void update_latencies();

jack_nframes_t wait(
int *status,
float *delayed_usecs );

void write_output_aux(
jack_nframes_t orig_nframes,
ssize_t contiguous,
ssize_t nwritten );

int xrun_recovery(
float *delayed_usecs );
};

} // end of namespace

#endif

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

@@ -0,0 +1,134 @@
/*
* 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 <malloc.h>
#include <string.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__ */

+ 76
- 0
qnx/ioaudio/hardware.h View File

@@ -0,0 +1,76 @@
/*
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"

enum SampleClockMode
{
AutoSync,
WordClock,
ClockMaster
};

enum Capabilities
{
Cap_None = 0x0,
Cap_HardwareMonitoring = 0x1,
Cap_AutoSync = 0x2,
Cap_WordClock = 0x4,
Cap_ClockMaster = 0x8,
Cap_ClockLockReporting = 0x10,
Cap_HardwareMetering = 0x20
};

struct jack_hardware_t
{
Capabilities capabilities;
unsigned long input_monitor_mask;
void *private_hw;

jack_hardware_t() :
capabilities( Cap_None ),
input_monitor_mask( 0 )
{
}

virtual ~jack_hardware_t() {}

virtual void release() = 0;

virtual int set_input_monitor_mask(
unsigned long ) = 0;

virtual int change_sample_clock(
SampleClockMode ) = 0;

virtual double get_hardware_peak(
jack_port_t *port,
jack_nframes_t frames ) = 0;

virtual double get_hardware_power(
jack_port_t *port,
jack_nframes_t frames ) = 0;

};

#endif /* __jack_hardware_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 = [
'../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'])

Loading…
Cancel
Save