Browse Source

Merge a154717cea into ba28ffa3db

pull/608/merge
twischer GitHub 5 years ago
parent
commit
52b764ecf4
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 3528 additions and 1316 deletions
  1. +14
    -0
      Makefile
  2. +16
    -0
      common/JackAPI.cpp
  3. +2
    -2
      common/JackAudioAdapterInterface.cpp
  4. +17
    -5
      common/JackAudioDriver.cpp
  5. +2
    -0
      common/JackAudioDriver.h
  6. +3
    -0
      common/JackChannel.h
  7. +16
    -0
      common/JackClient.cpp
  8. +2
    -0
      common/JackClient.h
  9. +4
    -1
      common/JackControlAPI.cpp
  10. +9
    -0
      common/JackDriver.cpp
  11. +2
    -0
      common/JackDriver.h
  12. +7
    -0
      common/JackGenericClientChannel.cpp
  13. +2
    -0
      common/JackGenericClientChannel.h
  14. +27
    -1
      common/JackRequest.h
  15. +10
    -0
      common/JackRequestDecoder.cpp
  16. +5
    -0
      common/JackServer.cpp
  17. +1
    -0
      common/JackServer.h
  18. +22
    -0
      common/JackThreadedDriver.cpp
  19. +1
    -0
      common/JackThreadedDriver.h
  20. +16
    -0
      common/jack/jack.h
  21. +1
    -1
      common/jack/systemdeps.h
  22. +2
    -0
      common/netjack_packet.c
  23. +60
    -9
      common/shm.c
  24. +25
    -7
      common/wscript
  25. +32
    -0
      example-clients/reload.c
  26. +7
    -4
      example-clients/wscript
  27. +437
    -181
      linux/alsa/JackAlsaDriver.cpp
  28. +14
    -20
      linux/alsa/JackAlsaDriver.h
  29. +1813
    -938
      linux/alsa/alsa_driver.c
  30. +201
    -107
      linux/alsa/alsa_driver.h
  31. +1
    -1
      linux/alsa/generic.h
  32. +1
    -1
      linux/alsa/generic_hw.c
  33. +10
    -10
      linux/alsa/hammerfall.c
  34. +2
    -2
      linux/alsa/hammerfall.h
  35. +3
    -3
      linux/alsa/hdsp.c
  36. +2
    -2
      linux/alsa/hdsp.h
  37. +4
    -4
      linux/alsa/ice1712.c
  38. +2
    -2
      linux/alsa/ice1712.h
  39. +4
    -0
      linux/alsa/usx2y.h
  40. +1
    -1
      posix/JackFifo.h
  41. +86
    -0
      qnx/JackAtomic_os.h
  42. +215
    -0
      qnx/JackLinuxTime.c
  43. +85
    -0
      qnx/JackPlatformPlug_os.h
  44. +300
    -0
      qnx/driver.h
  45. +2
    -0
      tests/wscript
  46. +40
    -14
      wscript

+ 14
- 0
Makefile View File

@@ -0,0 +1,14 @@
.PHONY: all
all:
CC=${QNX_HOST}/usr/bin/aarch64-unknown-nto-qnx7.0.0-gcc CXX=${QNX_HOST}/usr/bin/aarch64-unknown-nto-qnx7.0.0-g++ AR=${QNX_HOST}/usr/bin/aarch64-unknown-nto-qnx7.0.0-ar LDFLAGS="-L${INSTALL_ROOT_nto}/aarch64le/lib -L${INSTALL_ROOT_nto}/aarch64le/usr/lib -L${QNX_TARGET}/aarch64le/lib -L${QNX_TARGET}/aarch64le/usr/lib" PKG_CONFIG_LIBDIR=${INSTALL_ROOT_nto}/aarch64le/usr/lib/pkgconfig ./waf configure --platform=qnx --prefix=/usr --libdir=/usr/lib64
./waf build
./waf install --destdir=${INSTALL_ROOT_nto}/aarch64le

.PHONY: install
install: all

.PHONY:clean
clean:
# ignore error codes otherwise it would for example fail if clean is called before configure
-./waf clean


+ 16
- 0
common/JackAPI.cpp View File

@@ -277,6 +277,8 @@ extern "C"
LIB_EXPORT void jack_uuid_unparse(jack_uuid_t, char buf[JACK_UUID_STRING_SIZE]);
LIB_EXPORT int jack_uuid_empty(jack_uuid_t);

LIB_EXPORT int jack_client_reload_master(jack_client_t* ext_client);

#ifdef __cplusplus
}
#endif
@@ -2140,3 +2142,17 @@ LIB_EXPORT int jack_uuid_empty(jack_uuid_t u)
{
return u == JACK_UUID_EMPTY_INITIALIZER;
}

LIB_EXPORT int jack_client_reload_master(jack_client_t* ext_client)
{
JackGlobals::CheckContext("jack_client_reload_master");

JackClient* client = (JackClient*)ext_client;
if (client == NULL) {
jack_error("jack_client_reload_master called with a NULL client");
return -1;
} else {
WaitGraphChange();
return client->ClientReloadMaster();
}
}

+ 2
- 2
common/JackAudioAdapterInterface.cpp View File

@@ -22,7 +22,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#endif

#include "JackAudioAdapter.h"
#ifndef MY_TARGET_OS_IPHONE
#if !defined(MY_TARGET_OS_IPHONE) && !defined(__QNXNTO__)
#include "JackLibSampleRateResampler.h"
#endif
#include "JackTime.h"
@@ -185,7 +185,7 @@ namespace Jack
fRunning = false;
}

#ifdef MY_TARGET_OS_IPHONE
#if defined(MY_TARGET_OS_IPHONE) || defined(__QNXNTO__)
void JackAudioAdapterInterface::Create()
{}
#else


+ 17
- 5
common/JackAudioDriver.cpp View File

@@ -199,7 +199,19 @@ int JackAudioDriver::Write()

int JackAudioDriver::Process()
{
return (fEngineControl->fSyncMode) ? ProcessSync() : ProcessAsync();
int err = 0;
int retries = -1;

while (retries++ < fMaxRetryCount) {
err = (fEngineControl->fSyncMode) ? ProcessSync() : ProcessAsync();
if (err == 0) {
break;
}

jack_error("JackAudioDriver::Process failed, retry %d", retries);
}

return err;
}

/*
@@ -211,13 +223,13 @@ int JackAudioDriver::ProcessAsync()
{
// Read input buffers for the current cycle
if (Read() < 0) {
jack_error("JackAudioDriver::ProcessAsync: read error, stopping...");
jack_error("JackAudioDriver::ProcessAsync: read error");
return -1;
}

// Write output buffers from the previous cycle
if (Write() < 0) {
jack_error("JackAudioDriver::ProcessAsync: write error, stopping...");
jack_error("JackAudioDriver::ProcessAsync: write error");
return -1;
}

@@ -285,7 +297,7 @@ int JackAudioDriver::ProcessSync()
{
// Read input buffers for the current cycle
if (Read() < 0) {
jack_error("JackAudioDriver::ProcessSync: read error, stopping...");
jack_error("JackAudioDriver::ProcessSync: read error");
return -1;
}

@@ -294,7 +306,7 @@ int JackAudioDriver::ProcessSync()

// Write output buffers from the current cycle
if (Write() < 0) {
jack_error("JackAudioDriver::ProcessSync: write error, stopping...");
jack_error("JackAudioDriver::ProcessSync: write error");
return -1;
}



+ 2
- 0
common/JackAudioDriver.h View File

@@ -61,6 +61,8 @@ class SERVER_EXPORT JackAudioDriver : public JackDriver
void ProcessGraphSyncMaster();
void ProcessGraphSyncSlave();

static const int fMaxRetryCount = 5;

public:

JackAudioDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table);


+ 3
- 0
common/JackChannel.h View File

@@ -137,6 +137,9 @@ class JackClientChannelInterface
virtual void ClientDeactivate(int refnum, int* result)
{}

virtual void ClientReloadMaster(int* result)
{}

virtual void PortRegister(int refnum, const char* name, const char* type, unsigned int flags, unsigned int buffer_size, jack_port_id_t* port_index, int* result)
{}
virtual void PortUnRegister(int refnum, jack_port_id_t port_index, int* result)


+ 16
- 0
common/JackClient.cpp View File

@@ -34,6 +34,15 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

using namespace std;

#ifdef __QNXNTO__
void __attribute__((constructor)) init_output_for_percent_s_NULL_for_clients();
void init_output_for_percent_s_NULL_for_clients()
{
extern const char *output_for_percent_s_NULL;
output_for_percent_s_NULL = "(null)";
}
#endif

namespace Jack
{

@@ -493,6 +502,13 @@ int JackClient::Deactivate()
if (IsRealTime()) {
fThread.Kill();
}
return result;
}

int JackClient::ClientReloadMaster()
{
int result = -1;
fChannel->ClientReloadMaster(&result);
return result;
}



+ 2
- 0
common/JackClient.h View File

@@ -145,6 +145,8 @@ class SERVER_EXPORT JackClient : public JackClientInterface, public JackRunnable
virtual int Activate();
virtual int Deactivate();

virtual int ClientReloadMaster();

// Context
virtual int SetBufferSize(jack_nframes_t buffer_size);
virtual int SetFreeWheel(int onoff);


+ 4
- 1
common/JackControlAPI.cpp View File

@@ -663,7 +663,10 @@ jackctl_setup_signals(
sigfillset(&allsignals);
action.sa_handler = signal_handler;
action.sa_mask = allsignals;
action.sa_flags = SA_RESTART|SA_RESETHAND;
action.sa_flags = SA_RESETHAND;
#ifndef __QNXNTO__
action.sa_flags |= SA_RESTART;
#endif

for (i = 1; i < NSIG; i++)
{


+ 9
- 0
common/JackDriver.cpp View File

@@ -110,6 +110,10 @@ int JackDriver::Open(jack_nframes_t buffer_size,
fClientControl.fRefNum = refnum;
fClientControl.fActive = true;
fEngineControl->fDriverNum++;
if (buffer_size > BUFFER_SIZE_MAX) {
jack_error("Buffer size %ld exceeds BUFFER_SIZE_MAX %d", buffer_size, BUFFER_SIZE_MAX);
return -1;
}
if (buffer_size > 0) {
fEngineControl->fBufferSize = buffer_size;
}
@@ -351,6 +355,11 @@ int JackDriver::Stop()
return StopSlaves();
}

int JackDriver::Reload()
{
return 0;
}

int JackDriver::StartSlaves()
{
int res = 0;


+ 2
- 0
common/JackDriver.h View File

@@ -72,6 +72,7 @@ class SERVER_EXPORT JackDriverInterface

virtual int Start() = 0;
virtual int Stop() = 0;
virtual int Reload() = 0;

virtual bool IsFixedBufferSize() = 0;
virtual int SetBufferSize(jack_nframes_t buffer_size) = 0;
@@ -227,6 +228,7 @@ class SERVER_EXPORT JackDriver : public JackDriverClientInterface

virtual int Start();
virtual int Stop();
virtual int Reload();

// For "master" driver
int ProcessReadSlaves();


+ 7
- 0
common/JackGenericClientChannel.cpp View File

@@ -137,6 +137,13 @@ void JackGenericClientChannel::ClientDeactivate(int refnum, int* result)
ServerSyncCall(&req, &res, result);
}

void JackGenericClientChannel::ClientReloadMaster(int *result)
{
JackClientReloadMasterRequest req;
JackResult res;
ServerSyncCall(&req, &res, result);
}

void JackGenericClientChannel::PortRegister(int refnum, const char* name, const char* type, unsigned int flags, unsigned int buffer_size, jack_port_id_t* port_index, int* result)
{
JackPortRegisterRequest req(refnum, name, type, flags, buffer_size);


+ 2
- 0
common/JackGenericClientChannel.h View File

@@ -62,6 +62,8 @@ class JackGenericClientChannel : public detail::JackClientChannelInterface
void ClientActivate(int refnum, int is_real_time, int* result);
void ClientDeactivate(int refnum, int* result);

void ClientReloadMaster(int* result);

void PortRegister(int refnum, const char* name, const char* type, unsigned int flags, unsigned int buffer_size, jack_port_id_t* port_index, int* result);
void PortUnRegister(int refnum, jack_port_id_t port_index, int* result);



+ 27
- 1
common/JackRequest.h View File

@@ -90,7 +90,8 @@ struct JackRequest
kGetUUIDByClient = 37,
kClientHasSessionCallback = 38,
kComputeTotalLatencies = 39,
kPropertyChangeNotify = 40
kPropertyChangeNotify = 40,
kClientReloadMaster = 41,
};

RequestType fType;
@@ -1736,6 +1737,31 @@ struct JackClientNotification

};

/*!
\brief Restart Master Backend Request.
*/

