Author: titmuss
Date: Tue Dec 23 14:52:26 2008
New Revision: 3628
URL: http://svn.slimdevices.com?rev=3628&root=Jive&view=rev
Log:
Bug: N/A
Description:
Make the alsa output configurable. The audio playback and sound effects can be
routed to different devices, and
the buffer time and period count can be set (at the moment by editing a
configuration file, this is not yet
exposed to the ui).
Added:
7.4/trunk/squeezeplay/src/squeezeplay/share/applets/Playback/loadPriority.lua
Modified:
7.4/trunk/squeezeplay/src/squeezeplay/share/applets/Playback/PlaybackMeta.lua
7.4/trunk/squeezeplay/src/squeezeplay/share/applets/SetupSoundEffects/loadPriority.lua
7.4/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode.c
7.4/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_alsa.c
7.4/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_output.c
7.4/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_portaudio.c
7.4/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_priv.h
Modified:
7.4/trunk/squeezeplay/src/squeezeplay/share/applets/Playback/PlaybackMeta.lua
URL:
http://svn.slimdevices.com/7.4/trunk/squeezeplay/src/squeezeplay/share/applets/Playback/PlaybackMeta.lua?rev=3628&root=Jive&r1=3627&r2=3628&view=diff
==============================================================================
---
7.4/trunk/squeezeplay/src/squeezeplay/share/applets/Playback/PlaybackMeta.lua
(original)
+++
7.4/trunk/squeezeplay/src/squeezeplay/share/applets/Playback/PlaybackMeta.lua
Tue Dec 23 14:52:26 2008
@@ -9,8 +9,10 @@
local LocalPlayer = require("jive.slim.LocalPlayer")
local SlimServer = require("jive.slim.SlimServer")
-local debug = require("jive.utils.debug")
-local log = require("jive.utils.log").logger("applet")
+local Decode = require("squeezeplay.decode")
+
+local debug = require("jive.utils.debug")
+local log = require("jive.utils.log").logger("applet")
local appletManager = appletManager
local jiveMain = jiveMain
@@ -34,13 +36,29 @@
-- 2 == user off
-- 3 == user on
enableAudio = 0,
+
+ -- alsa settings
+ alsaPlaybackDevice = "default",
+ alsaPlaybackBufferTime = 60000,
+ alsaPlaybackPeriodCount = 3,
+
+ alsaEffectsDevice = nil,
+ alsaEffectsBufferTime = nil,
+ alsaEffectsPeriodCount = nil,
}
end
function registerApplet(meta)
+ local settings = meta:getSettings()
+
-- this allows us to share state with the applet
meta.state = {}
+
+ if not Decode:open(settings) then
+ -- no audio device
+ return
+ end
jiveMain:addItem(meta:menuItem('audioPlayback', 'advancedSettings',
"AUDIO_PLAYBACK", function(applet, ...) applet:settingsShow(meta.state) end))
end
@@ -53,7 +71,6 @@
-- no audio playback
return
end
-
-- Create player instance
local uuid = System:getUUID()
Added:
7.4/trunk/squeezeplay/src/squeezeplay/share/applets/Playback/loadPriority.lua
URL:
http://svn.slimdevices.com/7.4/trunk/squeezeplay/src/squeezeplay/share/applets/Playback/loadPriority.lua?rev=3628&root=Jive&view=auto
==============================================================================
---
7.4/trunk/squeezeplay/src/squeezeplay/share/applets/Playback/loadPriority.lua
(added)
+++
7.4/trunk/squeezeplay/src/squeezeplay/share/applets/Playback/loadPriority.lua
Tue Dec 23 14:52:26 2008
@@ -1,0 +1,1 @@
+loadPriority=10
Modified:
7.4/trunk/squeezeplay/src/squeezeplay/share/applets/SetupSoundEffects/loadPriority.lua
URL:
http://svn.slimdevices.com/7.4/trunk/squeezeplay/src/squeezeplay/share/applets/SetupSoundEffects/loadPriority.lua?rev=3628&root=Jive&r1=3627&r2=3628&view=diff
==============================================================================
---
7.4/trunk/squeezeplay/src/squeezeplay/share/applets/SetupSoundEffects/loadPriority.lua
(original)
+++
7.4/trunk/squeezeplay/src/squeezeplay/share/applets/SetupSoundEffects/loadPriority.lua
Tue Dec 23 14:52:26 2008
@@ -1,1 +1,1 @@
-loadPriority=2
+loadPriority=11
Modified: 7.4/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode.c
URL:
http://svn.slimdevices.com/7.4/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode.c?rev=3628&root=Jive&r1=3627&r2=3628&view=diff
==============================================================================
--- 7.4/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode.c (original)
+++ 7.4/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode.c Tue Dec 23
14:52:26 2008
@@ -22,7 +22,7 @@
#define DECODE_METADATA_SIZE 128
/* decoder thread */
-static SDL_Thread *decode_thread;
+static SDL_Thread *decode_thread = NULL;
/* current decoder state */
@@ -103,7 +103,9 @@
if (!fifo_empty(&decode_fifo)) {
current_audio_state = DECODE_STATE_RUNNING;
- decode_audio->resume();
+ if (decode_audio) {
+ decode_audio->resume();
+ }
}
fifo_unlock(&decode_fifo);
@@ -126,7 +128,9 @@
add_silence_ms = interval;
} else {
current_audio_state &= ~DECODE_STATE_RUNNING;
- decode_audio->pause();
+ if (decode_audio) {
+ decode_audio->pause();
+ }
}
fifo_unlock(&decode_fifo);
@@ -569,7 +573,7 @@
lua_setfield(L, -2, "outputTime");
elapsed = decode_elapsed_samples;
- delay = decode_audio->delay ? decode_audio->delay() : 0;
+ delay = (decode_audio && decode_audio->delay) ? decode_audio->delay() :
0;
if (elapsed > delay) {
elapsed -= delay;
}
@@ -633,12 +637,52 @@
lgain = lua_tointeger(L, 2);
rgain = lua_tointeger(L, 3);
- decode_audio->gain(lgain, rgain);
-
- return 0;
-}
+ if (decode_audio) {
+ decode_audio->gain(lgain, rgain);
+ }
+
+ return 0;
+}
+
+
+static int decode_audio_open(lua_State *L) {
+ /* initialise audio output */
+#ifdef HAVE_LIBASOUND
+ decode_audio = &decode_alsa;
+#endif
+#ifdef HAVE_LIBPORTAUDIO
+ if (!decode_audio) {
+ decode_audio = &decode_portaudio;
+ }
+#endif
+ if (!decode_audio) {
+ /* no audio support */
+ lua_pushnil(L);
+ lua_pushstring(L, "No audio support");
+ return 2;
+ }
+
+ if (!decode_audio->init(L)) {
+ /* audio init failed */
+ decode_audio = NULL;
+
+ lua_pushnil(L);
+ lua_pushstring(L, "Error in audio init");
+ return 2;
+ }
+
+ /* start decoder thread */
+ if (!decode_thread) {
+ decode_thread = SDL_CreateThread(decode_thread_execute, NULL);
+ }
+
+ lua_pushboolean(L, 1);
+ return 1;
+}
+
static const struct luaL_Reg decode_f[] = {
+ { "open", decode_audio_open },
{ "resumeDecoder", decode_resume_decoder },
{ "resumeAudio", decode_resume_audio },
{ "pauseAudio", decode_pause_audio },
@@ -660,34 +704,9 @@
/* register sample playback */
decode_sample_init(L);
- /* initialise audio output */
-#ifdef HAVE_LIBASOUND
- decode_audio = &decode_alsa;
-#endif
-#ifdef HAVE_LIBPORTAUDIO
- if (!decode_audio) {
- decode_audio = &decode_portaudio;
- }
-#endif
- if (!decode_audio) {
- /* no audio support */
- DEBUG_ERROR("No audio support");
- return 0;
- }
-
fifo_init(&decode_fifo, DECODE_FIFO_SIZE);
- if (!decode_audio->init()) {
- DEBUG_ERROR("Failed to init audio");
-
- fifo_free(&decode_fifo);
- return 0;
- }
-
mqueue_init(&decode_mqueue, decode_mqueue_buffer,
sizeof(decode_mqueue_buffer));
-
- /* start decoder thread */
- decode_thread = SDL_CreateThread(decode_thread_execute, NULL);
/* register lua functions */
luaL_register(L, "squeezeplay.decode", decode_f);
Modified: 7.4/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_alsa.c
URL:
http://svn.slimdevices.com/7.4/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_alsa.c?rev=3628&root=Jive&r1=3627&r2=3628&view=diff
==============================================================================
--- 7.4/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_alsa.c
(original)
+++ 7.4/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_alsa.c Tue
Dec 23 14:52:26 2008
@@ -20,35 +20,57 @@
#include <pthread.h>
#include <alsa/asoundlib.h>
-/* Stream sample rate */
-static u32_t new_sample_rate;
-static u32_t pcm_sample_rate;
-
-
-/* alsa */
-static char *device = "default";
-//static char *device = "plughw:0,0";
-
+
+
+#define FLAG_STREAM_PLAYBACK 0x01
+#define FLAG_STREAM_EFFECTS 0x02
+
+struct decode_alsa {
+ /* device configuration */
+ const char *name;
+ u32_t flags;
+ unsigned int buffer_time;
+ unsigned int period_count;
+
+ /* alsa state */
+ snd_pcm_t *pcm;
+ snd_pcm_hw_params_t *hw_params;
+ snd_pcm_sframes_t period_size;
+
+ /* playback state */
+ u32_t new_sample_rate;
+ u32_t pcm_sample_rate;
+
+ fft_fixed lgain, rgain;
+
+ /* thread */
+ pthread_t thread;
+};
+
+
+#define ALSA_DEFAULT_DEVICE "default"
+#define ALSA_DEFAULT_BUFFER_TIME 500000
+#define ALSA_DEFAULT_PERIOD_COUNT 3
+
+
+/* alsa debugging */
static snd_output_t *output;
-static snd_pcm_t *handle = NULL;
-static snd_pcm_hw_params_t *hwparams;
-
-static snd_pcm_sframes_t period_size;
-static fft_fixed lgain, rgain;
-
-static pthread_t audio_thread;
-
-
-static void decode_alsa_gain(s32_t lgain, s32_t rgain);
+
+/* player state */
+static struct decode_alsa *playback_state;
+static struct decode_alsa *effects_state;
+
/*
- * This function is called by portaudio when the stream is active to request
- * audio samples
+ * This function is called by to copy samples from the output buffer to
+ * the alsa buffer.
+ *
* Called with fifo-lock held.
*/
-static void callback(void *outputBuffer,
- unsigned long framesPerBuffer) {
+static void playback_callback(struct decode_alsa *state,
+ void *outputBuffer,
+ unsigned long framesPerBuffer) {
size_t bytes_used, len, skip_bytes = 0, add_bytes = 0;
bool_t reached_start_point;
Uint8 *outputArray = (u8_t *)outputBuffer;
@@ -61,7 +83,7 @@
if (!(current_audio_state & DECODE_STATE_RUNNING)) {
memset(outputArray, 0, len);
- goto mixin_effects;
+ return;
}
if (add_silence_ms) {
@@ -77,7 +99,7 @@
add_silence_ms = 0;
}
if (!len) {
- goto mixin_effects;
+ return;
}
}
@@ -101,7 +123,7 @@
memset(outputArray, 0, len);
DEBUG_ERROR("Audio underrun: used 0 bytes");
- goto mixin_effects;
+ return;
}
if (bytes_used < len) {
@@ -148,8 +170,8 @@
output_ptr = (sample_t *)(void *)outputArray;
decode_ptr = (sample_t *)(void *)(decode_fifo_buf +
decode_fifo.rptr);
while (samples_write--) {
- *(output_ptr++) = fixed_mul(lgain, *(decode_ptr++));
- *(output_ptr++) = fixed_mul(rgain, *(decode_ptr++));
+ *(output_ptr++) = fixed_mul(state->lgain,
*(decode_ptr++));
+ *(output_ptr++) = fixed_mul(state->rgain,
*(decode_ptr++));
}
fifo_rptr_incby(&decode_fifo, bytes_write);
@@ -160,136 +182,165 @@
}
reached_start_point = decode_check_start_point();
- if (reached_start_point && current_sample_rate != pcm_sample_rate) {
- new_sample_rate = current_sample_rate;
- }
-
- mixin_effects:
- /* mix in sound effects */
+ if (reached_start_point && current_sample_rate !=
state->pcm_sample_rate) {
+ state->new_sample_rate = current_sample_rate;
+ }
+}
+
+
+/*
+ * This function is called by to copy effects to the alsa buffer.
+ */
+static void effects_callback(struct decode_alsa *state,
+ void *outputBuffer,
+ unsigned long framesPerBuffer) {
+
decode_sample_mix(outputBuffer, SAMPLES_TO_BYTES(framesPerBuffer));
-
- return;
-}
-
-
-static int pcm_open(u32_t sample_rate) {
+}
+
+
+static int pcm_close(struct decode_alsa *state) {
+ int err;
+
+ if (!state->pcm) {
+ return 0;
+ }
+
+ if ((err = snd_pcm_drain(state->pcm)) < 0) {
+ DEBUG_ERROR("snd_pcm_drain error: %s", snd_strerror(err));
+ }
+
+ if ((err = snd_pcm_close(state->pcm)) < 0) {
+ DEBUG_ERROR("snd_pcm_close error: %s", snd_strerror(err));
+ }
+
+ snd_pcm_hw_params_free(state->hw_params);
+
+ state->pcm = NULL;
+ return 0;
+}
+
+
+static int pcm_open(struct decode_alsa *state) {
int err, dir;
snd_pcm_uframes_t size;
- unsigned int val;
-#define BUFFER_TIME 30000
-#define PERIOD_COUNT 3
-
- if (handle && sample_rate == pcm_sample_rate) {
- return 0;
- }
/* Close existing pcm (if any) */
- if (handle) {
- if ((err = snd_pcm_drain(handle)) < 0) {
- DEBUG_ERROR("snd_pcm_drain error: %s",
snd_strerror(err));
- }
-
- if ((err = snd_pcm_close(handle)) < 0) {
- DEBUG_ERROR("snd_pcm_close error: %s",
snd_strerror(err));
- }
-
- handle = NULL;
+ if (state->pcm) {
+ pcm_close(state);
}
/* Open pcm */
- if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) <
0) {
+ if ((err = snd_pcm_open(&state->pcm, state->name,
SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
DEBUG_ERROR("Playback open error: %s", snd_strerror(err));
return err;
}
/* Set hardware parameters */
- if ((err = snd_pcm_hw_params_malloc(&hwparams)) < 0) {
+ if ((err = snd_pcm_hw_params_malloc(&state->hw_params)) < 0) {
DEBUG_ERROR("hwparam malloc error: %s", snd_strerror(err));
return err;
}
- if ((err = snd_pcm_hw_params_any(handle, hwparams)) < 0) {
+ if ((err = snd_pcm_hw_params_any(state->pcm, state->hw_params)) < 0) {
DEBUG_ERROR("hwparam init error: %s", snd_strerror(err));
return err;
}
/* set hardware resampling */
- if ((err = snd_pcm_hw_params_set_rate_resample(handle, hwparams, 1)) <
0) {
+ if ((err = snd_pcm_hw_params_set_rate_resample(state->pcm,
state->hw_params, 1)) < 0) {
DEBUG_ERROR("Resampling setup failed: %s\n", snd_strerror(err));
return err;
}
/* set mmap interleaved access format */
- if ((err = snd_pcm_hw_params_set_access(handle, hwparams,
SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0) {
+ if ((err = snd_pcm_hw_params_set_access(state->pcm, state->hw_params,
SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0) {
DEBUG_ERROR("Access type not available: %s", snd_strerror(err));
return err;
}
/* set the sample format */
- if ((err = snd_pcm_hw_params_set_format(handle, hwparams,
SND_PCM_FORMAT_S32_LE)) < 0) {
+ if ((err = snd_pcm_hw_params_set_format(state->pcm, state->hw_params,
SND_PCM_FORMAT_S32_LE)) < 0) {
DEBUG_ERROR("Sample format not available: %s",
snd_strerror(err));
return err;
}
/* set the channel count */
- if ((err = snd_pcm_hw_params_set_channels(handle, hwparams, 2)) < 0) {
+ if ((err = snd_pcm_hw_params_set_channels(state->pcm, state->hw_params,
2)) < 0) {
DEBUG_ERROR("Channel count not available: %s",
snd_strerror(err));
return err;
}
/* set the stream rate */
- if ((err = snd_pcm_hw_params_set_rate_near(handle, hwparams,
&sample_rate, 0)) < 0) {
+ if ((err = snd_pcm_hw_params_set_rate_near(state->pcm,
state->hw_params, &state->new_sample_rate, 0)) < 0) {
DEBUG_ERROR("Rate not available: %s", snd_strerror(err));
return err;
}
/* set buffer and period times */
- val = BUFFER_TIME;
- if ((err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams,
&val, &dir)) < 0) {
+ if ((err = snd_pcm_hw_params_set_buffer_time_near(state->pcm,
state->hw_params, &state->buffer_time, &dir)) < 0) {
DEBUG_ERROR("Unable to set buffer time %s", snd_strerror(err));
return err;
}
- val = PERIOD_COUNT;
- if ((err = snd_pcm_hw_params_set_periods_near(handle, hwparams, &val,
&dir)) < 0) {
+ if ((err = snd_pcm_hw_params_set_periods_near(state->pcm,
state->hw_params, &state->period_count, &dir)) < 0) {
DEBUG_ERROR("Unable to set period size %s", snd_strerror(err));
return err;
}
- if ((err = snd_pcm_hw_params_get_period_size(hwparams, &size, &dir)) <
0) {
+ if ((err = snd_pcm_hw_params_get_period_size(state->hw_params, &size,
&dir)) < 0) {
DEBUG_ERROR("Unable to get period size: %s", snd_strerror(err));
return err;
}
- period_size = size;
+ state->period_size = size;
/* set hardware parameters */
- if ((err = snd_pcm_hw_params(handle, hwparams)) < 0) {
+ if ((err = snd_pcm_hw_params(state->pcm, state->hw_params)) < 0) {
DEBUG_ERROR("Unable to set hw params: %s", snd_strerror(err));
return err;
}
#ifdef RUNTIME_DEBUG
- snd_pcm_dump(handle, output);
+ snd_pcm_dump(state->pcm, output);
#endif
- pcm_sample_rate = sample_rate;
+ state->pcm_sample_rate = state->new_sample_rate;
+ state->new_sample_rate = 0;
return 0;
}
-static int xrun_recovery(snd_pcm_t *handle, int err) {
+static int pcm_test(const char *name) {
+ struct decode_alsa tmp_state;
+ int err;
+
+ memset(&tmp_state, 0, sizeof(struct decode_alsa));
+ tmp_state.name = name;
+ tmp_state.buffer_time = ALSA_DEFAULT_BUFFER_TIME;
+ tmp_state.period_count = ALSA_DEFAULT_PERIOD_COUNT;
+ tmp_state.new_sample_rate = 44100;
+ if ((err = pcm_open(&tmp_state)) < 0) {
+ return err;
+ }
+ pcm_close(&tmp_state);
+
+ return 0;
+}
+
+
+static int xrun_recovery(struct decode_alsa *state, int err) {
if (err == -EPIPE) { /* under-run */
- if ((err = snd_pcm_prepare(handle) < 0)) {
+ if ((err = snd_pcm_prepare(state->pcm) < 0)) {
DEBUG_ERROR("Can't recovery from underrun, prepare
failed: %s\n", snd_strerror(err));
}
return 0;
} else if (err == -ESTRPIPE) {
- while ((err = snd_pcm_resume(handle)) == -EAGAIN) {
+ while ((err = snd_pcm_resume(state->pcm)) == -EAGAIN) {
sleep(1); /* wait until the suspend flag is
released */
}
if (err < 0) {
- if ((err = snd_pcm_prepare(handle)) < 0) {
+ if ((err = snd_pcm_prepare(state->pcm)) < 0) {
DEBUG_ERROR("Can't recovery from suspend,
prepare failed: %s\n", snd_strerror(err));
}
}
@@ -299,15 +350,13 @@
}
-static void *audio_thread_execute(void *unused) {
- snd_pcm_state_t state;
- const snd_pcm_channel_area_t *areas;
- snd_pcm_uframes_t offset;
- snd_pcm_uframes_t frames, size;
- snd_pcm_sframes_t avail, commitres;
+static void *audio_thread_execute(void *data) {
+ struct decode_alsa *state = (struct decode_alsa *)data;
+ snd_pcm_state_t pcm_state;
+ snd_pcm_uframes_t size;
+ snd_pcm_sframes_t avail;
snd_pcm_status_t *status;
int err, first = 1;
- void *buf;
DEBUG_TRACE("audio_thread_execute");
@@ -316,34 +365,32 @@
while (1) {
fifo_lock(&decode_fifo);
- if (new_sample_rate) {
- if ((err = pcm_open(new_sample_rate)) < 0) {
+ if (state->new_sample_rate) {
+ if ((err = pcm_open(state)) < 0) {
DEBUG_ERROR("Open failed: %s",
snd_strerror(err));
- return (void *)-1;
- }
-
- new_sample_rate = 0;
+ goto thread_error_unlock;
+ }
first = 1;
}
fifo_unlock(&decode_fifo);
- state = snd_pcm_state(handle);
- if (state == SND_PCM_STATE_XRUN) {
- if ((err = xrun_recovery(handle, -EPIPE)) < 0) {
+ pcm_state = snd_pcm_state(state->pcm);
+ if (pcm_state == SND_PCM_STATE_XRUN) {
+ if ((err = xrun_recovery(state, -EPIPE)) < 0) {
DEBUG_ERROR("XRUN recovery failed: %s",
snd_strerror(err));
}
first = 1;
}
- else if (state == SND_PCM_STATE_SUSPENDED) {
- if ((err = xrun_recovery(handle, -ESTRPIPE)) < 0) {
+ else if (pcm_state == SND_PCM_STATE_SUSPENDED) {
+ if ((err = xrun_recovery(state, -ESTRPIPE)) < 0) {
DEBUG_ERROR("SUSPEND recovery failed: %s",
snd_strerror(err));
}
}
- avail = snd_pcm_avail_update(handle);
+ avail = snd_pcm_avail_update(state->pcm);
if (avail < 0) {
- if ((err = xrun_recovery(handle, avail)) < 0) {
+ if ((err = xrun_recovery(state, avail)) < 0) {
DEBUG_ERROR("Avail update failed: %s",
snd_strerror(err));
}
first = 1;
@@ -351,21 +398,21 @@
}
/* this is needed to ensure the sound works on resume */
- if (( err = snd_pcm_status(handle, status)) < 0) {
- printf("snd_pcm_status err=%d\n", err);
- }
-
- if (avail < period_size) {
+ if (( err = snd_pcm_status(state->pcm, status)) < 0) {
+ DEBUG_ERROR("snd_pcm_status err=%d\n", err);
+ }
+
+ if (avail < state->period_size) {
if (first) {
first = 0;
- if ((err = snd_pcm_start(handle)) < 0) {
+ if ((err = snd_pcm_start(state->pcm)) < 0) {
DEBUG_ERROR("Audio start error: %s",
snd_strerror(err));
}
}
else {
- if ((err = snd_pcm_wait(handle, 500)) < 0) {
+ if ((err = snd_pcm_wait(state->pcm, 500)) < 0) {
printf("err=%d\n", err);
- if ((err = xrun_recovery(handle,
avail)) < 0) {
+ if ((err = xrun_recovery(state, avail))
< 0) {
DEBUG_ERROR("PCM wait failed:
%s", snd_strerror(err));
}
first = 1;
@@ -375,12 +422,17 @@
continue;
}
- size = period_size;
+ size = state->period_size;
while (size > 0) {
+ const snd_pcm_channel_area_t *areas;
+ snd_pcm_uframes_t frames, offset;
+ snd_pcm_sframes_t commitres;
+ void *buf;
+
frames = size;
- if ((err = snd_pcm_mmap_begin(handle, &areas, &offset,
&frames)) < 0) {
- if ((err = xrun_recovery(handle, avail)) < 0) {
+ if ((err = snd_pcm_mmap_begin(state->pcm, &areas,
&offset, &frames)) < 0) {
+ if ((err = xrun_recovery(state, avail)) < 0) {
DEBUG_ERROR("mmap begin failed: %s",
snd_strerror(err));
}
first = 1;
@@ -389,13 +441,22 @@
fifo_lock(&decode_fifo);
buf = ((u8_t *)areas[0].addr) + (areas[0].first +
offset * areas[0].step) / 8;
- callback(buf, frames);
+
+ if (state->flags & FLAG_STREAM_PLAYBACK) {
+ playback_callback(state, buf, frames);
+ }
+ else {
+ memset(buf, 0, SAMPLES_TO_BYTES(frames));
+ }
+ if (state->flags & FLAG_STREAM_EFFECTS) {
+ effects_callback(state, buf, frames);
+ }
fifo_unlock(&decode_fifo);
- commitres = snd_pcm_mmap_commit(handle, offset,
frames);
+ commitres = snd_pcm_mmap_commit(state->pcm, offset,
frames);
if (commitres < 0 || (snd_pcm_uframes_t)commitres !=
frames) {
- if ((err = xrun_recovery(handle, avail)) < 0) {
+ if ((err = xrun_recovery(state, avail)) < 0) {
DEBUG_ERROR("mmap commit failed: %s",
snd_strerror(err));
}
first = 1;
@@ -403,130 +464,208 @@
size -= frames;
}
}
-}
-
-
-static void decode_alsa_start(void) {
- DEBUG_TRACE("decode_alsa_start");
-
- fifo_lock(&decode_fifo);
- if (pcm_sample_rate != current_sample_rate) {
- new_sample_rate = current_sample_rate;
- }
+
+ thread_error_unlock:
fifo_unlock(&decode_fifo);
-}
-
-
-static void decode_alsa_resume(void) {
- DEBUG_TRACE("decode_alsa_resume");
-
- fifo_lock(&decode_fifo);
- if (pcm_sample_rate != current_sample_rate) {
- new_sample_rate = current_sample_rate;
- }
- // snd_pcm_pause(handle, 1);
- fifo_unlock(&decode_fifo);
-}
-
-
-static void decode_alsa_pause(void) {
- DEBUG_TRACE("decode_alsa_pause");
-
- fifo_lock(&decode_fifo);
-// snd_pcm_pause(handle, 0);
- if (pcm_sample_rate != 44100) {
- new_sample_rate = 44100;
- }
- fifo_unlock(&decode_fifo);
-}
-
-
-static void decode_alsa_stop(void) {
- DEBUG_TRACE("decode_alsa_stop");
-
- fifo_lock(&decode_fifo);
- if (pcm_sample_rate != 44100) {
- new_sample_rate = 44100;
- }
- fifo_unlock(&decode_fifo);
-}
-
-
-static int decode_alsa_init(void) {
- int err;
+ free(status);
+
+ DEBUG_ERROR("Audio thread exited");
+ return (void *)-1;
+}
+
+
+static struct decode_alsa *decode_alsa_thread_init(const char *name, unsigned
int buffer_time, unsigned int period_count, u32_t flags) {
+ struct decode_alsa *state;
pthread_attr_t thread_attr;
struct sched_param thread_param;
size_t stacksize;
+ int err;
+
+ state = calloc(sizeof(struct decode_alsa), 1);
+ state->name = name;
+ state->flags = flags;
+ state->buffer_time = buffer_time;
+ state->period_count = period_count;
+ state->new_sample_rate = 44100;
+ state->lgain = FIXED_ONE;
+ state->rgain = FIXED_ONE;
+
+
+ /* start audio thread */
+ if ((err = pthread_attr_init(&thread_attr)) != 0) {
+ DEBUG_ERROR("pthread_attr_init: %s", strerror(err));
+ goto thread_err;
+ }
+
+ if ((err = pthread_attr_setdetachstate(&thread_attr,
PTHREAD_CREATE_DETACHED)) != 0) {
+ DEBUG_ERROR("pthread_attr_setdetachstate: %s", strerror(err));
+ goto thread_err;
+ }
+
+ stacksize = 32 * 1024; /* 32k stack, we don't do much here */
+ if ((err = pthread_attr_setstacksize(&thread_attr, stacksize)) != 0) {
+ DEBUG_ERROR("pthread_attr_setstacksize: %s", strerror(err));
+ }
+
+ if ((err = pthread_create(&state->thread, &thread_attr,
audio_thread_execute, state)) != 0) {
+ DEBUG_ERROR("pthread_create: %s", strerror(err));
+ goto thread_err;
+ }
+
+ /* set realtime scheduler policy, with a high priority */
+ thread_param.sched_priority = sched_get_priority_max(SCHED_FIFO);
+
+ err = pthread_setschedparam(state->thread, SCHED_FIFO, &thread_param);
+ if (err) {
+ if (err == EPERM) {
+ DEBUG_ERROR("Can't set audio thread priority\n");
+ }
+ else {
+ DEBUG_ERROR("pthread_create: %s", strerror(err));
+ goto thread_err;
+ }
+ }
+
+ return state;
+
+ thread_err:
+ // FIXME clean up
+ return NULL;
+}
+
+
+static u32_t decode_alsa_delay(void)
+{
+ snd_pcm_status_t* status;
+
+ /* dies with warning on GCC 4.2:
+ * snd_pcm_status_alloca(&status);
+ */
+ status = (snd_pcm_status_t *) alloca(snd_pcm_hw_params_sizeof());
+ memset(status, 0, snd_pcm_hw_params_sizeof());
+
+ snd_pcm_status(playback_state->pcm, status);
+
+ return (u32_t)snd_pcm_status_get_delay(status);
+}
+
+
+static void decode_alsa_start(void) {
+ DEBUG_TRACE("decode_alsa_start");
+
+ fifo_lock(&decode_fifo);
+ if (playback_state->pcm_sample_rate != current_sample_rate) {
+ playback_state->new_sample_rate = current_sample_rate;
+ }
+ fifo_unlock(&decode_fifo);
+}
+
+
+static void decode_alsa_resume(void) {
+ DEBUG_TRACE("decode_alsa_resume");
+
+ fifo_lock(&decode_fifo);
+ if (playback_state->pcm_sample_rate != current_sample_rate) {
+ playback_state->new_sample_rate = current_sample_rate;
+ }
+ // snd_pcm_pause(playback_state.pcm, 1);
+ fifo_unlock(&decode_fifo);
+}
+
+
+static void decode_alsa_pause(void) {
+ DEBUG_TRACE("decode_alsa_pause");
+
+ fifo_lock(&decode_fifo);
+// snd_pcm_pause(playback_state.pcm, 0);
+ if (playback_state->pcm_sample_rate != 44100) {
+ playback_state->new_sample_rate = 44100;
+ }
+ fifo_unlock(&decode_fifo);
+}
+
+
+static void decode_alsa_stop(void) {
+ DEBUG_TRACE("decode_alsa_stop");
+
+ fifo_lock(&decode_fifo);
+ if (playback_state->pcm_sample_rate != 44100) {
+ playback_state->new_sample_rate = 44100;
+ }
+ fifo_unlock(&decode_fifo);
+}
+
+
+static void decode_alsa_gain(s32_t left_gain, s32_t right_gain) {
+ playback_state->lgain = left_gain;
+ playback_state->rgain = right_gain;
+}
+
+
+static int decode_alsa_init(lua_State *L) {
+ int err;
+ const char *playback_device;
+ const char *effects_device;
+ unsigned int buffer_time;
+ unsigned int period_count;
+
if ((err = snd_output_stdio_attach(&output, stdout, 0)) < 0) {
DEBUG_ERROR("Output failed: %s", snd_strerror(err));
return 0;
}
- DEBUG_TRACE("Playback device: %s\n", device);
-
- if (pcm_open(44100) < 0) {
+ lua_getfield(L, 2, "alsaPlaybackDevice");
+ playback_device = luaL_optstring(L, -1, ALSA_DEFAULT_DEVICE);
+
+ lua_getfield(L, 2, "alsaEffectsDevice");
+ effects_device = luaL_optstring(L, -1, NULL);
+
+
+ /* test if device is available */
+ if (pcm_test(playback_device) < 0) {
+ lua_pop(L, 2);
return 0;
}
- /* start audio thread */
- if ((err = pthread_attr_init(&thread_attr)) != 0) {
- DEBUG_ERROR("pthread_attr_init: %s", strerror(err));
- return 0;
- }
-
- if ((err = pthread_attr_setdetachstate(&thread_attr,
PTHREAD_CREATE_DETACHED)) != 0) {
- DEBUG_ERROR("pthread_attr_setdetachstate: %s", strerror(err));
- return 0;
- }
-
- stacksize = 32 * 1024; /* 32k stack, we don't do much here */
- if ((err = pthread_attr_setstacksize(&thread_attr, stacksize)) != 0) {
- DEBUG_ERROR("pthread_attr_setstacksize: %s", strerror(err));
- }
-
- if ((err = pthread_create(&audio_thread, &thread_attr,
audio_thread_execute, NULL)) != 0) {
- DEBUG_ERROR("pthread_create: %s", strerror(err));
- return 0;
- }
-
- /* set realtime scheduler policy, with a high priority */
- thread_param.sched_priority = sched_get_priority_max(SCHED_FIFO);
-
- err = pthread_setschedparam(audio_thread, SCHED_FIFO, &thread_param);
- if (err) {
- if (err == EPERM) {
- DEBUG_ERROR("Can't set audio thread priority\n");
- }
- else {
- DEBUG_ERROR("pthread_create: %s", strerror(err));
- return 0;
- }
- }
-
+ if (effects_device && pcm_test(effects_device) < 0) {
+ effects_device = NULL;
+ }
+
+ DEBUG_TRACE("Playback device: %s\n", playback_device);
+
+ lua_getfield(L, 2, "alsaPlaybackBufferTime");
+ buffer_time = luaL_optinteger(L, -1, ALSA_DEFAULT_BUFFER_TIME);
+ lua_getfield(L, 2, "alsaPlaybackPeriodCount");
+ period_count = luaL_optinteger(L, -1, ALSA_DEFAULT_PERIOD_COUNT);
+ lua_pop(L, 2);
+
+ playback_state =
+ decode_alsa_thread_init(playback_device,
+ buffer_time,
+ period_count,
+ (effects_device) ? FLAG_STREAM_PLAYBACK
: FLAG_STREAM_PLAYBACK | FLAG_STREAM_EFFECTS
+ );
+
+ if (effects_device) {
+ DEBUG_TRACE("Effects device: %s\n", effects_device);
+
+ lua_getfield(L, 2, "alsaEffectsBufferTime");
+ buffer_time = luaL_optinteger(L, -1, ALSA_DEFAULT_BUFFER_TIME);
+ lua_getfield(L, 2, "alsaEffectsPeriodCount");
+ period_count = luaL_optinteger(L, -1,
ALSA_DEFAULT_PERIOD_COUNT);
+ lua_pop(L, 2);
+
+ effects_state =
+ decode_alsa_thread_init(effects_device,
+ buffer_time,
+ period_count,
+ FLAG_STREAM_EFFECTS
+ );
+ }
+
+ lua_pop(L, 2);
return 1;
-}
-
-static u32_t decode_alsa_delay(void)
-{
- snd_pcm_status_t* status;
-
- /* dies with warning on GCC 4.2:
- * snd_pcm_status_alloca(&status);
- */
- status = (snd_pcm_status_t *) alloca(snd_pcm_hw_params_sizeof());
- memset(status, 0, snd_pcm_hw_params_sizeof());
-
- snd_pcm_status(handle, status);
-
- return (u32_t)snd_pcm_status_get_delay(status);
-}
-
-
-static void decode_alsa_gain(s32_t left_gain, s32_t right_gain)
-{
- lgain = left_gain;
- rgain = right_gain;
}
Modified: 7.4/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_output.c
URL:
http://svn.slimdevices.com/7.4/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_output.c?rev=3628&root=Jive&r1=3627&r2=3628&view=diff
==============================================================================
--- 7.4/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_output.c
(original)
+++ 7.4/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_output.c Tue
Dec 23 14:52:26 2008
@@ -54,7 +54,9 @@
void decode_output_begin(void) {
/* call with the decode fifo locked */
- decode_audio->start();
+ if (decode_audio) {
+ decode_audio->start();
+ }
if (output_started) {
return;
@@ -72,7 +74,9 @@
output_started = FALSE;
- decode_audio->stop();
+ if (decode_audio) {
+ decode_audio->stop();
+ }
crossfade_started = FALSE;
transition_gain_step = 0;
@@ -90,7 +94,9 @@
decode_fifo.rptr = decode_fifo.wptr;
/* abort audio playback */
- decode_audio->stop();
+ if (decode_audio) {
+ decode_audio->stop();
+ }
}
}
Modified:
7.4/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_portaudio.c
URL:
http://svn.slimdevices.com/7.4/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_portaudio.c?rev=3628&root=Jive&r1=3627&r2=3628&view=diff
==============================================================================
--- 7.4/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_portaudio.c
(original)
+++ 7.4/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_portaudio.c
Tue Dec 23 14:52:26 2008
@@ -258,7 +258,7 @@
}
-static int decode_portaudio_init(void) {
+static int decode_portaudio_init(lua_State *L) {
PaError err;
int num_devices, i;
const PaDeviceInfo *device_info;
Modified: 7.4/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_priv.h
URL:
http://svn.slimdevices.com/7.4/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_priv.h?rev=3628&root=Jive&r1=3627&r2=3628&view=diff
==============================================================================
--- 7.4/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_priv.h
(original)
+++ 7.4/trunk/squeezeplay/src/squeezeplay/src/audio/decode/decode_priv.h Tue
Dec 23 14:52:26 2008
@@ -86,7 +86,7 @@
/* Audio output api */
struct decode_audio {
- int (*init)(void);
+ int (*init)(lua_State *L);
void (*start)(void);
void (*pause)(void);
void (*resume)(void);
_______________________________________________
Jive-checkins mailing list
[email protected]
http://lists.slimdevices.com/cgi-bin/mailman/listinfo/jive-checkins