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 --- | |||
| JACK_MAJOR_VERSION=0 | |||
| JACK_MINOR_VERSION=77 | |||
| JACK_MINOR_VERSION=78 | |||
| JACK_MICRO_VERSION=0 | |||
| @@ -296,6 +296,7 @@ libjack/Makefile | |||
| drivers/Makefile | |||
| drivers/alsa/Makefile | |||
| drivers/solaris/Makefile | |||
| drivers/dummy/Makefile | |||
| example-clients/Makefile | |||
| doc/Makefile | |||
| doc/reference.doxygen | |||
| @@ -1,5 +1,6 @@ | |||
| Makefile | |||
| Makefile.in | |||
| doxygen-build.stamp | |||
| reference | |||
| reference.doxygen | |||
| html | |||
| latex | |||
| @@ -6,7 +6,7 @@ DOX=reference.doxygen | |||
| EXTRA_DIST= | |||
| INSTIMAGES=reference/html/doxygen.png reference/html/fsm.png | |||
| INSTIMAGES=html/doxygen.png /html/fsm.png | |||
| DOC_STAMPS=html-build.stamp | |||
| @@ -25,36 +25,36 @@ clean-local: | |||
| distclean-local: clean | |||
| 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: | |||
| $(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' ; \ | |||
| else \ | |||
| for i in $$installfiles $(INSTIMAGES) reference/html/doxygen.css; do \ | |||
| for i in $$installfiles $(INSTIMAGES) html/doxygen.css; do \ | |||
| echo '-- Installing '$$i ; \ | |||
| $(INSTALL_DATA) $$i $(DESTDIR)$(DOC_DIR)/reference/html; \ | |||
| $(INSTALL_DATA) $$i $(DESTDIR)$(DOC_DIR)/html; \ | |||
| done; \ | |||
| fi) | |||
| # we need doxygen stuff built so we can know what to uninstall | |||
| 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' ; \ | |||
| else \ | |||
| for i in $$installfiles $(INSTIMAGES) reference/html/doxygen.css; do \ | |||
| for i in $$installfiles $(INSTIMAGES) html/doxygen.css; do \ | |||
| echo '-- Unstalling '$$i ; \ | |||
| rm $(DESTDIR)$(DOC_DIR)/$$i; \ | |||
| done; \ | |||
| fi) | |||
| 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 | |||
| @@ -30,7 +30,7 @@ PROJECT_NUMBER = @JACK_VERSION@ | |||
| # 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. | |||
| OUTPUT_DIRECTORY = reference | |||
| OUTPUT_DIRECTORY = | |||
| # The OUTPUT_LANGUAGE tag is used to specify the language in which all | |||
| # documentation generated by doxygen is written. Doxygen will use this | |||
| @@ -12,6 +12,7 @@ else | |||
| SOLARIS_DIR = | |||
| 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) | |||
| { | |||
| switch (driver->sample_bytes) { | |||
| switch (driver->playback_sample_bytes) { | |||
| case 2: | |||
| if (driver->interleaved) { | |||
| if (driver->playback_interleaved) { | |||
| driver->channel_copy = memcpy_interleave_d16_s16; | |||
| } else { | |||
| 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; | |||
| break; | |||
| } | |||
| driver->read_via_copy = sample_move_dS_s16; | |||
| break; | |||
| case 4: | |||
| if (driver->interleaved) { | |||
| if (driver->playback_interleaved) { | |||
| driver->channel_copy = memcpy_interleave_d32_s32; | |||
| } else { | |||
| 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; | |||
| 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; | |||
| 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) | |||
| { | |||
| int p_noninterleaved = 0; | |||
| int c_noninterleaved = 0; | |||
| snd_pcm_format_t c_format = 0; | |||
| snd_pcm_format_t p_format = 0; | |||
| int dir; | |||
| unsigned int p_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) { | |||
| 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_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) { | |||
| 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) { | |||
| 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_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) { | |||
| 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; | |||
| } | |||
| /* 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->interleaved = !c_noninterleaved; | |||
| driver->sample_format = c_format; | |||
| } else if (driver->capture_handle) { | |||
| driver->nfragments = c_nfragments; | |||
| driver->interleaved = !c_noninterleaved; | |||
| driver->sample_format = c_format; | |||
| } else { | |||
| driver->nfragments = p_nfragments; | |||
| driver->interleaved = !p_noninterleaved; | |||
| driver->sample_format = p_format; | |||
| } | |||
| 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_S16_LE: | |||
| 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; | |||
| default: | |||
| jack_error ("programming error: unhandled format type"); | |||
| jack_error ("programming error: unhandled format type for capture"); | |||
| exit (1); | |||
| } | |||
| if (driver->interleaved) { | |||
| if (driver->playback_interleaved) { | |||
| const snd_pcm_channel_area_t *my_areas; | |||
| snd_pcm_uframes_t offset, frames; | |||
| 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; | |||
| } | |||
| 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) { | |||
| 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; | |||
| } | |||
| driver->capture_interleave_skip = my_areas[0].step / 8; | |||
| driver->interleave_unit = snd_pcm_format_physical_width (driver->sample_format) / 8; | |||
| } 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) { | |||
| @@ -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->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->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 offset; | |||
| jack_port_t *port; | |||
| int err; | |||
| 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); | |||
| } | |||
| 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; | |||
| @@ -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 playback_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 frames_per_cycle; | |||
| @@ -76,7 +77,8 @@ typedef struct { | |||
| snd_pcm_uframes_t buffer_frames; | |||
| unsigned long channels_not_done; | |||
| 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; | |||
| unsigned long user_nperiods; | |||
| unsigned long nfragments; | |||
| @@ -102,7 +104,8 @@ typedef struct { | |||
| char hw_metering : 1; | |||
| char all_monitor_in : 1; | |||
| char capture_and_playback_not_synced : 1; | |||
| char interleaved : 1; | |||
| char playback_interleaved : 1; | |||
| char capture_interleaved : 1; | |||
| char with_monitor_ports : 1; | |||
| 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) { | |||
| if (driver->interleaved) { | |||
| if (driver->playback_interleaved) { | |||
| memset_interleave | |||
| (driver->playback_addr[chn], | |||
| 0, nframes * driver->sample_bytes, | |||
| 0, nframes * driver->playback_sample_bytes, | |||
| driver->interleave_unit, | |||
| driver->playback_interleave_skip); | |||
| } 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); | |||
| } | |||
| 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 | |||
| (driver->playback_addr[chn], | |||
| 0, nframes * driver->sample_bytes, | |||
| 0, nframes * driver->playback_sample_bytes, | |||
| driver->interleave_unit, | |||
| driver->playback_interleave_skip); | |||
| } 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->capture_addr[input_channel], | |||
| nsamples * driver->sample_bytes, | |||
| nsamples * driver->playback_sample_bytes, | |||
| driver->playback_interleave_skip, | |||
| driver->capture_interleave_skip); | |||
| 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! */ | |||
| dlhandle handle; | |||
| 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; | |||
| #if defined(__APPLE__) && defined(__POWERPC__) | |||
| @@ -779,7 +779,7 @@ jack_client_unload (jack_client_internal_t *client) | |||
| { | |||
| if (client->handle) { | |||
| if (client->finish) { | |||
| client->finish (); | |||
| client->finish (client->control->process_arg); | |||
| } | |||
| dlclose (client->handle); | |||
| } | |||
| @@ -22,6 +22,7 @@ | |||
| #include <config.h> | |||
| #include <errno.h> | |||
| #include <assert.h> | |||
| #include <string.h> | |||
| #include <stdio.h> | |||
| #include <jack/internal.h> | |||
| #include <jack/engine.h> | |||