![]() |
JACK! | ![]() |
sdl
Guest
![]() |
![]() |
Hello.
Anyone looked into providing a JACK backend for SDL audio? M _______________________________________________ SDL mailing list http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org |
||||||||||
|
![]() |
JACK! | ![]() |
sdl
Guest
![]() |
![]() |
On 2010-01-11 10:56:12, Jacob Meuser wrote:
Nice! Any particular reason this didn't make it into the SDL tree? Kind of annoying to have to close every audio program on my system and shut down jackd just to play an SDL based game... M _______________________________________________ SDL mailing list http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org |
||||||||||||||
|
![]() |
JACK! | ![]() |
Jacob Meuser
Guest
![]() |
![]() |
On Mon, Jan 11, 2010 at 10:18:01AM +0000, wrote:
I did this once ... -- SDF Public Access UNIX System - http://sdf.lonestar.org SDL_jackaudio.h>>> /* SDL - Simple DirectMedia Layer Copyright (C) 1997-2006 Sam Lantinga This library 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 library 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 library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Sam Lantinga */ #include "SDL_config.h" #ifndef _SDL_jackaudio_h #define _SDL_jackaudio_h #include <jack/jack.h> #include "../SDL_sysaudio.h" /* Hidden "this" pointer for the video functions */ #define _THIS SDL_AudioDevice *this struct SDL_PrivateAudioData { /* The parent process id, to detect when application quits */ pid_t parent; /* Raw mixing buffer */ Uint8 *mixbuf; int mixlen; /* Support for audio timing using a timer, in addition to select() */ float frame_ticks; float next_frame; }; #define FUDGE_TICKS 10 /* The scheduler overhead ticks per frame */ /* Old variable names */ #define stream (this->hidden->stream) #define parent (this->hidden->parent) #define mixbuf (this->hidden->mixbuf) #define mixlen (this->hidden->mixlen) #define frame_ticks (this->hidden->frame_ticks) #define next_frame (this->hidden->next_frame) #endif /* _SDL_jackaudio_h */ <<<SDL_jackaudio.h SDL_jackaudio.c>>> /* SDL - Simple DirectMedia Layer Copyright (C) 2008 Jacob Meuser This library 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 library 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 library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Jacob Meuser */ #include "SDL_config.h" /* Allow access to a raw mixing buffer */ #ifdef HAVE_SIGNAL_H #include <signal.h> #endif #include <unistd.h> #include "SDL_timer.h" #include "SDL_audio.h" #include "../SDL_audiomem.h" #include "../SDL_audio_c.h" #include "../SDL_audiodev_c.h" #include "SDL_jackaudio.h" /* The tag name used by jack audio */ #define JACK_DRIVER_NAME "jack" /* Audio driver functions */ static int JACK_OpenAudio(_THIS, SDL_AudioSpec *spec); static void JACK_WaitAudio(_THIS); static void JACK_PlayAudio(_THIS); static Uint8 *JACK_GetAudioBuf(_THIS); static void JACK_CloseAudio(_THIS); static char *client_name = "SDL"; static jack_client_t *client; jack_port_t **client_ports; static const char **playback_port_names; static char *server_name = "default"; static int sample_rate; static int period_size; static int channels; static int sample_bits; jack_default_audio_sample_t **obuf; ssize_t obufsize; pthread_cond_t input_ready = PTHREAD_COND_INITIALIZER; pthread_mutex_t input_lock = PTHREAD_MUTEX_INITIALIZER; /* (mostly) from jack's OSS driver */ static void copy_and_convert_in (jack_default_audio_sample_t *dst, void *src, size_t nframes, int channel, int chcount, int bits) { int srcidx; int dstidx; signed char *s8src = (signed char *) src; signed short *s16src = (signed short *) src; jack_default_audio_sample_t scale; srcidx = channel; switch (bits) { case 8: /* is this right for s8? how to do u8? */ scale = 1.0f / 0x7f; for (dstidx = 0; dstidx < nframes; dstidx++) { dst[dstidx] = (jack_default_audio_sample_t) s8src[srcidx] * scale; srcidx += chcount; } break; case 16: scale = 1.0f / 0x7fff; for (dstidx = 0; dstidx < nframes; dstidx++) { dst[dstidx] = (jack_default_audio_sample_t) s16src[srcidx] * scale; srcidx += chcount; } break; } } /* Audio driver bootstrap functions */ static int Audio_Available(void) { jack_options_t options; jack_status_t status; int available = 0; options = JackServerName | JackNoStartServer; if ( (client = jack_client_open(client_name, options, &status, server_name)) != NULL ) { available = 1; jack_client_close(client); } return available; } static void Audio_DeleteDevice(SDL_AudioDevice *device) { SDL_free(device->hidden); SDL_free(device); } static SDL_AudioDevice *Audio_CreateDevice(int devindex) { SDL_AudioDevice *this; /* Initialize all variables that we clean on shutdown */ this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice)); if ( this ) { SDL_memset(this, 0, (sizeof *this)); this->hidden = (struct SDL_PrivateAudioData *) SDL_malloc((sizeof *this->hidden)); } if ( (this == NULL) || (this->hidden == NULL) ) { SDL_OutOfMemory(); if ( this ) { SDL_free(this); } return(0); } SDL_memset(this->hidden, 0, (sizeof *this->hidden)); /* Set the function pointers */ this->OpenAudio = JACK_OpenAudio; this->WaitAudio = JACK_WaitAudio; this->PlayAudio = JACK_PlayAudio; this->GetAudioBuf = JACK_GetAudioBuf; this->CloseAudio = JACK_CloseAudio; this->free = Audio_DeleteDevice; return this; } AudioBootStrap JACK_bootstrap = { JACK_DRIVER_NAME, "Jack Audio Connection Kit", Audio_Available, Audio_CreateDevice }; /* This function waits until it is possible to write a full sound buffer */ /* but then why does SDL do PlayAudio then WaitAudio ? * instead, let's wait in PlayAudio until we get a process() callback. */ static void JACK_WaitAudio(_THIS) { /* don't wait. this is defined to keep SDL from sleeping */ // bzero(mixbuf, mixlen); #if 0 pthread_mutex_lock(&input_lock); pthread_cond_wait(&input_ready, &input_lock); pthread_mutex_unlock(&input_lock); #endif } static int process(jack_nframes_t nframes, void *arg) { if (pthread_mutex_trylock(&input_lock) == 0) { pthread_cond_signal(&input_ready); pthread_mutex_unlock(&input_lock); } return 0; } static void JACK_PlayAudio(_THIS) { int chn; #if 1 pthread_mutex_lock(&input_lock); pthread_cond_wait(&input_ready, &input_lock); #endif for (chn = 0; chn < channels; chn++) { obuf[chn] = jack_port_get_buffer(client_ports[chn], period_size); copy_and_convert_in(obuf[chn], mixbuf, period_size, chn, channels, sample_bits); } #if 1 pthread_mutex_unlock(&input_lock); #endif #if 0 /* If timer synchronization is enabled, set the next write frame */ if ( frame_ticks ) { next_frame += frame_ticks; } #endif } static Uint8 *JACK_GetAudioBuf(_THIS) { return(mixbuf); } static void JACK_CloseAudio(_THIS) { int i; if ( mixbuf != NULL ) { SDL_FreeAudioMem(mixbuf); mixbuf = NULL; } for (i = 0; i < channels; i++) { if (jack_port_unregister(client, client_ports[i])) { SDL_SetError("jack_port_unregister() failed"); } } jack_client_close(client); free(playback_port_names); free(client_ports); free(obuf); } static int JACK_OpenAudio(_THIS, SDL_AudioSpec *spec) { Uint16 test_format, format; jack_options_t options; jack_status_t status; int i; options = JackServerName | JackNoStartServer; if ( (client = jack_client_open(client_name, options, &status, server_name)) == NULL ) { SDL_SetError("Unable to initialize jack"); return(-1); } client_name = jack_get_client_name(client); sample_rate = jack_get_sample_rate(client); period_size = jack_get_buffer_size(client); channels = spec->channels; playback_port_names = jack_get_ports(client, NULL, NULL, JackPortIsPhysical | JackPortIsInput); jack_set_process_callback(client, process, NULL); if (jack_activate(client)) { SDL_SetError("jack_activate() failed"); } client_ports = (jack_port_t **)malloc(sizeof(jack_port_t*) * channels); if (client_ports == NULL) { printf("could not allocate ports: %s@%i\n", __FILE__, __LINE__); return(1); } obufsize = period_size * sizeof(jack_default_audio_sample_t *); obuf = (jack_default_audio_sample_t **)malloc(obufsize); bzero(obuf, obufsize); for (i = 0; i < channels; i++) { char name[64]; snprintf(name, sizeof(name), "output%d", i + 1); if ((client_ports[i] = jack_port_register(client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0)) == 0) { printf("jack_port_register() failed: %s@%i\n", __FILE__, __LINE__); return(1); } } for (i = 0; i < channels; i++) { printf("connecting output %s ", jack_port_name(client_ports[i])); printf("to input %s\n", playback_port_names[i]); if (jack_connect(client, jack_port_name(client_ports[i]), playback_port_names[i])) { printf("jack_connect() failed: %s@%i\n", __FILE__, __LINE__); return(1); } } /* Reset the timer synchronization flag */ frame_ticks = 0.0; mixbuf = NULL; /* Try for a closest match on audio format */ format = 0; for ( test_format = SDL_FirstAudioFormat(spec->format); ! format && test_format; ) { switch ( test_format ) { case AUDIO_S8: sample_bits = 8; format = 1; break; case AUDIO_S16SYS: sample_bits = 16; format = 1; break; default: format = 0; break; } if ( ! format ) { test_format = SDL_NextAudioFormat(); } } if ( format == 0 ) { SDL_SetError("Couldn't find any hardware audio formats"); return(-1); } spec->format = test_format; spec->freq = sample_rate; spec->samples = period_size; /* Calculate the final parameters for this audio specification */ SDL_CalculateAudioSpec(spec); /* Allocate mixing buffer */ mixlen = spec->size; mixbuf = (Uint8 *)SDL_AllocAudioMem(mixlen); if ( mixbuf == NULL ) { return(-1); } SDL_memset(mixbuf, spec->silence, spec->size); /* Get the parent process id (we're the parent of the audio thread) */ parent = getpid(); /* We're ready to rock and roll. :-) */ return(0); } <<<SDL_jackaudio.c _______________________________________________ SDL mailing list http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org |
||||||||||||
|
![]() |
JACK! | ![]() |
Jacob Meuser
Guest
![]() |
![]() |
On Mon, Jan 11, 2010 at 11:08:01AM +0000, wrote:
I never submitted it. it *worked*, but the idea of callback v. callback is ... well .. many SDL applications don't make for "nice" jack clients anyway. jack clients should to be careful to close their connection (like when you send it a signal, or it crashes), reply on time, etc. jack devs don't like reports of misbehaving clients messing up the client graph. anyway, there is talk in jack circles about having dbus handle which API (alsa/pulse/jack) is being requested, to deal with the issue you are referring to. -- SDF Public Access UNIX System - http://sdf.lonestar.org _______________________________________________ SDL mailing list http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org |
||||||||||||||||
|
![]() |
JACK! | ![]() |
René Dudfield
Guest
![]() |
![]() |
On Mon, Jan 11, 2010 at 11:24 AM, Jacob Meuser wrote:
sweet! it would be great to have SDL working with jack natively. I imagine jack cleanup could be put in exit handlers? So when the sound system is initialised it installs some exit handlers. You can set up alsa plugins so that SDL goes through alsa to jack though. I wrote about using it here: http://renesd.blogspot.com/2009/09/alsa-midi-timidity-fluidsynth-and-jack.html ... but here is the plugin page: http://alsa.opensrc.org/index.php/Jack_%28plugin%29 However, that's not as nice as just setting an environment variable to use JACK :) cheers, _______________________________________________ SDL mailing list http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org |
||||||||||||||||||
|
![]() |
JACK! | ![]() |
sdl
Guest
![]() |
![]() |
'Lo,
On 2010-01-11 11:41:34, René Dudfield wrote:
Yep, I do use that setup. Unfortunately, for some ALSA programs, it just doesn't work. For SDL-based programs, it seems to fail consistently (SDL claims not to be able to open the audio device) and for other programs it works intermittently (Skype mostly works, Flash player spews errors). Some programs appear to work flawlessly... M _______________________________________________ SDL mailing list http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org |
||||||||||||
|
![]() |
JACK! | ![]() |
dominique
Guest
![]() |
![]() |
SNAKE!!!!!!!
Sorry, I'll just step back into my MGS fan closet. _______________________________________________ SDL mailing list http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org |
||||||||||
|
![]() |
JACK! | ![]() |
Ryan C. Gordon
Guest
![]() |
![]() |
That is the most unfortunate term for a community, ever. How widespread is JACK? I didn't realize people used it directly, but rather through ALSA, and assumed that the whole thing was being superceded by PulseAudio anyhow. I'm not against including an SDL audio target for it. --ryan. _______________________________________________ SDL mailing list http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org |
||||||||||||
|
![]() |
JACK! | ![]() |
sdl
Guest
![]() |
![]() |
On 2010-01-11 12:57:24, Ryan C. Gordon wrote:
JACK and PulseAudio don't really have the same goals. JACK is more geared towards pro audio, precise timing and the lowest possible latency (for recording, etc). It also provides inter-application routing which is probably the main reason I use it. As for widespread, it's probably not as popular as PulseAudio. M _______________________________________________ SDL mailing list http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org |
||||||||||||
|
![]() |
JACK! | ![]() |
Johannes Kroll
Guest
![]() |
![]() |
On Mon, 11 Jan 2010 12:57:24 -0500
"Ryan C. Gordon" wrote:
ALSA is used as a backend by JACK, not the other way round. (The ALSA->JACK plugin might be an exception, but it doesn't seem to work reliably). JACK is used for very low-latency audio, intra-application audio routing, and sample-accurate synchronization of applications (sequencers, soft synths, etc). As far as I know, this is not quite the domain of PulseAudio, so PulseAudio won't supercede JACK.
That would be cool! _______________________________________________ SDL mailing list http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org |
||||||||||||||||
|