struct JackClientReloadMasterRequest : public JackRequest
{
JackClientReloadMasterRequest(): JackRequest(JackRequest::kClientReloadMaster)
{
}

int Read(detail::JackChannelTransactionInterface* trans)
{
CheckSize();
return 0;
}

int Write(detail::JackChannelTransactionInterface* trans)
{
CheckRes(JackRequest::Write(trans, Size()));
return 0;
}

int Size() { return 0; }
};

} // end of namespace

#endif

+ 10
- 0
common/JackRequestDecoder.cpp View File

@@ -346,6 +346,16 @@ int JackRequestDecoder::HandleRequest(detail::JackChannelTransactionInterface* s
break;
}

case JackRequest::kClientReloadMaster: {
jack_log("JackRequest::ClientReloadMaster");
JackClientReloadMasterRequest req;
JackResult res;
CheckRead(req, socket);
res.fResult = fServer->ReloadMaster();
CheckWrite("JackRequest::ClientReloadMaster", socket);
break;
}

default:
jack_error("Unknown request %ld", type);
return -1;


+ 5
- 0
common/JackServer.cpp View File

@@ -430,6 +430,11 @@ error:
return -1;
}

int JackServer::ReloadMaster()
{
return fAudioDriver->Reload();
}

//----------------------
// Transport management
//----------------------


+ 1
- 0
common/JackServer.h View File

@@ -98,6 +98,7 @@ class SERVER_EXPORT JackServer
JackDriverInfo* AddSlave(jack_driver_desc_t* driver_desc, JSList* driver_params);
void RemoveSlave(JackDriverInfo* info);
int SwitchMaster(jack_driver_desc_t* driver_desc, JSList* driver_params);
int ReloadMaster();

// Object access
JackLockedEngine* GetEngine();


+ 22
- 0
common/JackThreadedDriver.cpp View File

@@ -239,6 +239,28 @@ int JackThreadedDriver::Stop()
return 0;
}

int JackThreadedDriver::Reload()
{
if (Stop() < 0) {
jack_error("JackThreadedDriver::Reload stop failed");
return -1;
}

// not able to use Close() and Open() since we dont have original Open() parameters, these
// are internal to fDriver, reload should reopen with same parameters
if (fDriver->Reload() < 0) {
jack_error("JackThreadedDriver::Reload reload failed");
return -1;
}

if (Start() < 0) {
jack_error("JackThreadedDriver::Reload start failed");
return -1;
}

return 0;
}

bool JackThreadedDriver::Execute()
{
return (Process() == 0);


+ 1
- 0
common/JackThreadedDriver.h View File

@@ -70,6 +70,7 @@ class SERVER_EXPORT JackThreadedDriver : public JackDriverClientInterface, publi

virtual int Start();
virtual int Stop();
virtual int Reload();

virtual bool IsFixedBufferSize();
virtual int SetBufferSize(jack_nframes_t buffer_size);


+ 16
- 0
common/jack/jack.h View File

@@ -139,6 +139,22 @@ int jack_client_close (jack_client_t *client) JACK_OPTIONAL_WEAK_EXPORT;
*/
int jack_client_name_size (void) JACK_OPTIONAL_WEAK_EXPORT;

/**
* Reloads audio backend.
*
* This is useful when client wants audio backend to reload its state.
* Currently used only for alsa audio backend.
*
* Alsa backend will close or open audio devices on reload depending on
* the state of the ports asociated with audio device. If all ports
* are disconnected audio device is closed, opened otherwise. This
* behaviour is modifiable by alsa backend options provided to jackd
* on startup.
*
* @return 0 if successful.
*/
int jack_client_reload_master(jack_client_t* ext_client) JACK_OPTIONAL_WEAK_EXPORT;

/**
* @return pointer to actual client name. This is useful when @ref
* JackUseExactName is not specified on open and @ref


+ 1
- 1
common/jack/systemdeps.h View File

@@ -107,7 +107,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

#endif /* _WIN32 && !__CYGWIN__ && !GNU_WIN32 */

#if defined(__APPLE__) || defined(__linux__) || defined(__sun__) || defined(sun) || defined(__unix__) || defined(__CYGWIN__) || defined(GNU_WIN32)
#if defined(__APPLE__) || defined(__linux__) || defined(__sun__) || defined(sun) || defined(__unix__) || defined(__CYGWIN__) || defined(GNU_WIN32) || defined(__QNXNTO__)

#if defined(__CYGWIN__) || defined(GNU_WIN32)
#include <stdint.h>


+ 2
- 0
common/netjack_packet.c View File

@@ -428,7 +428,9 @@ netjack_poll (int sockfd, int timeout)

action.sa_handler = SIG_DFL;
action.sa_mask = sigmask;
#ifndef __QNXNTO__
action.sa_flags = SA_RESTART;
#endif

for (i = 1; i < NSIG; i++)
if (sigismember (&sigmask, i))


+ 60
- 9
common/shm.c View File

@@ -49,11 +49,16 @@
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <stdlib.h>
#include "promiscuous.h"

#ifdef __QNXNTO__
#include <sys/mman.h>
#else
#include <sys/shm.h>
#endif

#endif

#include "shm.h"
@@ -148,8 +153,6 @@ static jack_shm_registry_t *jack_shm_registry = NULL;
#define JACK_SHM_REGISTRY_KEY JACK_SEMAPHORE_KEY
#endif

static int semid = -1;

#ifdef WIN32

#include <psapi.h>
@@ -178,12 +181,61 @@ static BOOL check_process_running(DWORD process_id)
}

static int
semaphore_init () {return 0;}
jack_shm_lock_registry () {return 0;}

static void
jack_shm_unlock_registry () { }

#elif __QNXNTO__
#include <semaphore.h>

static sem_t* semid = SEM_FAILED;

static int
semaphore_init ()
{
const char name[] = "/jack-shm-registry-lock";
const int oflag = O_CREAT | O_RDWR;
const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
if ((semid = sem_open(name, oflag, mode, 1)) == SEM_FAILED) {
jack_error("Creating semaphore %s failed", name);
return -1;
}

return 0;
}

static int
jack_shm_lock_registry (void)
{
if (semid == SEM_FAILED) {
if (semaphore_init () < 0)
return -1;
}

// TODO automatically unblock in case the process terminates
const int ret = sem_wait(semid);
if (ret < 0) {
jack_error("sem_wait() failed with %s", strerror(ret));
return -1;
}

static int
semaphore_add (int value) {return 0;}
return 0;
}

static void
jack_shm_unlock_registry (void)
{
const int ret = sem_post(semid);

if (ret < 0) {
jack_error("sem_post() failed with %s", strerror(ret));
}
}

#else
static int semid = -1;

/* all semaphore errors are fatal -- issue message, but do not return */
static void
semaphore_error (char *msg)
@@ -247,8 +299,6 @@ semaphore_add (int value)
return 0;
}

#endif

static int
jack_shm_lock_registry (void)
{
@@ -266,6 +316,8 @@ jack_shm_unlock_registry (void)
semaphore_add (1);
}

#endif

static void
jack_shm_init_registry ()
{
@@ -1308,4 +1360,3 @@ jack_attach_shm_read (jack_shm_info_t* si)
}

#endif /* !USE_POSIX_SHM */


+ 25
- 7
common/wscript View File

