git-svn-id: svn+ssh://jackaudio.org/trunk/jack@454 0c269be4-1314-0410-8aa9-9f06e86f4224tags/0.109.0
@@ -13,7 +13,7 @@ dnl micro version = incremented when implementation-only | |||||
dnl changes are made | dnl changes are made | ||||
dnl --- | dnl --- | ||||
JACK_MAJOR_VERSION=0 | JACK_MAJOR_VERSION=0 | ||||
JACK_MINOR_VERSION=77 | |||||
JACK_MINOR_VERSION=78 | |||||
JACK_MICRO_VERSION=0 | JACK_MICRO_VERSION=0 | ||||
@@ -296,6 +296,7 @@ libjack/Makefile | |||||
drivers/Makefile | drivers/Makefile | ||||
drivers/alsa/Makefile | drivers/alsa/Makefile | ||||
drivers/solaris/Makefile | drivers/solaris/Makefile | ||||
drivers/dummy/Makefile | |||||
example-clients/Makefile | example-clients/Makefile | ||||
doc/Makefile | doc/Makefile | ||||
doc/reference.doxygen | doc/reference.doxygen | ||||
@@ -1,5 +1,6 @@ | |||||
Makefile | Makefile | ||||
Makefile.in | Makefile.in | ||||
doxygen-build.stamp | doxygen-build.stamp | ||||
reference | |||||
reference.doxygen | reference.doxygen | ||||
html | |||||
latex |
@@ -6,7 +6,7 @@ DOX=reference.doxygen | |||||
EXTRA_DIST= | EXTRA_DIST= | ||||
INSTIMAGES=reference/html/doxygen.png reference/html/fsm.png | |||||
INSTIMAGES=html/doxygen.png /html/fsm.png | |||||
DOC_STAMPS=html-build.stamp | DOC_STAMPS=html-build.stamp | ||||
@@ -25,36 +25,36 @@ clean-local: | |||||
distclean-local: clean | distclean-local: clean | ||||
rm -f *.stamp || true | rm -f *.stamp || true | ||||
if test -d reference; then rm -rf reference; fi | |||||
if test -d html; then rm -rf html; fi | |||||
if test -d latex; then rm -rf latex; fi | |||||
install-data-local: | install-data-local: | ||||
$(mkinstalldirs) $(DESTDIR)$(DOC_DIR)/reference/html | |||||
(installfiles=`echo reference/html/*.html`; \ | |||||
if test "$$installfiles" = 'reference/html/*.html'; \ | |||||
$(mkinstalldirs) $(DESTDIR)$(DOC_DIR)/html | |||||
(installfiles=`echo html/*.html`; \ | |||||
if test "$$installfiles" = 'html/*.html'; \ | |||||
then echo '-- Nothing to install' ; \ | then echo '-- Nothing to install' ; \ | ||||
else \ | else \ | ||||
for i in $$installfiles $(INSTIMAGES) reference/html/doxygen.css; do \ | |||||
for i in $$installfiles $(INSTIMAGES) html/doxygen.css; do \ | |||||
echo '-- Installing '$$i ; \ | echo '-- Installing '$$i ; \ | ||||
$(INSTALL_DATA) $$i $(DESTDIR)$(DOC_DIR)/reference/html; \ | |||||
$(INSTALL_DATA) $$i $(DESTDIR)$(DOC_DIR)/html; \ | |||||
done; \ | done; \ | ||||
fi) | fi) | ||||
# we need doxygen stuff built so we can know what to uninstall | # we need doxygen stuff built so we can know what to uninstall | ||||
uninstall-local: doxygen-build.stamp | uninstall-local: doxygen-build.stamp | ||||
(installfiles=`echo reference/html/*.html`; \ | |||||
if test "$$installfiles" = 'reference/html/*.html'; \ | |||||
(installfiles=`echo html/*.html`; \ | |||||
if test "$$installfiles" = 'html/*.html'; \ | |||||
then echo '-- Nothing to uninstall' ; \ | then echo '-- Nothing to uninstall' ; \ | ||||
else \ | else \ | ||||
for i in $$installfiles $(INSTIMAGES) reference/html/doxygen.css; do \ | |||||
for i in $$installfiles $(INSTIMAGES) html/doxygen.css; do \ | |||||
echo '-- Unstalling '$$i ; \ | echo '-- Unstalling '$$i ; \ | ||||
rm $(DESTDIR)$(DOC_DIR)/$$i; \ | rm $(DESTDIR)$(DOC_DIR)/$$i; \ | ||||
done; \ | done; \ | ||||
fi) | fi) | ||||
dist-hook: dist-hook-local | dist-hook: dist-hook-local | ||||
mkdir $(distdir)/reference | |||||
mkdir $(distdir)/reference/html | |||||
-cp reference/html/*.html reference/html/*.css \ | |||||
reference/html/*.png $(distdir)/reference/html | |||||
mkdir $(distdir)/html | |||||
-cp html/*.html html/*.css \ | |||||
html/*.png $(distdir)/html | |||||
.PHONY : dist-hook-local | .PHONY : dist-hook-local |
@@ -30,7 +30,7 @@ PROJECT_NUMBER = @JACK_VERSION@ | |||||
# If a relative path is entered, it will be relative to the location | # If a relative path is entered, it will be relative to the location | ||||
# where doxygen was started. If left blank the current directory will be used. | # where doxygen was started. If left blank the current directory will be used. | ||||
OUTPUT_DIRECTORY = reference | |||||
OUTPUT_DIRECTORY = | |||||
# The OUTPUT_LANGUAGE tag is used to specify the language in which all | # The OUTPUT_LANGUAGE tag is used to specify the language in which all | ||||
# documentation generated by doxygen is written. Doxygen will use this | # documentation generated by doxygen is written. Doxygen will use this | ||||
@@ -12,6 +12,7 @@ else | |||||
SOLARIS_DIR = | SOLARIS_DIR = | ||||
endif | endif | ||||
SUBDIRS = $(ALSA_DIR) $(SOLARIS_DIR) | |||||
SUBDIRS = dummy $(ALSA_DIR) $(SOLARIS_DIR) | |||||
DIST_SUBDIRS = dummy alsa solaris | |||||
DIST_SUBDIRS = alsa solaris |
@@ -191,9 +191,9 @@ static void | |||||
alsa_driver_setup_io_function_pointers (alsa_driver_t *driver) | alsa_driver_setup_io_function_pointers (alsa_driver_t *driver) | ||||
{ | { | ||||
switch (driver->sample_bytes) { | |||||
switch (driver->playback_sample_bytes) { | |||||
case 2: | case 2: | ||||
if (driver->interleaved) { | |||||
if (driver->playback_interleaved) { | |||||
driver->channel_copy = memcpy_interleave_d16_s16; | driver->channel_copy = memcpy_interleave_d16_s16; | ||||
} else { | } else { | ||||
driver->channel_copy = memcpy_fake; | driver->channel_copy = memcpy_fake; | ||||
@@ -219,12 +219,10 @@ alsa_driver_setup_io_function_pointers (alsa_driver_t *driver) | |||||
driver->write_via_copy = sample_move_d16_sS; | driver->write_via_copy = sample_move_d16_sS; | ||||
break; | break; | ||||
} | } | ||||
driver->read_via_copy = sample_move_dS_s16; | |||||
break; | break; | ||||
case 4: | case 4: | ||||
if (driver->interleaved) { | |||||
if (driver->playback_interleaved) { | |||||
driver->channel_copy = memcpy_interleave_d32_s32; | driver->channel_copy = memcpy_interleave_d32_s32; | ||||
} else { | } else { | ||||
driver->channel_copy = memcpy_fake; | driver->channel_copy = memcpy_fake; | ||||
@@ -250,9 +248,15 @@ alsa_driver_setup_io_function_pointers (alsa_driver_t *driver) | |||||
driver->write_via_copy = sample_move_d32u24_sS; | driver->write_via_copy = sample_move_d32u24_sS; | ||||
break; | break; | ||||
} | } | ||||
break; | |||||
} | |||||
switch (driver->capture_sample_bytes) { | |||||
case 2: | |||||
driver->read_via_copy = sample_move_dS_s16; | |||||
break; | |||||
case 4: | |||||
driver->read_via_copy = sample_move_dS_s32u24; | driver->read_via_copy = sample_move_dS_s32u24; | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
@@ -389,10 +393,6 @@ static int | |||||
alsa_driver_set_parameters (alsa_driver_t *driver, jack_nframes_t frames_per_cycle, jack_nframes_t user_nperiods, jack_nframes_t rate) | alsa_driver_set_parameters (alsa_driver_t *driver, jack_nframes_t frames_per_cycle, jack_nframes_t user_nperiods, jack_nframes_t rate) | ||||
{ | { | ||||
int p_noninterleaved = 0; | |||||
int c_noninterleaved = 0; | |||||
snd_pcm_format_t c_format = 0; | |||||
snd_pcm_format_t p_format = 0; | |||||
int dir; | int dir; | ||||
unsigned int p_period_size = 0; | unsigned int p_period_size = 0; | ||||
unsigned int c_period_size = 0; | unsigned int c_period_size = 0; | ||||
@@ -431,8 +431,8 @@ alsa_driver_set_parameters (alsa_driver_t *driver, jack_nframes_t frames_per_cyc | |||||
if (driver->playback_handle) { | if (driver->playback_handle) { | ||||
p_period_size = snd_pcm_hw_params_get_period_size (driver->playback_hw_params, &dir); | p_period_size = snd_pcm_hw_params_get_period_size (driver->playback_hw_params, &dir); | ||||
p_nfragments = snd_pcm_hw_params_get_periods (driver->playback_hw_params, &dir); | p_nfragments = snd_pcm_hw_params_get_periods (driver->playback_hw_params, &dir); | ||||
p_format = (snd_pcm_format_t) snd_pcm_hw_params_get_format (driver->playback_hw_params); | |||||
p_noninterleaved = (snd_pcm_hw_params_get_access (driver->playback_hw_params) == SND_PCM_ACCESS_MMAP_NONINTERLEAVED); | |||||
driver->playback_sample_format = (snd_pcm_format_t) snd_pcm_hw_params_get_format (driver->playback_hw_params); | |||||
driver->playback_interleaved = (snd_pcm_hw_params_get_access (driver->playback_hw_params) == SND_PCM_ACCESS_MMAP_INTERLEAVED); | |||||
if (p_period_size != driver->frames_per_cycle) { | if (p_period_size != driver->frames_per_cycle) { | ||||
jack_error ("alsa_pcm: requested an interrupt every %u frames but got %uc frames for playback", | jack_error ("alsa_pcm: requested an interrupt every %u frames but got %uc frames for playback", | ||||
@@ -444,8 +444,8 @@ alsa_driver_set_parameters (alsa_driver_t *driver, jack_nframes_t frames_per_cyc | |||||
if (driver->capture_handle) { | if (driver->capture_handle) { | ||||
c_period_size = snd_pcm_hw_params_get_period_size (driver->capture_hw_params, &dir); | c_period_size = snd_pcm_hw_params_get_period_size (driver->capture_hw_params, &dir); | ||||
c_nfragments = snd_pcm_hw_params_get_periods (driver->capture_hw_params, &dir); | c_nfragments = snd_pcm_hw_params_get_periods (driver->capture_hw_params, &dir); | ||||
c_format = (snd_pcm_format_t) snd_pcm_hw_params_get_format (driver->capture_hw_params); | |||||
c_noninterleaved = (snd_pcm_hw_params_get_access (driver->capture_hw_params) == SND_PCM_ACCESS_MMAP_NONINTERLEAVED); | |||||
driver->capture_sample_format = (snd_pcm_format_t) snd_pcm_hw_params_get_format (driver->capture_hw_params); | |||||
driver->capture_interleaved = (snd_pcm_hw_params_get_access (driver->capture_hw_params) == SND_PCM_ACCESS_MMAP_INTERLEAVED); | |||||
if (c_period_size != driver->frames_per_cycle) { | if (c_period_size != driver->frames_per_cycle) { | ||||
jack_error ("alsa_pcm: requested an interrupt every %u frames but got %uc frames for capture", | jack_error ("alsa_pcm: requested an interrupt every %u frames but got %uc frames for capture", | ||||
@@ -460,44 +460,35 @@ alsa_driver_set_parameters (alsa_driver_t *driver, jack_nframes_t frames_per_cyc | |||||
return -1; | return -1; | ||||
} | } | ||||
/* Check that we are using the same sample format on both streams */ | |||||
if (p_format != c_format) { | |||||
jack_error ("Sorry. The PCM device \"%s\" and \"%s\"" | |||||
"don't support the same sample format for capture and playback." | |||||
"We cannot use this PCM device.", driver->alsa_name_playback, driver->alsa_name_capture ); | |||||
return -1; | |||||
} | |||||
/* check interleave setup */ | |||||
if (c_noninterleaved != p_noninterleaved) { | |||||
jack_error ("ALSA: the playback and capture components for this PCM device differ " | |||||
"in their use of channel interleaving. We cannot use this PCM device."); | |||||
return -1; | |||||
} | |||||
driver->nfragments = c_nfragments; | driver->nfragments = c_nfragments; | ||||
driver->interleaved = !c_noninterleaved; | |||||
driver->sample_format = c_format; | |||||
} else if (driver->capture_handle) { | } else if (driver->capture_handle) { | ||||
driver->nfragments = c_nfragments; | driver->nfragments = c_nfragments; | ||||
driver->interleaved = !c_noninterleaved; | |||||
driver->sample_format = c_format; | |||||
} else { | } else { | ||||
driver->nfragments = p_nfragments; | driver->nfragments = p_nfragments; | ||||
driver->interleaved = !p_noninterleaved; | |||||
driver->sample_format = p_format; | |||||
} | } | ||||
driver->buffer_frames = driver->frames_per_cycle * driver->nfragments; | driver->buffer_frames = driver->frames_per_cycle * driver->nfragments; | ||||
driver->sample_bytes = snd_pcm_format_physical_width (driver->sample_format) / 8; | |||||
driver->playback_sample_bytes = snd_pcm_format_physical_width (driver->playback_sample_format) / 8; | |||||
driver->capture_sample_bytes = snd_pcm_format_physical_width (driver->capture_sample_format) / 8; | |||||
switch (driver->playback_sample_format) { | |||||
case SND_PCM_FORMAT_S32_LE: | |||||
case SND_PCM_FORMAT_S16_LE: | |||||
case SND_PCM_FORMAT_S32_BE: | |||||
case SND_PCM_FORMAT_S16_BE: | |||||
break; | |||||
default: | |||||
jack_error ("programming error: unhandled format type for playback"); | |||||
exit (1); | |||||
} | |||||
switch (driver->sample_format) { | |||||
switch (driver->capture_sample_format) { | |||||
case SND_PCM_FORMAT_S32_LE: | case SND_PCM_FORMAT_S32_LE: | ||||
case SND_PCM_FORMAT_S16_LE: | case SND_PCM_FORMAT_S16_LE: | ||||
case SND_PCM_FORMAT_S32_BE: | case SND_PCM_FORMAT_S32_BE: | ||||
@@ -505,11 +496,11 @@ alsa_driver_set_parameters (alsa_driver_t *driver, jack_nframes_t frames_per_cyc | |||||
break; | break; | ||||
default: | default: | ||||
jack_error ("programming error: unhandled format type"); | |||||
jack_error ("programming error: unhandled format type for capture"); | |||||
exit (1); | exit (1); | ||||
} | } | ||||
if (driver->interleaved) { | |||||
if (driver->playback_interleaved) { | |||||
const snd_pcm_channel_area_t *my_areas; | const snd_pcm_channel_area_t *my_areas; | ||||
snd_pcm_uframes_t offset, frames; | snd_pcm_uframes_t offset, frames; | ||||
if (snd_pcm_mmap_begin(driver->playback_handle, &my_areas, &offset, &frames) < 0) { | if (snd_pcm_mmap_begin(driver->playback_handle, &my_areas, &offset, &frames) < 0) { | ||||
@@ -517,16 +508,22 @@ alsa_driver_set_parameters (alsa_driver_t *driver, jack_nframes_t frames_per_cyc | |||||
return -1; | return -1; | ||||
} | } | ||||
driver->playback_interleave_skip = my_areas[0].step / 8; | driver->playback_interleave_skip = my_areas[0].step / 8; | ||||
driver->interleave_unit = snd_pcm_format_physical_width (driver->playback_sample_format) / 8; | |||||
} else { | |||||
driver->interleave_unit = 0; /* NOT USED */ | |||||
driver->playback_interleave_skip = snd_pcm_format_physical_width (driver->playback_sample_format) / 8; | |||||
} | |||||
if (driver->capture_interleaved) { | |||||
const snd_pcm_channel_area_t *my_areas; | |||||
snd_pcm_uframes_t offset, frames; | |||||
if (snd_pcm_mmap_begin(driver->capture_handle, &my_areas, &offset, &frames) < 0) { | if (snd_pcm_mmap_begin(driver->capture_handle, &my_areas, &offset, &frames) < 0) { | ||||
jack_error ("ALSA: %s: mmap areas info error", driver->alsa_name_playback); | |||||
jack_error ("ALSA: %s: mmap areas info error", driver->alsa_name_capture); | |||||
return -1; | return -1; | ||||
} | } | ||||
driver->capture_interleave_skip = my_areas[0].step / 8; | driver->capture_interleave_skip = my_areas[0].step / 8; | ||||
driver->interleave_unit = snd_pcm_format_physical_width (driver->sample_format) / 8; | |||||
} else { | } else { | ||||
driver->interleave_unit = 0; /* NOT USED */ | |||||
driver->playback_interleave_skip = snd_pcm_format_physical_width (driver->sample_format) / 8; | |||||
driver->capture_interleave_skip = driver->playback_interleave_skip; | |||||
driver->capture_interleave_skip = snd_pcm_format_physical_width (driver->capture_sample_format) / 8; | |||||
} | } | ||||
if (driver->playback_nchannels > driver->capture_nchannels) { | if (driver->playback_nchannels > driver->capture_nchannels) { | ||||
@@ -576,8 +573,7 @@ alsa_driver_set_parameters (alsa_driver_t *driver, jack_nframes_t frames_per_cyc | |||||
} | } | ||||
driver->clock_sync_data = (ClockSyncStatus *) malloc (sizeof (ClockSyncStatus) * | driver->clock_sync_data = (ClockSyncStatus *) malloc (sizeof (ClockSyncStatus) * | ||||
(driver->capture_nchannels > driver->playback_nchannels ? | |||||
driver->capture_nchannels : driver->playback_nchannels)); | |||||
driver->max_nchannels); | |||||
driver->period_usecs = (jack_time_t) floor ((((float) driver->frames_per_cycle) / driver->frame_rate) * 1000000.0f); | driver->period_usecs = (jack_time_t) floor ((((float) driver->frames_per_cycle) / driver->frame_rate) * 1000000.0f); | ||||
driver->poll_timeout = (int) floor (1.5f * driver->period_usecs); | driver->poll_timeout = (int) floor (1.5f * driver->period_usecs); | ||||
@@ -1170,6 +1166,7 @@ alsa_driver_write (alsa_driver_t* driver, jack_nframes_t nframes) | |||||
snd_pcm_sframes_t contiguous; | snd_pcm_sframes_t contiguous; | ||||
snd_pcm_sframes_t offset; | snd_pcm_sframes_t offset; | ||||
jack_port_t *port; | jack_port_t *port; | ||||
int err; | |||||
driver->process_count++; | driver->process_count++; | ||||
@@ -1224,9 +1221,10 @@ alsa_driver_write (alsa_driver_t* driver, jack_nframes_t nframes) | |||||
alsa_driver_silence_untouched_channels (driver, contiguous); | alsa_driver_silence_untouched_channels (driver, contiguous); | ||||
} | } | ||||
if (snd_pcm_mmap_commit (driver->playback_handle, offset, contiguous) < 0) { | |||||
jack_error ("could not complete playback of %lu frames", contiguous); | |||||
return -1; | |||||
if ((err = snd_pcm_mmap_commit (driver->playback_handle, offset, contiguous)) < 0) { | |||||
jack_error ("could not complete playback of %lu frames: error = %d", contiguous, err); | |||||
if (err != -EPIPE && err != -ESTRPIPE) | |||||
return -1; | |||||
} | } | ||||
nframes -= contiguous; | nframes -= contiguous; | ||||
@@ -0,0 +1,6 @@ | |||||
Makefile | |||||
Makefile.in | |||||
.deps | |||||
.libs | |||||
*.lo | |||||
*.la |
@@ -0,0 +1,12 @@ | |||||
MAINTAINERCLEANFILES=Makefile.in | |||||
AM_CFLAGS = $(JACK_CFLAGS) | |||||
plugindir = $(ADDON_DIR) | |||||
plugin_LTLIBRARIES = jack_dummy.la | |||||
jack_dummy_la_LDFLAGS = -module -avoid-version | |||||
jack_dummy_la_SOURCES = dummy_driver.c dummy_driver.h | |||||
# jack_alsa_la_LIBADD = |
@@ -0,0 +1,323 @@ | |||||
/* | |||||
Copyright (C) 2003 Robert Ham <rah@bash.sh> | |||||
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$ | |||||
*/ | |||||
#include <stdio.h> | |||||
#include <memory.h> | |||||
#include <unistd.h> | |||||
#include <stdlib.h> | |||||
#include <errno.h> | |||||
#include <stdarg.h> | |||||
#include <getopt.h> | |||||
#include <jack/types.h> | |||||
#include <jack/internal.h> | |||||
#include <jack/engine.h> | |||||
#include <jack/time.h> | |||||
#include "dummy_driver.h" | |||||
#undef DEBUG_WAKEUP | |||||
static int | |||||
dummy_driver_audio_start (dummy_driver_t *driver) | |||||
{ | |||||
return 0; | |||||
} | |||||
static int | |||||
dummy_driver_audio_stop (dummy_driver_t *driver) | |||||
{ | |||||
return 0; | |||||
} | |||||
static jack_nframes_t | |||||
dummy_driver_wait (dummy_driver_t *driver, int extra_fd, int *status, float *delayed_usecs) | |||||
{ | |||||
usleep (driver->wait_time); | |||||
driver->last_wait_ust = jack_get_microseconds (); | |||||
*status = 0; | |||||
*delayed_usecs = 0.0; | |||||
return driver->period_size; | |||||
} | |||||
static int | |||||
dummy_driver_null_cycle (dummy_driver_t* driver, jack_nframes_t nframes) | |||||
{ | |||||
return 0; | |||||
} | |||||
static int | |||||
dummy_driver_read (dummy_driver_t *driver, jack_nframes_t nframes) | |||||
{ | |||||
return 0; | |||||
} | |||||
static int | |||||
dummy_driver_write (dummy_driver_t* driver, jack_nframes_t nframes) | |||||
{ | |||||
return 0; | |||||
} | |||||
static int | |||||
dummy_driver_attach (dummy_driver_t *driver, jack_engine_t *engine) | |||||
{ | |||||
jack_port_t * port; | |||||
char buf[32]; | |||||
unsigned int chn; | |||||
int port_flags; | |||||
driver->engine = engine; | |||||
driver->engine->set_buffer_size (engine, driver->period_size); | |||||
driver->engine->set_sample_rate (engine, driver->sample_rate); | |||||
port_flags = JackPortIsOutput|JackPortIsPhysical|JackPortIsTerminal; | |||||
for (chn = 0; chn < driver->capture_channels; chn++) | |||||
{ | |||||
snprintf (buf, sizeof(buf) - 1, "capture_%u", chn+1); | |||||
port = jack_port_register (driver->client, buf, JACK_DEFAULT_AUDIO_TYPE, port_flags, 0); | |||||
if (!port) | |||||
{ | |||||
jack_error ("DUMMY: cannot register port for %s", buf); | |||||
break; | |||||
} | |||||
driver->capture_ports = jack_slist_append (driver->capture_ports, port); | |||||
} | |||||
port_flags = JackPortIsInput|JackPortIsPhysical|JackPortIsTerminal; | |||||
for (chn = 0; chn < driver->playback_channels; chn++) | |||||
{ | |||||
snprintf (buf, sizeof(buf) - 1, "playback_%u", chn+1); | |||||
port = jack_port_register (driver->client, buf, JACK_DEFAULT_AUDIO_TYPE, port_flags, 0); | |||||
if (!port) | |||||
{ | |||||
jack_error ("DUMMY: cannot register port for %s", buf); | |||||
break; | |||||
} | |||||
driver->playback_ports = jack_slist_append (driver->playback_ports, port); | |||||
} | |||||
jack_activate (driver->client); | |||||
return 0; | |||||
} | |||||
static void | |||||
dummy_driver_detach (dummy_driver_t *driver, jack_engine_t *engine) | |||||
{ | |||||
JSList * node; | |||||
if (driver->engine == 0) | |||||
return; | |||||
for (node = driver->capture_ports; node; node = jack_slist_next (node)) | |||||
jack_port_unregister (driver->client, ((jack_port_t *) node->data)); | |||||
jack_slist_free (driver->capture_ports); | |||||
driver->capture_ports = NULL; | |||||
for (node = driver->playback_ports; node; node = jack_slist_next (node)) | |||||
jack_port_unregister (driver->client, ((jack_port_t *) node->data)); | |||||
jack_slist_free (driver->playback_ports); | |||||
driver->playback_ports = NULL; | |||||
driver->engine = NULL; | |||||
} | |||||
static void | |||||
dummy_driver_delete (dummy_driver_t *driver) | |||||
{ | |||||
free (driver); | |||||
} | |||||
static jack_driver_t * | |||||
dummy_driver_new (jack_client_t * client, | |||||
char *name, | |||||
unsigned int capture_ports, | |||||
unsigned int playback_ports, | |||||
jack_nframes_t sample_rate, | |||||
jack_nframes_t period_size, | |||||
unsigned long wait_time) | |||||
{ | |||||
dummy_driver_t * driver; | |||||
printf ("creating dummy driver ... %s|%lu|%lu|%lu|%u|%u\n", | |||||
name, sample_rate, period_size, wait_time, | |||||
capture_ports, playback_ports); | |||||
driver = (dummy_driver_t *) calloc (1, sizeof (dummy_driver_t)); | |||||
jack_driver_init ((jack_driver_t *) driver); | |||||
driver->attach = (JackDriverAttachFunction) dummy_driver_attach; | |||||
driver->detach = (JackDriverDetachFunction) dummy_driver_detach; | |||||
driver->wait = (JackDriverWaitFunction) dummy_driver_wait; | |||||
driver->read = (JackDriverReadFunction) dummy_driver_read; | |||||
driver->write = (JackDriverReadFunction) dummy_driver_write; | |||||
driver->null_cycle = (JackDriverNullCycleFunction) dummy_driver_null_cycle; | |||||
driver->start = (JackDriverStartFunction) dummy_driver_audio_start; | |||||
driver->stop = (JackDriverStopFunction) dummy_driver_audio_stop; | |||||
driver->period_usecs = (((float)period_size) / ((float)sample_rate)) / 1000000.0; | |||||
driver->sample_rate = sample_rate; | |||||
driver->period_size = period_size; | |||||
driver->wait_time = wait_time; | |||||
driver->capture_channels = capture_ports; | |||||
driver->capture_ports = NULL; | |||||
driver->playback_channels = playback_ports; | |||||
driver->playback_ports = NULL; | |||||
driver->client = client; | |||||
driver->engine = NULL; | |||||
return (jack_driver_t *) driver; | |||||
} | |||||
static void | |||||
dummy_usage () | |||||
{ | |||||
fprintf (stderr, "\n" | |||||
"dummy driver arguments:\n" | |||||
" -h,--help \tprint this message\n" | |||||
" -r,--rate <n> \tsample rate (default: 48000)\n" | |||||
" -p,--period <n> \tframes per period (default: 1024)\n" | |||||
" -C,--capture <n> \tnumber of capture ports (default: 2)\n" | |||||
" -P,--playback <n> \tnumber of playback ports (default: 2)\n" | |||||
" -w,--wait <usecs> \tnumber of usecs to wait between engine processes (default: 21333)\n" | |||||
"\n"); | |||||
} | |||||
static void | |||||
dummy_error (char *type, char *value) | |||||
{ | |||||
fprintf (stderr, "dummy driver: unknown %s: `%s'\n", type, value); | |||||
dummy_usage(); | |||||
} | |||||
/* DRIVER "PLUGIN" INTERFACE */ | |||||
const char driver_client_name[] = "dummy_pcm"; | |||||
jack_driver_t * | |||||
driver_initialize (jack_client_t *client, int argc, char **argv) | |||||
{ | |||||
jack_nframes_t sample_rate = 48000; | |||||
jack_nframes_t period_size = 1024; | |||||
unsigned int capture_ports = 2; | |||||
unsigned int playback_ports = 2; | |||||
int wait_time_set = 0; | |||||
unsigned long wait_time; | |||||
int opt; | |||||
char optstring[2]; /* string made from opt char */ | |||||
struct option long_options[] = | |||||
{ | |||||
{ "help", no_argument, NULL, 'h' }, | |||||
{ "rate", required_argument, NULL, 'r' }, | |||||
{ "period", required_argument, NULL, 'p' }, | |||||
{ "capture", required_argument, NULL, 'C' }, | |||||
{ "playback", required_argument, NULL, 'P' }, | |||||
{ "wait", required_argument, NULL, 'w' }, | |||||
{ 0, 0, 0, 0 } | |||||
}; | |||||
/* | |||||
* Setting optind back to zero is a hack to reinitialize a new | |||||
* getopts() loop. See declaration in <getopt.h>. | |||||
*/ | |||||
optind = 0; | |||||
opterr = 0; | |||||
while ((opt = getopt_long(argc, argv, "C::P::p:r:w:h", | |||||
long_options, NULL)) | |||||
!= EOF) { | |||||
switch (opt) { | |||||
case 'C': | |||||
capture_ports = atoi (optarg); | |||||
break; | |||||
case 'P': | |||||
playback_ports = atoi (optarg); | |||||
break; | |||||
case 'p': | |||||
period_size = atoi(optarg); | |||||
break; | |||||
case 'r': | |||||
sample_rate = atoi(optarg); | |||||
break; | |||||
case 'w': | |||||
wait_time = strtoul(optarg, NULL, 10); | |||||
wait_time_set = 1; | |||||
break; | |||||
case 'h': | |||||
dummy_usage(); | |||||
return NULL; | |||||
/* the rest is error handling: */ | |||||
case 1: /* not an option */ | |||||
dummy_error("parameter", optarg); | |||||
return NULL; | |||||
default: /* unrecognized option */ | |||||
optstring[0] = (char) optopt; | |||||
optstring[1] = '\0'; | |||||
dummy_error("option", optstring); | |||||
return NULL; | |||||
} | |||||
} | |||||
if (!wait_time_set) | |||||
wait_time = (((float)period_size) / ((float)sample_rate)) * 1000000.0; | |||||
return dummy_driver_new (client, "dummy_pcm", capture_ports, playback_ports, | |||||
sample_rate, period_size, wait_time); | |||||
} | |||||
void | |||||
driver_finish (jack_driver_t *driver) | |||||
{ | |||||
dummy_driver_delete ((dummy_driver_t *) driver); | |||||
} |
@@ -0,0 +1,52 @@ | |||||
/* | |||||
Copyright (C) 2003 Robert Ham <rah@bash.sh> | |||||
This program is free software; you can redistribute it and/or modify | |||||
it under the terms of the GNU General Public License as published by | |||||
the Free Software Foundation; either version 2 of the License, or | |||||
(at your option) any later version. | |||||
This program is distributed in the hope that it will be useful, | |||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
GNU General Public License for more details. | |||||
You should have received a copy of the GNU General Public License | |||||
along with this program; if not, write to the Free Software | |||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||||
*/ | |||||
#ifndef __JACK_DUMMY_DRIVER_H__ | |||||
#define __JACK_DUMMY_DRIVER_H__ | |||||
#include <unistd.h> | |||||
#include <jack/types.h> | |||||
#include <jack/jslist.h> | |||||
#include <jack/driver.h> | |||||
#include <jack/jack.h> | |||||
typedef struct _dummy_driver dummy_driver_t; | |||||
struct _dummy_driver | |||||
{ | |||||
JACK_DRIVER_DECL | |||||
jack_nframes_t sample_rate; | |||||
jack_nframes_t period_size; | |||||
unsigned long wait_time; | |||||
unsigned int capture_channels; | |||||
unsigned int playback_channels; | |||||
JSList * capture_ports; | |||||
JSList * playback_ports; | |||||
struct _jack_engine * engine; | |||||
jack_client_t * client; | |||||
}; | |||||
#endif /* __JACK_DUMMY_DRIVER_H__ */ |
@@ -62,7 +62,8 @@ typedef struct { | |||||
channel_t user_nchannels; | channel_t user_nchannels; | ||||
channel_t playback_nchannels; | channel_t playback_nchannels; | ||||
channel_t capture_nchannels; | channel_t capture_nchannels; | ||||
unsigned long sample_bytes; | |||||
unsigned long playback_sample_bytes; | |||||
unsigned long capture_sample_bytes; | |||||
jack_nframes_t frame_rate; | jack_nframes_t frame_rate; | ||||
jack_nframes_t frames_per_cycle; | jack_nframes_t frames_per_cycle; | ||||
@@ -76,7 +77,8 @@ typedef struct { | |||||
snd_pcm_uframes_t buffer_frames; | snd_pcm_uframes_t buffer_frames; | ||||
unsigned long channels_not_done; | unsigned long channels_not_done; | ||||
unsigned long channel_done_bits; | unsigned long channel_done_bits; | ||||
snd_pcm_format_t sample_format; | |||||
snd_pcm_format_t playback_sample_format; | |||||
snd_pcm_format_t capture_sample_format; | |||||
float max_sample_val; | float max_sample_val; | ||||
unsigned long user_nperiods; | unsigned long user_nperiods; | ||||
unsigned long nfragments; | unsigned long nfragments; | ||||
@@ -102,7 +104,8 @@ typedef struct { | |||||
char hw_metering : 1; | char hw_metering : 1; | ||||
char all_monitor_in : 1; | char all_monitor_in : 1; | ||||
char capture_and_playback_not_synced : 1; | char capture_and_playback_not_synced : 1; | ||||
char interleaved : 1; | |||||
char playback_interleaved : 1; | |||||
char capture_interleaved : 1; | |||||
char with_monitor_ports : 1; | char with_monitor_ports : 1; | ||||
ReadCopyFunction read_via_copy; | ReadCopyFunction read_via_copy; | ||||
@@ -130,27 +133,27 @@ static __inline__ void alsa_driver_mark_channel_done (alsa_driver_t *driver, cha | |||||
} | } | ||||
static __inline__ void alsa_driver_silence_on_channel (alsa_driver_t *driver, channel_t chn, jack_nframes_t nframes) { | static __inline__ void alsa_driver_silence_on_channel (alsa_driver_t *driver, channel_t chn, jack_nframes_t nframes) { | ||||
if (driver->interleaved) { | |||||
if (driver->playback_interleaved) { | |||||
memset_interleave | memset_interleave | ||||
(driver->playback_addr[chn], | (driver->playback_addr[chn], | ||||
0, nframes * driver->sample_bytes, | |||||
0, nframes * driver->playback_sample_bytes, | |||||
driver->interleave_unit, | driver->interleave_unit, | ||||
driver->playback_interleave_skip); | driver->playback_interleave_skip); | ||||
} else { | } else { | ||||
memset (driver->playback_addr[chn], 0, nframes * driver->sample_bytes); | |||||
memset (driver->playback_addr[chn], 0, nframes * driver->playback_sample_bytes); | |||||
} | } | ||||
alsa_driver_mark_channel_done (driver,chn); | alsa_driver_mark_channel_done (driver,chn); | ||||
} | } | ||||
static __inline__ void alsa_driver_silence_on_channel_no_mark (alsa_driver_t *driver, channel_t chn, jack_nframes_t nframes) { | static __inline__ void alsa_driver_silence_on_channel_no_mark (alsa_driver_t *driver, channel_t chn, jack_nframes_t nframes) { | ||||
if (driver->interleaved) { | |||||
if (driver->playback_interleaved) { | |||||
memset_interleave | memset_interleave | ||||
(driver->playback_addr[chn], | (driver->playback_addr[chn], | ||||
0, nframes * driver->sample_bytes, | |||||
0, nframes * driver->playback_sample_bytes, | |||||
driver->interleave_unit, | driver->interleave_unit, | ||||
driver->playback_interleave_skip); | driver->playback_interleave_skip); | ||||
} else { | } else { | ||||
memset (driver->playback_addr[chn], 0, nframes * driver->sample_bytes); | |||||
memset (driver->playback_addr[chn], 0, nframes * driver->playback_sample_bytes); | |||||
} | } | ||||
} | } | ||||
@@ -184,7 +187,7 @@ static __inline__ void alsa_driver_copy_channel (alsa_driver_t *driver, | |||||
driver->channel_copy (driver->playback_addr[output_channel], | driver->channel_copy (driver->playback_addr[output_channel], | ||||
driver->capture_addr[input_channel], | driver->capture_addr[input_channel], | ||||
nsamples * driver->sample_bytes, | |||||
nsamples * driver->playback_sample_bytes, | |||||
driver->playback_interleave_skip, | driver->playback_interleave_skip, | ||||
driver->capture_interleave_skip); | driver->capture_interleave_skip); | ||||
alsa_driver_mark_channel_done (driver, output_channel); | alsa_driver_mark_channel_done (driver, output_channel); | ||||
@@ -336,7 +336,7 @@ typedef struct _jack_client_internal { | |||||
struct _jack_client_internal *next_client; /* not a linked list! */ | struct _jack_client_internal *next_client; /* not a linked list! */ | ||||
dlhandle handle; | dlhandle handle; | ||||
int (*initialize)(jack_client_t*, const char*); /* for internal clients only */ | int (*initialize)(jack_client_t*, const char*); /* for internal clients only */ | ||||
void (*finish)(void); /* for internal clients only */ | |||||
void (*finish)(void *); /* for internal clients only */ | |||||
int error; | int error; | ||||
#if defined(__APPLE__) && defined(__POWERPC__) | #if defined(__APPLE__) && defined(__POWERPC__) | ||||
@@ -779,7 +779,7 @@ jack_client_unload (jack_client_internal_t *client) | |||||
{ | { | ||||
if (client->handle) { | if (client->handle) { | ||||
if (client->finish) { | if (client->finish) { | ||||
client->finish (); | |||||
client->finish (client->control->process_arg); | |||||
} | } | ||||
dlclose (client->handle); | dlclose (client->handle); | ||||
} | } | ||||
@@ -22,6 +22,7 @@ | |||||
#include <config.h> | #include <config.h> | ||||
#include <errno.h> | #include <errno.h> | ||||
#include <assert.h> | #include <assert.h> | ||||
#include <string.h> | |||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <jack/internal.h> | #include <jack/internal.h> | ||||
#include <jack/engine.h> | #include <jack/engine.h> | ||||