@@ -28,6 +28,8 @@ def create_jack_process_obj(bld, target, sources, uselib = None, framework = Non
env_includes = ['../macosx', '../posix', '../macosx/coreaudio']
if bld.env['IS_LINUX']:
env_includes = ['../linux', '../posix', '../linux/alsa']
if bld.env['IS_QNX']:
env_includes = ['../qnx', '../posix']
if bld.env['IS_SUN']:
env_includes = ['../solaris', '../posix', '../solaris/oss']
if bld.env['IS_WINDOWS']:
@@ -36,7 +38,7 @@ def create_jack_process_obj(bld, target, sources, uselib = None, framework = Non
process.name = target
process.target = target
process.source = sources
if bld.env['IS_LINUX'] or bld.env['IS_MACOSX']:
if bld.env['IS_LINUX'] or bld.env['IS_MACOSX'] or bld.env['IS_QNX']:
process.env.append_value('CPPFLAGS', '-fvisibility=hidden')
process.install_path = '${ADDON_DIR}/'
process.use = [uselib.name]
@@ -92,6 +94,22 @@ def build(bld):
uselib.append('RT')
uselib.append('DL')

if bld.env['IS_QNX']:
common_libsources += [
'JackDebugClient.cpp',
'timestamps.c',
'promiscuous.c',
'../posix/JackPosixThread.cpp',
'../posix/JackPosixProcessSync.cpp',
'../posix/JackPosixMutex.cpp',
'../posix/JackSocket.cpp',
'../posix/JackFifo.cpp',
'../linux/JackLinuxTime.c',
]
includes = ['../qnx', '../posix'] + includes
uselib.append('SOCKET')
# libdl and librt is included in libc in QNX

if bld.env['IS_SUN']:
common_libsources += [
'JackDebugClient.cpp',
@@ -163,7 +181,7 @@ def build(bld):
'JackMetadata.cpp',
]

if bld.env['IS_LINUX']:
if bld.env['IS_LINUX'] or bld.env['IS_QNX']:
clientlib.source += [
'../posix/JackSocketClientChannel.cpp',
'../posix/JackPosixServerLaunch.cpp',
@@ -192,7 +210,7 @@ def build(bld):
if not bld.env['IS_WINDOWS']:
clientlib.vnum = bld.env['JACK_API_VERSION']

if bld.env['IS_LINUX']:
if bld.env['IS_LINUX'] or bld.env['IS_QNX']:
clientlib.env.append_value('CPPFLAGS', '-fvisibility=hidden')

if bld.env['IS_MACOSX']:
@@ -270,7 +288,7 @@ def build(bld):
'JackMetadata.cpp',
]

if bld.env['IS_LINUX']:
if bld.env['IS_LINUX'] or bld.env['IS_QNX']:
serverlib.source += [
'../posix/JackSocketServerChannel.cpp',
'../posix/JackSocketNotifyChannel.cpp',
@@ -307,7 +325,7 @@ def build(bld):
if not bld.env['IS_WINDOWS']:
serverlib.vnum = bld.env['JACK_API_VERSION']

if bld.env['IS_LINUX']:
if bld.env['IS_LINUX'] or bld.env['IS_QNX']:
serverlib.env.append_value('CPPFLAGS', '-fvisibility=hidden')

if bld.env['IS_MACOSX']:
@@ -333,7 +351,7 @@ def build(bld):
if skipshared:
netlib.env['SHLIB_MARKER'] = ''
netlib.use += ['WS2_32', 'WINMM']
elif not bld.env['IS_MACOSX']:
elif not bld.env['IS_MACOSX'] and not bld.env['IS_QNX']:
netlib.use += ['RT']
netlib.install_path = '${LIBDIR}'
netlib.source = [
@@ -347,7 +365,7 @@ def build(bld):
'JackGlobals.cpp',
'ringbuffer.c']

if bld.env['IS_LINUX']:
if bld.env['IS_LINUX'] or bld.env['IS_QNX']:
netlib.source += ['../posix/JackNetUnixSocket.cpp','../posix/JackPosixThread.cpp', '../posix/JackPosixMutex.cpp', '../linux/JackLinuxTime.c']
netlib.env.append_value('CPPFLAGS', '-fvisibility=hidden')



+ 32
- 0
example-clients/reload.c View File

@@ -0,0 +1,32 @@
#include <stdio.h>
#include <string.h>
#include <jack/jack.h>


int main(int argc, char* argv[])
{
if (argc < 2) {
printf("usage: %s [server_name [server_name ...]]", argv[0]);
return 1;
}

const int client_count = argc - 1;
char** server_names = &argv[1];

jack_client_t* clients[client_count];

for (int i = 0; i < client_count; ++i) {
const jack_options_t options = (jack_options_t) (JackNoStartServer | JackServerName);
jack_status_t status;

printf("Connecting to JACK server %s\n", server_names[i]);
clients[i] = jack_client_open("reload", options, &status, server_names[i]);
jack_client_reload_master(clients[i]);
}

for (int i = 0; i < client_count; ++i) {
jack_client_close(clients[i]);
}

return 0;
}

+ 7
- 4
example-clients/wscript View File

@@ -31,6 +31,7 @@ example_programs = {
'jack_midi_latency_test' : 'midi_latency_test.c',
'jack_simdtests' : 'simdtests.cpp',
'jack_property' : 'property.c',
'jack_reload' : 'reload.c',
}

example_libs = {
@@ -49,6 +50,8 @@ def build(bld):
os_incdir = ['../linux', '../posix']
if bld.env['IS_MACOSX']:
os_incdir = ['../macosx', '../posix']
if bld.env['IS_QNX']:
os_incdir = ['../qnx', '../posix']
if bld.env['IS_SUN']:
os_incdir = ['../solaris', '../posix']
if bld.env['IS_WINDOWS']:
@@ -76,7 +79,7 @@ def build(bld):
prog.use = use
if bld.env['IS_LINUX']:
prog.use += ['RT', 'M']
if bld.env['IS_SUN']:
if bld.env['IS_SUN'] or bld.env['IS_QNX']:
prog.use += ['M']
#prog.cflags = ['-Wno-deprecated-declarations', '-Wno-misleading-indentation']
#prog.cxxflags = ['-Wno-deprecated-declarations', '-Wno-misleading-indentation']
@@ -90,7 +93,7 @@ def build(bld):
prog.use = ['clientlib']
if bld.env['IS_LINUX']:
prog.use += ['RT', 'READLINE']
if bld.env['IS_MACOSX']:
if bld.env['IS_MACOSX'] or bld.env['IS_QNX']:
prog.use += ['READLINE']
if bld.env['IS_WINDOWS']:
prog.use += ['READLINE']
@@ -101,7 +104,7 @@ def build(bld):
prog.includes = os_incdir + ['../common/jack', '../common']
prog.source = 'capture_client.c'
prog.use = ['clientlib']
if bld.env['IS_MACOSX']:
if bld.env['IS_MACOSX'] or bld.env['IS_QNX']:
prog.use += ['SNDFILE']
if bld.env['IS_LINUX']:
prog.use += ['RT', 'SNDFILE']
@@ -111,7 +114,7 @@ def build(bld):
prog.uselib = ['SNDFILE']
prog.target = 'jack_rec'

if bld.env['IS_LINUX'] or bld.env['IS_MACOSX']:
if bld.env['IS_LINUX'] or bld.env['IS_MACOSX'] or bld.env['IS_QNX']:
prog = bld(features = 'c cprogram')
prog.includes = os_incdir + ['.', '..', '../common/jack', '../common']
prog.source = ['netsource.c', '../common/netjack_packet.c']


+ 437
- 181
linux/alsa/JackAlsaDriver.cpp View File

@@ -32,6 +32,11 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#include <sys/types.h>
#include <sys/time.h>
#include <string.h>
#include <sstream>
#include <fstream>
#include <algorithm>
#include <cctype>
#include <vector>

#include "JackAlsaDriver.h"
#include "JackEngineControl.h"
@@ -126,7 +131,7 @@ void JackAlsaDriver::UpdateLatencies()
int JackAlsaDriver::Attach()
{
JackPort* port;
jack_port_id_t port_index;
jack_port_id_t port_id;
unsigned long port_flags = (unsigned long)CaptureDriverFlags;
char name[REAL_JACK_PORT_NAME_SIZE+1];
char alias[REAL_JACK_PORT_NAME_SIZE+1];
@@ -145,41 +150,47 @@ int JackAlsaDriver::Attach()

jack_log("JackAlsaDriver::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) {
for (int i = 0, port_list_index = 0; i < alsa_driver->devices_c_count; ++i) {
alsa_device_t *device = &alsa_driver->devices[i];
for (int j = 0; j < device->capture_nchannels; ++j, ++port_list_index) {
snprintf(name, sizeof(name), "%s:capture_%d", fClientControl.fName, port_list_index + 1);
snprintf(alias, sizeof(alias), "%s:%s:capture_%d", fAliasName, device->capture_name, j + 1);
if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, (JackPortFlags)port_flags, fEngineControl->fBufferSize, &port_id) < 0) {
jack_error("driver: cannot register port for %s", name);
return -1;
return -1;
}
port = fGraphManager->GetPort(port_id);
port->SetAlias(alias);
fCapturePortList[port_list_index] = port_id;
jack_log("JackAlsaDriver::Attach fCapturePortList[i] %ld ", port_id);
}
port = fGraphManager->GetPort(port_index);
port->SetAlias(alias);
fCapturePortList[i] = port_index;
jack_log("JackAlsaDriver::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("JackAlsaDriver::Attach fPlaybackPortList[i] %ld ", port_index);
for (int i = 0, port_list_index = 0; i < alsa_driver->devices_p_count; ++i) {
alsa_device_t *device = &alsa_driver->devices[i];
for (int j = 0; j < device->playback_nchannels; ++j, ++port_list_index) {
snprintf(name, sizeof(name), "%s:playback_%d", fClientControl.fName, port_list_index + 1);
snprintf(alias, sizeof(alias), "%s:%s:playback_%d", fAliasName, device->playback_name, j + 1);
if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, (JackPortFlags)port_flags, fEngineControl->fBufferSize, &port_id) < 0) {
jack_error("driver: cannot register port for %s", name);
return -1;
}
port = fGraphManager->GetPort(port_id);
port->SetAlias(alias);
fPlaybackPortList[port_list_index] = port_id;
jack_log("JackAlsaDriver::Attach fPlaybackPortList[i] %ld ", port_id);

// 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("ALSA: 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, port_list_index + 1);
if (fEngine->PortRegister(fClientControl.fRefNum, name, JACK_DEFAULT_AUDIO_TYPE, MonitorDriverFlags, fEngineControl->fBufferSize, &port_id) < 0) {
jack_error("ALSA: cannot register monitor port for %s", name);
} else {
fMonitorPortList[port_list_index] = port_id;
}
}
}
}
@@ -204,6 +215,7 @@ int JackAlsaDriver::Detach()
return JackAudioDriver::Detach();
}

#ifndef __QNXNTO__
extern "C" char* get_control_device_name(const char * device_name)
{
char * ctl_name;
@@ -233,7 +245,9 @@ extern "C" char* get_control_device_name(const char * device_name)

return ctl_name;
}
#endif

#ifndef __QNXNTO__
static int card_to_num(const char* device)
{
int err;
@@ -273,50 +287,47 @@ free:
fail:
return i;
}
#endif

int JackAlsaDriver::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 JackAlsaDriver::Open(alsa_driver_info_t info)
{
// Generic JackAudioDriver Open
if (JackAudioDriver::Open(nframes, samplerate, capturing, playing,
inchannels, outchannels, monitor, capture_driver_name, playback_driver_name,
capture_latency, playback_latency) != 0) {
if (JackAudioDriver::Open(
info.frames_per_period,
info.frame_rate,
info.devices_capture_size > 0,
info.devices_playback_size > 0,
-1,
-1,
info.monitor,
info.devices_capture_size > 0 ? info.devices[0].capture_name : "-",
info.devices_playback_size > 0 ? info.devices[0].playback_name : "-",
info.capture_latency,
info.playback_latency) != 0) {
return -1;
}

alsa_midi_t *midi = 0;
jack_log("JackAlsaDriver::Open capture_driver_name = %s", info.devices_capture_size > 0 ? info.devices[0].capture_name : "-");
jack_log("JackAlsaDriver::Open playback_driver_name = %s", info.devices_playback_size > 0 ? info.devices[0].playback_name : "-");

#ifndef __QNXNTO__
#ifndef __ANDROID__
if (strcmp(midi_driver_name, "seq") == 0)
midi = alsa_seqmidi_new((jack_client_t*)this, 0);
else if (strcmp(midi_driver_name, "raw") == 0)
midi = alsa_rawmidi_new((jack_client_t*)this);
if (strcmp(info.midi_name, "seq") == 0)
info.midi_driver = alsa_seqmidi_new((jack_client_t*)this, 0);
else if (strcmp(info.midi_name, "raw") == 0)
info.midi_driver = alsa_rawmidi_new((jack_client_t*)this);
#endif

// FIXME: needs adaptation for multiple drivers
if (JackServerGlobals::on_device_acquire != NULL) {
int capture_card = card_to_num(capture_driver_name);
int playback_card = card_to_num(playback_driver_name);
int capture_card = card_to_num(info.devices_capture_size > 0 ? info.devices[0].capture_name : "-");
int playback_card = card_to_num(info.devices_playback_size > 0 ? info.devices[0].playback_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);
jack_error("Audio device %s cannot be acquired...", info.devices_capture_size > 0 ? info.devices[0].capture_name : "-");
return -1;
}
}
@@ -324,7 +335,7 @@ int JackAlsaDriver::Open(jack_nframes_t nframes,
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);
jack_error("Audio device %s cannot be acquired...",info.devices_playback_size > 0 ? info.devices[0].playback_name : "-" );
if (capture_card >= 0) {
snprintf(audio_name, sizeof(audio_name), "Audio%d", capture_card);
JackServerGlobals::on_device_release(audio_name);
@@ -333,40 +344,56 @@ int JackAlsaDriver::Open(jack_nframes_t nframes,
}
}
}
#endif

fDriver = alsa_driver_new ((char*)"alsa_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) {
// ALSA driver may have changed the in/out values
fCaptureChannels = ((alsa_driver_t *)fDriver)->capture_nchannels;
fPlaybackChannels = ((alsa_driver_t *)fDriver)->playback_nchannels;
if (JackServerGlobals::on_device_reservation_loop != NULL) {
device_reservation_loop_running = true;
if (JackPosixThread::StartImp(&fReservationLoopThread, 0, 0, on_device_reservation_loop, NULL) != 0) {
device_reservation_loop_running = false;
fDriver = alsa_driver_new ((char*)"alsa_pcm", info, NULL);
if (!fDriver) {
Close();
return -1;
}

/* we need to initialize variables for all devices, mainly channels count since this is required by Jack to setup ports */
UpdateDriverTargetState(DriverMode::Init);

if (alsa_driver_open((alsa_driver_t *)fDriver) < 0) {
Close();
return -1;
}

/* we are starting with all alsa devices closed, therfore populate jack channels based on user hint */
if (info.features & ALSA_DRIVER_FEAT_BACKEND_EVAL_ON_INIT && info.features & ALSA_DRIVER_FEAT_BACKEND_CLOSE_IDLE) {
for (size_t i = 0; i < std::max(info.devices_capture_size, info.devices_playback_size); ++i) {
if (i < info.devices_capture_size && info.devices[i].capture_channels < 1) {
jack_error ("invalid or missing channels parameter with '-x' option 'start-closed' for device C: '%s'", info.devices[i].capture_name);
Close();
return -1;
}

if (i < info.devices_playback_size && info.devices[i].playback_channels < 1) {
jack_error ("invalid or missing channels parameter with '-x' option 'start-closed' for device P: '%s'", info.devices[i].playback_name);
Close();
return -1;
}

fCaptureChannels += info.devices[i].capture_channels;
fPlaybackChannels += info.devices[i].playback_channels;
}
return 0;
/* in case we really opened alsa devices, channel information is generated by driver */
} else {
Close();
return -1;
fCaptureChannels = ((alsa_driver_t *)fDriver)->capture_nchannels;
fPlaybackChannels = ((alsa_driver_t *)fDriver)->playback_nchannels;
}

#ifndef __QNXNTO__
if (JackServerGlobals::on_device_reservation_loop != NULL) {
device_reservation_loop_running = true;
if (JackPosixThread::StartImp(&fReservationLoopThread, 0, 0, on_device_reservation_loop, NULL) != 0) {
device_reservation_loop_running = false;
}
}
#endif

return 0;
}

int JackAlsaDriver::Close()
@@ -374,15 +401,20 @@ int JackAlsaDriver::Close()
// Generic audio driver close
int res = JackAudioDriver::Close();

UpdateDriverTargetState(DriverMode::Shutdown);
alsa_driver_close((alsa_driver_t *)fDriver);

if (fDriver) {
alsa_driver_delete((alsa_driver_t*)fDriver);
}

#ifndef __QNXNTO__
if (device_reservation_loop_running) {
device_reservation_loop_running = false;
JackPosixThread::StopImp(fReservationLoopThread);
}

// FIXME: needs adaptation for multiple drivers
if (JackServerGlobals::on_device_release != NULL)
{
char audio_name[32];
@@ -398,6 +430,7 @@ int JackAlsaDriver::Close()
JackServerGlobals::on_device_release(audio_name);
}
}
#endif

return res;
}
@@ -423,28 +456,39 @@ int JackAlsaDriver::Stop()
return res;
}

int JackAlsaDriver::Reload()
{
UpdateDriverTargetState(DriverMode::Runtime);

alsa_driver_t* driver = (alsa_driver_t*) fDriver;
if (alsa_driver_close (driver) < 0) {
jack_error("JackAlsaDriver::Reload close failed");
return -1;
}
if (alsa_driver_open (driver) < 0) {
jack_error("JackAlsaDriver::Reload open failed");
return -1;
}

return 0;
}

int JackAlsaDriver::Read()
{
/* Taken from alsa_driver_run_cycle */
int wait_status;
jack_nframes_t nframes;
alsa_driver_wait_status_t wait_status;
jack_nframes_t nframes = 0;
fDelayedUsecs = 0.f;

retry:

nframes = alsa_driver_wait((alsa_driver_t *)fDriver, -1, &wait_status, &fDelayedUsecs);

if (wait_status < 0)
return -1; /* driver failed */
/* wait until all devices have some data available */
do {
nframes = alsa_driver_wait((alsa_driver_t *)fDriver, -1, &wait_status, &fDelayedUsecs);

if (nframes == 0) {
/* we detected an xrun and restarted: notify
* clients about the delay.
*/
jack_log("ALSA XRun wait_status = %d", wait_status);
NotifyXRun(fBeginDateUst, fDelayedUsecs);
goto retry; /* recoverable error*/
}
if (wait_status != ALSA_DRIVER_WAIT_OK) {
jack_error("JackAlsaDriver::Read wait failed, xrun recovery");
goto retry;
}
} while (nframes == 0);

if (nframes != fEngineControl->fBufferSize)
jack_log("JackAlsaDriver::Read warning fBufferSize = %ld nframes = %ld", fEngineControl->fBufferSize, nframes);
@@ -452,20 +496,45 @@ retry:
// Has to be done before read
JackDriver::CycleIncTime();

return alsa_driver_read((alsa_driver_t *)fDriver, fEngineControl->fBufferSize);
if (alsa_driver_read((alsa_driver_t *)fDriver, fEngineControl->fBufferSize) != 0) {
jack_error("JackAlsaDriver::Read read failed, xrun recovery");
goto retry;
}

return 0;

retry:
/* we detected an xrun and restarted: notify
* clients about the delay.
*/
jack_error("JackAlsaDriver::Read failed, xrun recovery");
alsa_driver_xrun_recovery((alsa_driver_t *)fDriver, &fDelayedUsecs);
NotifyXRun(fBeginDateUst, fDelayedUsecs);

return -1;
}

int JackAlsaDriver::Write()
{
return alsa_driver_write((alsa_driver_t *)fDriver, fEngineControl->fBufferSize);
if (alsa_driver_write((alsa_driver_t *)fDriver, fEngineControl->fBufferSize) != 0) {
jack_error("JackAlsaDriver::Write failed, xrun recovery");
alsa_driver_xrun_recovery((alsa_driver_t *)fDriver, &fDelayedUsecs);
NotifyXRun(fBeginDateUst, fDelayedUsecs);
return -1;
}

return 0;
}

void JackAlsaDriver::ReadInputAux(jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nread)
void JackAlsaDriver::ReadInputAux(alsa_device_t *device, jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_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);
alsa_driver_read_from_channel((alsa_driver_t *)fDriver, chn, buf + nread, contiguous);
/* global channel offset to fCapturePortList of this capture alsa device */
channel_t port_n = device->capture_channel_offset;

for (channel_t chn = 0; chn < device->capture_nchannels; ++chn, ++port_n) {
if (fGraphManager->GetConnectionsNum(fCapturePortList[port_n]) > 0) {
jack_default_audio_sample_t* buf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fCapturePortList[port_n], orig_nframes);
alsa_driver_read_from_channel((alsa_driver_t *)fDriver, device, chn, buf + nread, contiguous);
}
}
}
@@ -499,16 +568,69 @@ int JackAlsaDriver::PortSetDefaultMetadata(jack_port_id_t port_id, const char* p
return fEngine->PortSetDefaultMetadata(fClientControl.fRefNum, port_id, pretty_name);
}

void JackAlsaDriver::WriteOutputAux(jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nwritten)
int JackAlsaDriver::UpdateDriverTargetState(DriverMode mode)
{
for (int chn = 0; chn < fPlaybackChannels; chn++) {
int c_list_index = 0, p_list_index = 0;
alsa_driver_t* driver = (alsa_driver_t*) fDriver;

for (int i = 0; i < driver->devices_count; ++i) {
alsa_device_t *device = &driver->devices[i];

int capture_connections_count = 0;
for (int j = 0; j < device->capture_nchannels; ++j) {
capture_connections_count += fGraphManager->GetConnectionsNum(fCapturePortList[c_list_index]);
c_list_index++;
}
device->capture_target_state = TargetState(mode, capture_connections_count);

int playback_connections_count = 0;
for (int j = 0; j < device->playback_nchannels; ++j) {
playback_connections_count += fGraphManager->GetConnectionsNum(fPlaybackPortList[p_list_index]);
p_list_index++;
}
device->playback_target_state = TargetState(mode, playback_connections_count);
}

return 0;
}

int JackAlsaDriver::TargetState(DriverMode mode, int connections_count)
{
alsa_driver_t* driver = (alsa_driver_t*) fDriver;

if (mode == DriverMode::Shutdown) {
return SND_PCM_STATE_NOTREADY;
}

if (connections_count > 0) {
return SND_PCM_STATE_RUNNING;
}

// evaluation during init is disabled by user option
if (mode == DriverMode::Init && !(driver->features & ALSA_DRIVER_FEAT_BACKEND_EVAL_ON_INIT)) {
return SND_PCM_STATE_RUNNING;
}

if (driver->features & ALSA_DRIVER_FEAT_BACKEND_CLOSE_IDLE) {
return SND_PCM_STATE_NOTREADY;
}

return SND_PCM_STATE_PREPARED;
}

void JackAlsaDriver::WriteOutputAux(alsa_device_t *device, jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nwritten)
{
/* global channel offset to fPlaybackPortList of this playback alsa device */
channel_t port_n = device->playback_channel_offset;

for (channel_t chn = 0; chn < device->playback_nchannels; ++chn, ++port_n) {
// 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);
alsa_driver_write_to_channel(((alsa_driver_t *)fDriver), chn, buf + nwritten, contiguous);
if (fGraphManager->GetConnectionsNum(fPlaybackPortList[port_n]) > 0) {
jack_default_audio_sample_t* buf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fPlaybackPortList[port_n], orig_nframes);
alsa_driver_write_to_channel(((alsa_driver_t *)fDriver), device, 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);
if (fWithMonitorPorts && fGraphManager->GetConnectionsNum(fMonitorPortList[port_n]) > 0) {
jack_default_audio_sample_t* monbuf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fMonitorPortList[port_n], orig_nframes);
memcpy(monbuf + nwritten, buf + nwritten, contiguous * sizeof(jack_default_audio_sample_t));
}
}
@@ -578,6 +700,7 @@ extern "C"
{
#endif

#ifndef __QNXNTO__
static
jack_driver_param_constraint_desc_t *
enum_alsa_devices()
@@ -667,6 +790,7 @@ fail:
jack_constraint_free(constraint_ptr);
return NULL;
}
#endif

static int
dither_opt (char c, DitherAlgorithm* dither)
@@ -705,11 +829,14 @@ SERVER_EXPORT const jack_driver_desc_t* driver_get_descriptor ()
desc = jack_driver_descriptor_construct("alsa", JackDriverMaster, "Linux ALSA API based audio backend", &filler);

strcpy(value.str, "hw:0");
#ifndef __QNXNTO__
#ifdef __ANDROID__
jack_driver_descriptor_add_parameter(desc, &filler, "device", 'd', JackDriverParamString, &value, NULL, "ALSA device name", NULL);
#else
jack_driver_descriptor_add_parameter(desc, &filler, "device", 'd', JackDriverParamString, &value, enum_alsa_devices(), "ALSA device name", NULL);
#endif
#endif


strcpy(value.str, "none");
jack_driver_descriptor_add_parameter(desc, &filler, "capture", 'C', JackDriverParamString, &value, NULL, "Provide capture ports. Optionally set device", NULL);
@@ -753,9 +880,9 @@ SERVER_EXPORT const jack_driver_desc_t* driver_get_descriptor ()
"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);
strcpy(value.str, "none");
jack_driver_descriptor_add_parameter(desc, &filler, "inchannels", 'i', JackDriverParamString, &value, NULL, "List of device capture channels (defaults to hw max)", NULL);
jack_driver_descriptor_add_parameter(desc, &filler, "outchannels", 'o', JackDriverParamString, &value, NULL, "List of device playback channels (defaults to hw 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);
@@ -778,33 +905,94 @@ SERVER_EXPORT const jack_driver_desc_t* driver_get_descriptor ()
"ALSA MIDI driver",
NULL);

value.i = 0;
jack_driver_descriptor_add_parameter(desc, &filler, "eval-on-init", 'x', JackDriverParamBool, &value, NULL, "Do not start ALSA devices on jack startup", NULL);

value.i = 0;
jack_driver_descriptor_add_parameter(desc, &filler, "close-idle", 'c', JackDriverParamBool, &value, NULL, "Close idle devices on alsa driver restart request", NULL);

value.i = 0;
jack_driver_descriptor_add_parameter(desc, &filler, "unlinked-devs", 'u', JackDriverParamBool, &value, NULL, "Do not link devices", NULL);

return desc;
}

struct array_string_t
{
enum flags {
none,
discard_duplicate,
};

std::vector<char*> data;
};

void array_string_free(struct array_string_t *obj)
{
if (obj == NULL) {
return;
}
for (size_t i = 0; i < obj->data.size(); ++i) {
free(obj->data[i]);
}
}

struct array_string_t array_string_split(const char *str, const char sep, array_string_t::flags flags = array_string_t::none)
{
struct array_string_t result;

std::stringstream stream;
stream << std::string(str);
if (stream.str().find(sep) == std::string::npos) {
result.data.push_back((char*) calloc(JACK_CLIENT_NAME_SIZE + 1, sizeof(char)));
strncpy(result.data[0], str, JACK_CLIENT_NAME_SIZE);
result.data[0][JACK_CLIENT_NAME_SIZE] = '\0';
return result;
}

std::string driver;
while (std::getline(stream, driver, sep)) {
driver.erase(std::remove_if(driver.begin(), driver.end(), isspace), driver.end());
if (std::find(result.data.begin(), result.data.end(), driver) != result.data.end() && (flags & array_string_t::discard_duplicate))
continue;
char *str = (char*) calloc(JACK_CLIENT_NAME_SIZE + 1, sizeof(char));
strncpy(str, driver.c_str(), JACK_CLIENT_NAME_SIZE);
str[JACK_CLIENT_NAME_SIZE] = '\0';
result.data.push_back(str);
}

return result;
}

static Jack::JackAlsaDriver* g_alsa_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 = "hw:0";
const char *capture_pcm_name = "hw:0";
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";

alsa_driver_info_t info = {};
info.devices = NULL;
info.midi_name = strdup("none");
info.hw_monitoring = FALSE;
info.hw_metering = FALSE;
info.monitor = FALSE;
info.soft_mode = FALSE;
info.frame_rate = 48000;
info.frames_per_period = 1024;
info.periods_n = 2;
info.dither = None;
info.shorts_first = FALSE;
info.capture_latency = 0;
info.playback_latency = 0;

char *capture_names_param = NULL;
char *playback_names_param = NULL;

char *capture_channels_param = NULL;
char *playback_channels_param = NULL;

int duplex = FALSE;

for (node = params; node; node = jack_slist_next (node)) {
param = (const jack_driver_param_t *) node->data;
@@ -812,112 +1000,175 @@ SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLocke
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);
capture_names_param = strdup (param->value.str);
jack_log("capture device %s", capture_names_param);
}
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);
playback_names_param = strdup (param->value.str);
jack_log("playback device %s", playback_names_param);
}
break;

case 'D':
playback = TRUE;
capture = TRUE;
duplex = 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);
playback_names_param = strdup (param->value.str);
capture_names_param = strdup (param->value.str);
jack_log("playback device %s", playback_names_param);
jack_log("capture device %s", capture_names_param);
}
break;

case 'H':
hw_monitoring = param->value.i;
info.hw_monitoring = param->value.i;
break;

case 'm':
monitor = param->value.i;
info.monitor = param->value.i;
break;

case 'M':
hw_metering = param->value.i;
info.hw_metering = param->value.i;
break;

case 'r':
srate = param->value.ui;
jack_log("apparent rate = %d", srate);
info.frame_rate = param->value.ui;
jack_log("apparent rate = %d", info.frame_rate);
break;

case 'p':
frames_per_interrupt = param->value.ui;
jack_log("frames per period = %d", frames_per_interrupt);
info.frames_per_period = param->value.ui;
jack_log("frames per period = %d", info.frames_per_period);
break;

case 'n':
user_nperiods = param->value.ui;
if (user_nperiods < 2) { /* enforce minimum value */
user_nperiods = 2;
info.periods_n = param->value.ui;
if (info.periods_n < 2) { /* enforce minimum value */
info.periods_n = 2;
}
break;

case 's':
soft_mode = param->value.i;
info.soft_mode = param->value.i;
break;

case 'z':
if (dither_opt (param->value.c, &dither)) {
if (dither_opt (param->value.c, &info.dither)) {
return NULL;
}
break;

case 'i':
user_capture_nchnls = param->value.ui;
capture_channels_param = strdup(param->value.str);
break;

case 'o':
user_playback_nchnls = param->value.ui;
playback_channels_param = strdup(param->value.str);
break;

case 'S':
shorts_first = param->value.i;
info.shorts_first = param->value.i;
break;

case 'I':
systemic_input_latency = param->value.ui;
info.capture_latency = param->value.ui;
break;

case 'O':
systemic_output_latency = param->value.ui;
info.playback_latency = param->value.ui;
break;

case 'X':
midi_driver = strdup(param->value.str);
free(info.midi_name);
info.midi_name = strdup(param->value.str);
break;

case 'x':
info.features |= param->value.i ? ALSA_DRIVER_FEAT_BACKEND_EVAL_ON_INIT : 0;
break;

case 'c':
info.features |= param->value.i ? ALSA_DRIVER_FEAT_BACKEND_CLOSE_IDLE : 0;
break;

case 'u':
info.features |= param->value.i ? ALSA_DRIVER_FEAT_UNLINKED_DEVS : 0;
break;
}
}

/* duplex is the default */
if (!capture && !playback) {
capture = TRUE;
playback = TRUE;
if (!capture_names_param && !playback_names_param) {
duplex = TRUE;
}

if (duplex) {
if (!capture_names_param) {
capture_names_param = strdup("hw:0");
}
if (!playback_names_param) {
playback_names_param = strdup("hw:0");
}
}

struct array_string_t capture_names = {};
if (capture_names_param) {
capture_names = array_string_split(capture_names_param, ' ', array_string_t::discard_duplicate);
free(capture_names_param);
}

struct array_string_t playback_names = {};
if (playback_names_param) {
playback_names = array_string_split(playback_names_param, ' ', array_string_t::discard_duplicate);
free(playback_names_param);
}

struct array_string_t capture_channels = {};
if (capture_channels_param) {
capture_channels = array_string_split(capture_channels_param, ' ');
free(capture_channels_param);
}

struct array_string_t playback_channels = {};
if (playback_channels_param) {
playback_channels = array_string_split(playback_channels_param, ' ');
free(playback_channels_param);
}

info.devices_capture_size = capture_names.data.size();
info.devices_playback_size = playback_names.data.size();
info.devices = (alsa_device_info_t*) calloc(std::max(info.devices_capture_size, info.devices_playback_size), sizeof(alsa_device_info_t));
for (size_t i = 0; i < std::max(info.devices_capture_size, info.devices_playback_size); ++i) {
if (i < capture_names.data.size()) {
info.devices[i].capture_name = strdup(capture_names.data[i]);
}
if (i < capture_channels.data.size()) {
info.devices[i].capture_channels = atoi(capture_channels.data[i]);
}
if (i < playback_names.data.size()) {
info.devices[i].playback_name = strdup(playback_names.data[i]);
}
if (i < playback_channels.data.size()) {
info.devices[i].playback_channels = atoi(playback_channels.data[i]);
}
}

array_string_free(&capture_names);
array_string_free(&playback_names);
array_string_free(&capture_channels);
array_string_free(&playback_channels);

g_alsa_driver = new Jack::JackAlsaDriver("system", "alsa_pcm", engine, table);
Jack::JackDriverClientInterface* threaded_driver = new Jack::JackThreadedDriver(g_alsa_driver);
// Special open for ALSA driver...
if (g_alsa_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) {
if (g_alsa_driver->Open(info) == 0) {
return threaded_driver;
} else {
delete threaded_driver; // Delete the decorated driver
@@ -927,9 +1178,9 @@ SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLocke

// Code to be used in alsa_driver.c

void ReadInput(jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nread)
void ReadInput(alsa_device_t *device, jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nread)
{
g_alsa_driver->ReadInputAux(orig_nframes, contiguous, nread);
g_alsa_driver->ReadInputAux(device, orig_nframes, contiguous, nread);
}
void MonitorInput()
{
@@ -939,9 +1190,9 @@ void ClearOutput()
{
g_alsa_driver->ClearOutputAux();
}
void WriteOutput(jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nwritten)
void WriteOutput(alsa_device_t *device, jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nwritten)
{
g_alsa_driver->WriteOutputAux(orig_nframes, contiguous, nwritten);
g_alsa_driver->WriteOutputAux(device, orig_nframes, contiguous, nwritten);
}
void SetTime(jack_time_t time)
{
@@ -951,8 +1202,13 @@ void SetTime(jack_time_t time)
int Restart()
{
int res;
if ((res = g_alsa_driver->Stop()) == 0) {
res = g_alsa_driver->Start();
if ((res = g_alsa_driver->Stop()) != 0) {
jack_error("restart: stop driver failed");
return res;
}
if ((res = g_alsa_driver->Start()) != 0) {
jack_error("restart: start driver failed");
return res;
}
return res;
}


+ 14
- 20
linux/alsa/JackAlsaDriver.h View File

@@ -38,6 +38,12 @@ class JackAlsaDriver : public JackAudioDriver

private:

enum DriverMode {
Init,
Runtime,
Shutdown,
};

jack_driver_t* fDriver;
jack_native_thread_t fReservationLoopThread;

@@ -51,24 +57,7 @@ class JackAlsaDriver : public JackAudioDriver
virtual ~JackAlsaDriver()
{}

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(alsa_driver_info_t info);

int Close();
int Attach();
@@ -76,6 +65,7 @@ class JackAlsaDriver : public JackAudioDriver

int Start();
int Stop();
int Reload();

int Read();
int Write();
@@ -88,14 +78,18 @@ class JackAlsaDriver : public JackAudioDriver

int SetBufferSize(jack_nframes_t buffer_size);

void ReadInputAux(jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nread);
void ReadInputAux(alsa_device_t *device, jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nread);
void MonitorInputAux();
void ClearOutputAux();
void WriteOutputAux(jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nwritten);
void WriteOutputAux(alsa_device_t *device, jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nwritten);
void SetTimetAux(jack_time_t time);

int PortSetDefaultMetadata(jack_port_id_t port_id, const char* pretty_name);

int UpdateDriverTargetState(DriverMode mode);

int TargetState(DriverMode mode, int connections_count);

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


+ 1813
- 938
linux/alsa/alsa_driver.c
File diff suppressed because it is too large
View File


+ 201
- 107
linux/alsa/alsa_driver.h View File

@@ -21,7 +21,12 @@
#ifndef __jack_alsa_driver_h__
#define __jack_alsa_driver_h__

#ifdef __QNXNTO__
#include <sys/asoundlib.h>
#else
#include <alsa/asoundlib.h>
#endif

#include "bitset.h"

#if __BYTE_ORDER == __LITTLE_ENDIAN
@@ -41,6 +46,34 @@
#include "memops.h"
#include "alsa_midi.h"

#ifdef __QNXNTO__
#define SND_PCM_FORMAT_S16_LE SND_PCM_SFMT_S16_LE
#define SND_PCM_FORMAT_S16_BE SND_PCM_SFMT_S16_BE
#define SND_PCM_FORMAT_S24_LE SND_PCM_SFMT_S24_LE
#define SND_PCM_FORMAT_S24_BE SND_PCM_SFMT_S24_BE
#define SND_PCM_FORMAT_S32_LE SND_PCM_SFMT_S32_LE
#define SND_PCM_FORMAT_S32_BE SND_PCM_SFMT_S32_BE
#define SND_PCM_FORMAT_FLOAT_LE SND_PCM_SFMT_FLOAT_LE
#define SND_PCM_FORMAT_UNKNOWN SND_PCM_SFMT_SPECIAL
#define SND_PCM_STATE_PREPARED SND_PCM_STATUS_PREPARED
#define SND_PCM_STATE_SUSPENDED SND_PCM_STATUS_SUSPENDED
#define SND_PCM_STATE_XRUN SND_PCM_STATUS_UNDERRUN
#define SND_PCM_STATE_RUNNING SND_PCM_STATUS_RUNNING
#define SND_PCM_STATE_NOTREADY SND_PCM_STATUS_NOTREADY
#define SND_PCM_STREAM_PLAYBACK SND_PCM_CHANNEL_PLAYBACK
#define SND_PCM_STREAM_CAPTURE SND_PCM_CHANNEL_CAPTURE

typedef unsigned long snd_pcm_uframes_t;
typedef signed long snd_pcm_sframes_t;
typedef int32_t alsa_driver_default_format_t;
#else
#define SND_PCM_STATE_NOTREADY (SND_PCM_STATE_LAST + 1)
#endif

#define ALSA_DRIVER_FEAT_BACKEND_EVAL_ON_INIT (1 << 0)
#define ALSA_DRIVER_FEAT_BACKEND_CLOSE_IDLE (1 << 1)
#define ALSA_DRIVER_FEAT_UNLINKED_DEVS (1 << 2)

#ifdef __cplusplus
extern "C"
{
@@ -54,61 +87,105 @@ typedef void (*WriteCopyFunction) (char *dst, jack_default_audio_sample_t *src,
unsigned long dst_skip_bytes,
dither_state_t *state);

typedef struct _alsa_device {
#ifdef __QNXNTO__
unsigned int playback_sample_format;
unsigned int capture_sample_format;
void *capture_areas;
void *playback_areas;
void *capture_areas_ptr;
void *playback_areas_ptr;
#else
snd_pcm_format_t playback_sample_format;
snd_pcm_format_t capture_sample_format;
const snd_pcm_channel_area_t *capture_areas;
const snd_pcm_channel_area_t *playback_areas;
#endif
snd_pcm_t *playback_handle;
snd_pcm_t *capture_handle;

char *playback_name;
char *capture_name;

char **playback_addr;
char **capture_addr;

channel_t playback_channel_offset;
channel_t capture_channel_offset;

channel_t playback_nchannels;
channel_t capture_nchannels;
channel_t max_nchannels;
channel_t user_nchannels;

bitset_t channels_not_done;
bitset_t channels_done;

char quirk_bswap;

ReadCopyFunction read_via_copy;
WriteCopyFunction write_via_copy;

unsigned long interleave_unit;
unsigned long *capture_interleave_skip;
unsigned long *playback_interleave_skip;

char playback_interleaved;
char capture_interleaved;

unsigned long *silent;

unsigned long playback_sample_bytes;
unsigned long capture_sample_bytes;

/* device is 'snd_pcm_link' to a group, only 1 group of linked devices is allowed */
int capture_linked;
int playback_linked;

int capture_xrun_count;
int playback_xrun_count;

/* desired state of device, decided by JackAlsaDriver */
int capture_target_state;
int playback_target_state;

jack_hardware_t *hw;
snd_ctl_t *ctl_handle;
char *alsa_driver;

JSList *clock_sync_listeners;
pthread_mutex_t clock_sync_lock;
unsigned long next_clock_sync_listener_id;
} alsa_device_t;

typedef struct _alsa_driver {

JACK_DRIVER_NT_DECL

#ifndef __QNXNTO__
snd_pcm_hw_params_t *playback_hw_params;
snd_pcm_sw_params_t *playback_sw_params;
snd_pcm_hw_params_t *capture_hw_params;
snd_pcm_sw_params_t *capture_sw_params;
#endif
int poll_timeout_ms;
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 *alsa_name_playback;
char *alsa_name_capture;
char *alsa_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_hw_params_t *playback_hw_params;
snd_pcm_sw_params_t *playback_sw_params;
snd_pcm_hw_params_t *capture_hw_params;
snd_pcm_sw_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;

@@ -116,28 +193,17 @@ typedef struct _alsa_driver {
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 preferred_sample_bytes;

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;
@@ -146,83 +212,115 @@ typedef struct _alsa_driver {
alsa_midi_t *midi;
int xrun_recovery;

alsa_device_t *devices;
int devices_count;
int devices_c_count;
int devices_p_count;

int features;
} alsa_driver_t;

typedef struct _alsa_device_info {
char *capture_name;
char *playback_name;

int capture_channels;
int playback_channels;
} alsa_device_info_t;

typedef struct _alsa_driver_info {
alsa_device_info_t *devices;
uint32_t devices_capture_size;
uint32_t devices_playback_size;

char *midi_name;
alsa_midi_t *midi_driver;

jack_nframes_t frame_rate;
jack_nframes_t frames_per_period;
int periods_n;

DitherAlgorithm dither;

int shorts_first;

jack_nframes_t capture_latency;
jack_nframes_t playback_latency;

// these 4 should be reworked as struct.features
int hw_monitoring;
int hw_metering;
int monitor;
int soft_mode;

int features;
} alsa_driver_info_t;

static inline void
alsa_driver_mark_channel_done (alsa_driver_t *driver, channel_t chn) {
bitset_remove (driver->channels_not_done, chn);
driver->silent[chn] = 0;
alsa_driver_mark_channel_done (alsa_driver_t *driver, alsa_device_t *device, channel_t chn) {
bitset_remove (device->channels_not_done, chn);
device->silent[chn] = 0;
}

static inline void
alsa_driver_silence_on_channel (alsa_driver_t *driver, channel_t chn,
alsa_driver_silence_on_channel (alsa_driver_t *driver, alsa_device_t *device, channel_t chn,
jack_nframes_t nframes) {
if (driver->playback_interleaved) {
if (device->playback_interleaved) {
memset_interleave
(driver->playback_addr[chn],
0, nframes * driver->playback_sample_bytes,
driver->interleave_unit,
driver->playback_interleave_skip[chn]);
(device->playback_addr[chn],
0, nframes * device->playback_sample_bytes,
device->interleave_unit,
device->playback_interleave_skip[chn]);
} else {
memset (driver->playback_addr[chn], 0,
nframes * driver->playback_sample_bytes);
memset (device->playback_addr[chn], 0,
nframes * device->playback_sample_bytes);
}
alsa_driver_mark_channel_done (driver,chn);
alsa_driver_mark_channel_done (driver, device, chn);
}

static inline void
alsa_driver_silence_on_channel_no_mark (alsa_driver_t *driver, channel_t chn,
alsa_driver_silence_on_channel_no_mark (alsa_driver_t *driver, alsa_device_t *device, channel_t chn,
jack_nframes_t nframes) {
if (driver->playback_interleaved) {
if (device->playback_interleaved) {
memset_interleave
(driver->playback_addr[chn],
0, nframes * driver->playback_sample_bytes,
driver->interleave_unit,
driver->playback_interleave_skip[chn]);
(device->playback_addr[chn],
0, nframes * device->playback_sample_bytes,
device->interleave_unit,
device->playback_interleave_skip[chn]);
} else {
memset (driver->playback_addr[chn], 0,
nframes * driver->playback_sample_bytes);
memset (device->playback_addr[chn], 0,
nframes * device->playback_sample_bytes);
}
}

static inline void
alsa_driver_read_from_channel (alsa_driver_t *driver,
alsa_device_t *device,
channel_t channel,
jack_default_audio_sample_t *buf,
jack_nframes_t nsamples)
{
driver->read_via_copy (buf,
driver->capture_addr[channel],
device->read_via_copy (buf,
device->capture_addr[channel],
nsamples,
driver->capture_interleave_skip[channel]);
device->capture_interleave_skip[channel]);
}

static inline void
alsa_driver_write_to_channel (alsa_driver_t *driver,
alsa_device_t *device,
channel_t channel,
jack_default_audio_sample_t *buf,
jack_nframes_t nsamples)
{
driver->write_via_copy (driver->playback_addr[channel],
device->write_via_copy (device->playback_addr[channel],
buf,
nsamples,
driver->playback_interleave_skip[channel],
device->playback_interleave_skip[channel],
driver->dither_state+channel);
alsa_driver_mark_channel_done (driver, channel);
alsa_driver_mark_channel_done (driver, device, channel);
}

void alsa_driver_silence_untouched_channels (alsa_driver_t *driver,
jack_nframes_t nframes);
void alsa_driver_set_clock_sync_status (alsa_driver_t *driver, channel_t chn,
ClockSyncStatus status);
int alsa_driver_listen_for_clock_sync_status (alsa_driver_t *,
ClockSyncListenerFunction,
void *arg);
int alsa_driver_stop_listen_for_clock_sync_status (alsa_driver_t *,
unsigned int);
void alsa_driver_clock_sync_notify (alsa_driver_t *, channel_t chn,
ClockSyncStatus);

int
alsa_driver_reset_parameters (alsa_driver_t *driver,
jack_nframes_t frames_per_cycle,
@@ -230,37 +328,31 @@ alsa_driver_reset_parameters (alsa_driver_t *driver,
jack_nframes_t rate);

jack_driver_t *
alsa_driver_new (char *name, char *playback_alsa_device,
char *capture_alsa_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,
alsa_midi_t *midi_driver
);
alsa_driver_new (char *name, alsa_driver_info_t info, jack_client_t *client);

void
alsa_driver_delete (alsa_driver_t *driver);

int
alsa_driver_open (alsa_driver_t *driver);

int
alsa_driver_start (alsa_driver_t *driver);

int
alsa_driver_stop (alsa_driver_t *driver);

int
alsa_driver_close (alsa_driver_t *driver);

typedef enum {
ALSA_DRIVER_WAIT_OK = 0,
ALSA_DRIVER_WAIT_ERROR = -1,
ALSA_DRIVER_WAIT_XRUN = -2,
} alsa_driver_wait_status_t;

jack_nframes_t
alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *status, float
alsa_driver_wait (alsa_driver_t *driver, int extra_fd, alsa_driver_wait_status_t *status, float
*delayed_usecs);

int
@@ -269,15 +361,17 @@ alsa_driver_read (alsa_driver_t *driver, jack_nframes_t nframes);
int
alsa_driver_write (alsa_driver_t* driver, jack_nframes_t nframes);

jack_time_t jack_get_microseconds(void);
int
alsa_driver_xrun_recovery (alsa_driver_t *driver, float *delayed_usecs);

// Code implemented in JackAlsaDriver.cpp

void ReadInput(jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nread);
void ReadInput(alsa_device_t *device, jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nread);
void MonitorInput();
void ClearOutput();
void WriteOutput(jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nwritten);
void WriteOutput(alsa_device_t *device, jack_nframes_t orig_nframes, snd_pcm_sframes_t contiguous, snd_pcm_sframes_t nwritten);
void SetTime(jack_time_t time);

int Restart();

#ifdef __cplusplus


+ 1
- 1
linux/alsa/generic.h View File

@@ -27,7 +27,7 @@ extern "C"
#endif

jack_hardware_t *
jack_alsa_generic_hw_new (alsa_driver_t *driver);
jack_alsa_generic_hw_new (alsa_device_t *device);

#ifdef __cplusplus
}


+ 1
- 1
linux/alsa/generic_hw.c View File

@@ -38,7 +38,7 @@ generic_release (jack_hardware_t *hw)
}

jack_hardware_t *
jack_alsa_generic_hw_new (alsa_driver_t *driver)
jack_alsa_generic_hw_new (alsa_device_t *device)

{
jack_hardware_t *hw;


+ 10
- 10
linux/alsa/hammerfall.c View File

@@ -62,7 +62,7 @@ hammerfall_broadcast_channel_status_change (hammerfall_t *h, int lock, int sync,
}

for (chn = lowchn; chn < highchn; chn++) {
alsa_driver_set_clock_sync_status (h->driver, chn, status);
alsa_driver_set_clock_sync_status (h->device, chn, status);
}
}

@@ -87,8 +87,8 @@ hammerfall_check_sync_state (hammerfall_t *h, int val, int adat_id)

/* XXX broken! fix for hammerfall light ! */

alsa_driver_set_clock_sync_status (h->driver, 24, status);
alsa_driver_set_clock_sync_status (h->driver, 25, status);
alsa_driver_set_clock_sync_status (h->device, 24, status);
alsa_driver_set_clock_sync_status (h->device, 25, status);

h->said_that_spdif_is_fine = TRUE;
}
@@ -153,7 +153,7 @@ hammerfall_set_input_monitor_mask (jack_hardware_t *hw, unsigned long mask)
snd_ctl_elem_value_set_integer (ctl, i, (mask & (1<<i)) ? 1 : 0);
}
if ((err = snd_ctl_elem_write (h->driver->ctl_handle, ctl)) != 0) {
if ((err = snd_ctl_elem_write (h->device->ctl_handle, ctl)) != 0) {
jack_error ("ALSA/Hammerfall: cannot set input monitoring (%s)", snd_strerror (err));
return -1;
}
@@ -188,7 +188,7 @@ hammerfall_change_sample_clock (jack_hardware_t *hw, SampleClockMode mode)
break;
}

if ((err = snd_ctl_elem_write (h->driver->ctl_handle, ctl)) < 0) {
if ((err = snd_ctl_elem_write (h->device->ctl_handle, ctl)) < 0) {
jack_error ("ALSA-Hammerfall: cannot set clock mode");
}

@@ -244,17 +244,17 @@ hammerfall_monitor_controls (void *arg)
snd_ctl_elem_value_set_id (sw[2], switch_id[2]);

while (1) {
if (snd_ctl_elem_read (h->driver->ctl_handle, sw[0])) {
if (snd_ctl_elem_read (h->device->ctl_handle, sw[0])) {
jack_error ("cannot read control switch 0 ...");
}
hammerfall_check_sync (h, sw[0]);

if (snd_ctl_elem_read (h->driver->ctl_handle, sw[1])) {
if (snd_ctl_elem_read (h->device->ctl_handle, sw[1])) {
jack_error ("cannot read control switch 0 ...");
}
hammerfall_check_sync (h, sw[1]);

if (snd_ctl_elem_read (h->driver->ctl_handle, sw[2])) {
if (snd_ctl_elem_read (h->device->ctl_handle, sw[2])) {
jack_error ("cannot read control switch 0 ...");
}
hammerfall_check_sync (h, sw[2]);
@@ -269,7 +269,7 @@ hammerfall_monitor_controls (void *arg)
#endif /* HAMMERFALL_MONITOR_CONTROLS */

jack_hardware_t *
jack_alsa_hammerfall_hw_new (alsa_driver_t *driver)
jack_alsa_hammerfall_hw_new (alsa_device_t *device)
{
jack_hardware_t *hw;
hammerfall_t *h;
@@ -293,7 +293,7 @@ jack_alsa_hammerfall_hw_new (alsa_driver_t *driver)
h->lock_status[2] = FALSE;
h->sync_status[2] = FALSE;
h->said_that_spdif_is_fine = FALSE;
h->driver = driver;
h->device = device;

h->monitor_interval.tv_sec = 1;
h->monitor_interval.tv_nsec = 0;


+ 2
- 2
linux/alsa/hammerfall.h View File

@@ -29,7 +29,7 @@ typedef struct
int sync_status[3];
int said_that_spdif_is_fine;
pthread_t monitor_thread;
alsa_driver_t *driver;
alsa_device_t *device;
struct timespec monitor_interval;
}
hammerfall_t;
@@ -39,7 +39,7 @@ extern "C"
{
#endif

jack_hardware_t *jack_alsa_hammerfall_hw_new (alsa_driver_t *driver);
jack_hardware_t *jack_alsa_hammerfall_hw_new (alsa_device_t *device);

#ifdef __cplusplus
}


+ 3
- 3
linux/alsa/hdsp.c View File

@@ -115,7 +115,7 @@ static int hdsp_set_mixer_gain(jack_hardware_t *hw, int input_channel,
snd_ctl_elem_value_set_integer (ctl, 2, gain);

/* Commit the mixer value and check for errors */
if ((err = snd_ctl_elem_write (h->driver->ctl_handle, ctl)) != 0) {
if ((err = snd_ctl_elem_write (h->device->ctl_handle, ctl)) != 0) {
jack_error ("ALSA/HDSP: cannot set mixer gain (%s)", snd_strerror (err));
return -1;
}
@@ -206,7 +206,7 @@ hdsp_release (jack_hardware_t *hw)

/* Mostly copied directly from hammerfall.c */
jack_hardware_t *
jack_alsa_hdsp_hw_new (alsa_driver_t *driver)
jack_alsa_hdsp_hw_new (alsa_device_t *device)
{
jack_hardware_t *hw;
hdsp_t *h;
@@ -227,7 +227,7 @@ jack_alsa_hdsp_hw_new (alsa_driver_t *driver)
hw->get_hardware_power = hdsp_get_hardware_power;
h = (hdsp_t *) malloc (sizeof (hdsp_t));
h->driver = driver;
h->device = device;
hw->private_hw = h;

return hw;


+ 2
- 2
linux/alsa/hdsp.h View File

@@ -25,7 +25,7 @@

typedef struct
{
alsa_driver_t *driver;
alsa_device_t *device;
}
hdsp_t;

@@ -35,7 +35,7 @@ extern "C"
#endif

jack_hardware_t *
jack_alsa_hdsp_hw_new (alsa_driver_t *driver);
jack_alsa_hdsp_hw_new (alsa_device_t *device);

#ifdef __cplusplus
}


+ 4
- 4
linux/alsa/ice1712.c View File

@@ -47,7 +47,7 @@ ice1712_hw_monitor_toggle(jack_hardware_t *hw, int idx, int onoff)
} else {
snd_ctl_elem_value_set_enumerated (val, 0, 0);
}
if ((err = snd_ctl_elem_write (h->driver->ctl_handle, val)) != 0) {
if ((err = snd_ctl_elem_write (h->device->ctl_handle, val)) != 0) {
jack_error ("ALSA/ICE1712: (%d) cannot set input monitoring (%s)",
idx,snd_strerror (err));
return -1;
@@ -94,7 +94,7 @@ ice1712_release (jack_hardware_t *hw)


jack_hardware_t *
jack_alsa_ice1712_hw_new (alsa_driver_t *driver)
jack_alsa_ice1712_hw_new (alsa_device_t *device)
{
jack_hardware_t *hw;
ice1712_t *h;
@@ -113,14 +113,14 @@ jack_alsa_ice1712_hw_new (alsa_driver_t *driver)

h = (ice1712_t *) malloc (sizeof (ice1712_t));

h->driver = driver;
h->device = device;

/* Get the EEPROM (adopted from envy24control) */
h->eeprom = (ice1712_eeprom_t *) malloc (sizeof (ice1712_eeprom_t));
snd_ctl_elem_value_alloca (&val);
snd_ctl_elem_value_set_interface (val, SND_CTL_ELEM_IFACE_CARD);
snd_ctl_elem_value_set_name (val, "ICE1712 EEPROM");
if ((err = snd_ctl_elem_read (driver->ctl_handle, val)) < 0) {
if ((err = snd_ctl_elem_read (device->ctl_handle, val)) < 0) {
jack_error( "ALSA/ICE1712: Unable to read EEPROM contents (%s)\n", snd_strerror (err));
/* Recover? */
}


+ 2
- 2
linux/alsa/ice1712.h View File

@@ -59,7 +59,7 @@ ice1712_eeprom_t;

typedef struct
{
alsa_driver_t *driver;
alsa_device_t *device;
ice1712_eeprom_t *eeprom;
unsigned long active_channels;
}
@@ -70,7 +70,7 @@ extern "C"
{
#endif

jack_hardware_t *jack_alsa_ice1712_hw_new (alsa_driver_t *driver);
jack_hardware_t *jack_alsa_ice1712_hw_new (alsa_device_t *device);

#ifdef __cplusplus
}


+ 4
- 0
linux/alsa/usx2y.h View File

@@ -22,6 +22,8 @@
#ifndef __jack_usx2y_h__
#define __jack_usx2y_h__

#include <poll.h>

#define USX2Y_MAXPACK 50
#define USX2Y_MAXBUFFERMS 100
#define USX2Y_MAXSTRIDE 3
@@ -51,7 +53,9 @@ typedef struct snd_usX2Y_hwdep_pcm_shm snd_usX2Y_hwdep_pcm_shm_t;
typedef struct
{
alsa_driver_t *driver;
#ifndef __QNXNTO__
snd_hwdep_t *hwdep_handle;
#endif
struct pollfd pfds;
struct snd_usX2Y_hwdep_pcm_shm *hwdep_pcm_shm;
int playback_iso_start;


+ 1
- 1
posix/JackFifo.h View File

@@ -44,7 +44,7 @@ class SERVER_EXPORT JackFifo : public detail::JackSynchro

protected:

void BuildName(const char* name, const char* server_name, char* res);
void BuildName(const char* name, const char* server_name, char* res, int size);

public:



+ 86
- 0
qnx/JackAtomic_os.h View File

@@ -0,0 +1,86 @@
/*
Copyright (C) 2004-2008 Grame

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

*/

#ifndef __JackAtomic_linux__
#define __JackAtomic_linux__

#include "JackTypes.h"

#ifdef __PPC__

static inline int CAS(register UInt32 value, register UInt32 newvalue, register volatile void* addr)
{
register int result;
register UInt32 tmp;
asm volatile (
"# CAS \n"
" lwarx %4, 0, %1 \n" // creates a reservation on addr
" cmpw %4, %2 \n" // test value at addr
" bne- 1f \n"
" sync \n" // synchronize instructions
" stwcx. %3, 0, %1 \n" // if the reservation is not altered
// stores the new value at addr
" bne- 1f \n"
" li %0, 1 \n"
" b 2f \n"
"1: \n"
" li %0, 0 \n"
"2: \n"
: "=r" (result)
: "r" (addr), "r" (value), "r" (newvalue), "r" (tmp)
);
return result;
}

#endif

#if defined(__i386__) || defined(__x86_64__)

#define LOCK "lock ; "

static inline char CAS(volatile UInt32 value, UInt32 newvalue, volatile void* addr)
{
register char ret;
__asm__ __volatile__ (
"# CAS \n\t"
LOCK "cmpxchg %2, (%1) \n\t"
"sete %0 \n\t"
: "=a" (ret)
: "c" (addr), "d" (newvalue), "a" (value)
);
return ret;
}

#endif




#if !defined(__i386__) && !defined(__x86_64__) && !defined(__PPC__)


static inline char CAS(volatile UInt32 value, UInt32 newvalue, volatile void* addr)
{
return __sync_bool_compare_and_swap ((UInt32*)addr, value, newvalue);
}
#endif


#endif


+ 215
- 0
qnx/JackLinuxTime.c View File

@@ -0,0 +1,215 @@
/*
Copyright (C) 2001-2003 Paul Davis
Copyright (C) 2005 Jussi Laako
Copyright (C) 2004-2008 Grame

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

*/

#include "JackConstants.h"
#include "JackTime.h"
#include "JackTypes.h"
#include "JackError.h"

#include <stdint.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <inttypes.h>

jack_time_t (*_jack_get_microseconds)(void) = 0;

#if defined(__gnu_linux__) && (defined(__i386__) || defined(__x86_64__))
#define HPET_SUPPORT
#define HPET_MMAP_SIZE 1024
#define HPET_CAPS 0x000
#define HPET_PERIOD 0x004
#define HPET_COUNTER 0x0f0
#define HPET_CAPS_COUNTER_64BIT (1 << 13)
#if defined(__x86_64__)
typedef uint64_t hpet_counter_t;
#else
typedef uint32_t hpet_counter_t;
#endif
static int hpet_fd;
static unsigned char *hpet_ptr;
static uint32_t hpet_period; /* period length in femto secs */
static uint64_t hpet_offset = 0;
static uint64_t hpet_wrap;
static hpet_counter_t hpet_previous = 0;
#endif /* defined(__gnu_linux__) && (__i386__ || __x86_64__) */

#ifdef HPET_SUPPORT

static int jack_hpet_init ()
{
uint32_t hpet_caps;

hpet_fd = open("/dev/hpet", O_RDONLY);
if (hpet_fd < 0) {
jack_error ("This system has no accessible HPET device (%s)", strerror (errno));
return -1;
}

hpet_ptr = (unsigned char *) mmap(NULL, HPET_MMAP_SIZE,
PROT_READ, MAP_SHARED, hpet_fd, 0);
if (hpet_ptr == MAP_FAILED) {
jack_error ("This system has no mappable HPET device (%s)", strerror (errno));
close (hpet_fd);
return -1;
}

/* this assumes period to be constant. if needed,
it can be moved to the clock access function
*/
hpet_period = *((uint32_t *) (hpet_ptr + HPET_PERIOD));
hpet_caps = *((uint32_t *) (hpet_ptr + HPET_CAPS));
hpet_wrap = ((hpet_caps & HPET_CAPS_COUNTER_64BIT) &&
(sizeof(hpet_counter_t) == sizeof(uint64_t))) ?
0 : ((uint64_t) 1 << 32);

return 0;
}

static jack_time_t jack_get_microseconds_from_hpet (void)
{
hpet_counter_t hpet_counter;
long double hpet_time;

hpet_counter = *((hpet_counter_t *) (hpet_ptr + HPET_COUNTER));
if (hpet_counter < hpet_previous)
hpet_offset += hpet_wrap;
hpet_previous = hpet_counter;
hpet_time = (long double) (hpet_offset + hpet_counter) *
(long double) hpet_period * (long double) 1e-9;
return ((jack_time_t) (hpet_time + 0.5));
}

#else

static int jack_hpet_init ()
{
jack_error ("This version of JACK or this computer does not have HPET support.\n"
"Please choose a different clock source.");
return -1;
}

static jack_time_t jack_get_microseconds_from_hpet (void)
{
/* never called */
return 0;
}

#endif /* HPET_SUPPORT */

#define HAVE_CLOCK_GETTIME 1

#ifndef HAVE_CLOCK_GETTIME

static jack_time_t jack_get_microseconds_from_system (void)
{
jack_time_t jackTime;
struct timeval tv;

gettimeofday (&tv, NULL);
jackTime = (jack_time_t) tv.tv_sec * 1000000 + (jack_time_t) tv.tv_usec;
return jackTime;
}

#else

static jack_time_t jack_get_microseconds_from_system (void)
{
jack_time_t jackTime;
struct timespec time;

clock_gettime(CLOCK_MONOTONIC, &time);
jackTime = (jack_time_t) time.tv_sec * 1e6 +
(jack_time_t) time.tv_nsec / 1e3;
return jackTime;
}

#endif /* HAVE_CLOCK_GETTIME */


SERVER_EXPORT void JackSleep(long usec)
{
usleep(usec);
}

SERVER_EXPORT void InitTime()
{
/* nothing to do on a generic system - we use the system clock */
}

SERVER_EXPORT void EndTime()
{}

void SetClockSource(jack_timer_type_t source)
{
jack_log("Clock source : %s", ClockSourceName(source));

switch (source)
{
case JACK_TIMER_HPET:
if (jack_hpet_init () == 0) {
_jack_get_microseconds = jack_get_microseconds_from_hpet;
} else {
_jack_get_microseconds = jack_get_microseconds_from_system;
}
break;

case JACK_TIMER_SYSTEM_CLOCK:
default:
_jack_get_microseconds = jack_get_microseconds_from_system;
break;
}
}

const char* ClockSourceName(jack_timer_type_t source)
{
switch (source) {
case JACK_TIMER_HPET:
return "hpet";
case JACK_TIMER_SYSTEM_CLOCK:
#ifdef HAVE_CLOCK_GETTIME
return "system clock via clock_gettime";
#else
return "system clock via gettimeofday";
#endif
}

/* what is wrong with gcc ? */
return "unknown";
}

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

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


+ 85
- 0
qnx/JackPlatformPlug_os.h View File

@@ -0,0 +1,85 @@
/*
Copyright (C) 2004-2008 Grame

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

*/

#ifndef __JackPlatformPlug_linux__
#define __JackPlatformPlug_linux__

#define jack_server_dir "/dev/shm"
#define jack_client_dir "/dev/shm"
#define JACK_DEFAULT_DRIVER "alsa"

namespace Jack
{
struct JackRequest;
struct JackResult;

class JackPosixMutex;
class JackPosixThread;
class JackFifo;
class JackSocketServerChannel;
class JackSocketClientChannel;
class JackSocketServerNotifyChannel;
class JackSocketNotifyChannel;
class JackClientSocket;
class JackNetUnixSocket;
}

/* __JackPlatformMutex__ */
#include "JackPosixMutex.h"
namespace Jack {typedef JackPosixMutex JackMutex; }

/* __JackPlatformThread__ */
#include "JackPosixThread.h"
namespace Jack { typedef JackPosixThread JackThread; }

#include "JackFifo.h"
namespace Jack { typedef JackFifo JackSynchro; }


/* __JackPlatformChannelTransaction__ */
/*
#include "JackSocket.h"
namespace Jack { typedef JackClientSocket JackChannelTransaction; }
*/

/* __JackPlatformProcessSync__ */
#include "JackPosixProcessSync.h"
namespace Jack { typedef JackPosixProcessSync JackProcessSync; }

/* __JackPlatformServerChannel__ */
#include "JackSocketServerChannel.h"
namespace Jack { typedef JackSocketServerChannel JackServerChannel; }

/* __JackPlatformClientChannel__ */
#include "JackSocketClientChannel.h"
namespace Jack { typedef JackSocketClientChannel JackClientChannel; }

/* __JackPlatformServerNotifyChannel__ */
#include "JackSocketServerNotifyChannel.h"
namespace Jack { typedef JackSocketServerNotifyChannel JackServerNotifyChannel; }

/* __JackPlatformNotifyChannel__ */
#include "JackSocketNotifyChannel.h"
namespace Jack { typedef JackSocketNotifyChannel JackNotifyChannel; }

/* __JackPlatformNetSocket__ */
#include "JackNetUnixSocket.h"
namespace Jack { typedef JackNetUnixSocket JackNetSocket; }

#endif

+ 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__ */

+ 2
- 0
tests/wscript View File

@@ -20,6 +20,8 @@ def build(bld):
prog.includes = ['..','../macosx', '../posix', '../common/jack', '../common']
if bld.env['IS_LINUX']:
prog.includes = ['..','../linux', '../posix', '../common/jack', '../common']
if bld.env['IS_QNX']:
prog.includes = ['..','../qnx', '../posix', '../common/jack', '../common']
if bld.env['IS_SUN']:
prog.includes = ['..','../solaris', '../posix', '../common/jack', '../common']
prog.source = test_program_sources


+ 40
- 14
wscript View File

@@ -95,6 +95,15 @@ def options(opt):
alsa.check_cfg(
package='alsa >= 1.0.18',
args='--cflags --libs')
# Check for QNX sound headers
qsa = opt.add_auto_option(
'qsa',
help='Enable QNX sound driver',
conf_dest='BUILD_DRIVER_ALSA')
qsa.check(lib='asound', uselib_store='ALSA')
qsa.check(
header_name=['sys/asoundlib.h'],
msg='Checking for header sys/asoundlib.h')
firewire = opt.add_auto_option(
'firewire',
help='Enable FireWire driver (FFADO)',
@@ -185,6 +194,7 @@ def detect_platform(conf):
platforms = [
# ('KEY, 'Human readable name', ['strings', 'to', 'check', 'for'])
('IS_LINUX', 'Linux', ['gnu0', 'gnukfreebsd', 'linux', 'posix']),
('IS_QNX', 'QNX', ['qnx']),
('IS_MACOSX', 'MacOS X', ['darwin']),
('IS_SUN', 'SunOS', ['sunos']),
('IS_WINDOWS', 'Windows', ['cygwin', 'msys', 'win32'])
@@ -304,7 +314,11 @@ def configure(conf):
conf.check_cc(fragment=fragment, define_name='HAVE_NGREG', mandatory=False,
msg='Checking for NGREG')

conf.env['LIB_PTHREAD'] = ['pthread']
if conf.env['IS_QNX']:
conf.env['LIB_PTHREAD'] = ['c']
conf.env['LIB_SOCKET'] = ['socket']
else:
conf.env['LIB_PTHREAD'] = ['pthread']
conf.env['LIB_DL'] = ['dl']
conf.env['LIB_RT'] = ['rt']
conf.env['LIB_M'] = ['m']
@@ -512,6 +526,9 @@ def obj_add_includes(bld, obj):
if bld.env['IS_MACOSX']:
obj.includes += ['macosx', 'posix']

if bld.env['IS_QNX']:
obj.includes += ['qnx', 'posix']

if bld.env['IS_SUN']:
obj.includes += ['posix', 'solaris']

@@ -540,6 +557,10 @@ def build_jackd(bld):
jackd.use += ['DL', 'PTHREAD']
jackd.framework = ['CoreFoundation']

if bld.env['IS_QNX']:
jackd.use += ['M', 'PTHREAD']


if bld.env['IS_SUN']:
jackd.use += ['DL', 'PTHREAD']

@@ -598,16 +619,20 @@ def build_drivers(bld):
alsa_src = [
'common/memops.c',
'linux/alsa/JackAlsaDriver.cpp',
'linux/alsa/alsa_rawmidi.c',
'linux/alsa/alsa_seqmidi.c',
'linux/alsa/alsa_midi_jackmp.cpp',
'linux/alsa/generic_hw.c',
'linux/alsa/hdsp.c',
'linux/alsa/alsa_driver.c',
'linux/alsa/hammerfall.c',
'linux/alsa/ice1712.c'
'linux/alsa/alsa_driver.c'
]

if not bld.env['IS_QNX']:
alsa_src += [
'linux/alsa/alsa_rawmidi.c',
'linux/alsa/alsa_seqmidi.c',
'linux/alsa/alsa_midi_jackmp.cpp',
'linux/alsa/generic_hw.c',
'linux/alsa/hdsp.c',
'linux/alsa/hammerfall.c',
'linux/alsa/ice1712.c'
]

alsarawmidi_src = [
'linux/alsarawmidi/JackALSARawMidiDriver.cpp',
'linux/alsarawmidi/JackALSARawMidiInputPort.cpp',
@@ -704,11 +729,12 @@ def build_drivers(bld):
target = 'alsa',
source = alsa_src,
use = ['ALSA'])
create_driver_obj(
bld,
target = 'alsarawmidi',
source = alsarawmidi_src,
use = ['ALSA'])
if not bld.env['IS_QNX']:
create_driver_obj(
bld,
target = 'alsarawmidi',
source = alsarawmidi_src,
use = ['ALSA'])

if bld.env['BUILD_DRIVER_FFADO']:
create_driver_obj(


Loading…
Cancel
Save