summaryrefslogtreecommitdiff
path: root/plugins/pulse
diff options
context:
space:
mode:
authorGravatar Jan D. Behrens <zykure@web.de>2011-03-11 21:51:46 +0100
committerGravatar waker <wakeroid@gmail.com>2011-03-12 14:48:08 +0100
commit1569720abe9c07c40762aa8faf243b04b854dde2 (patch)
tree002a96190553392c9b61d9a2ffcefb188cc0cca2 /plugins/pulse
parent85d90b28c51b24316dec2f4ee10a6b5bd6e4a6ff (diff)
updated pulseaudio plugin to use new API format
Added new functions pulse_set_spec and pulse_setformat, both based on the alsa.c implementation. The plugin now uses the file's samplerate, and should automatically create a channel map suitable for the currently used sound setup. TODO/FIXME: * Plugin doesn't work with bitrates other than S16 * Plugin doesn't support soundcard enumeration (display list of available soundcards)
Diffstat (limited to 'plugins/pulse')
-rw-r--r--plugins/pulse/pulse.c196
1 files changed, 143 insertions, 53 deletions
diff --git a/plugins/pulse/pulse.c b/plugins/pulse/pulse.c
index bbc30d97..1a20b44a 100644
--- a/plugins/pulse/pulse.c
+++ b/plugins/pulse/pulse.c
@@ -51,6 +51,8 @@ static int pulse_terminate;
static pa_simple *s;
static pa_sample_spec ss;
+static pa_channel_map channel_map;
+static ddb_waveformat_t requested_fmt;
static int state;
static uintptr_t mutex;
@@ -60,6 +62,84 @@ static void pulse_thread(void *context);
static void pulse_callback(char *stream, int len);
+static int pulse_init();
+
+static int pulse_free();
+
+static int pulse_setformat(ddb_waveformat_t *fmt);
+
+static int pulse_play();
+
+static int pulse_stop();
+
+static int pulse_pause();
+
+static int pulse_unpause();
+
+static int pulse_set_spec(ddb_waveformat_t *fmt)
+{
+ memcpy (&plugin.fmt, fmt, sizeof (ddb_waveformat_t));
+ if (!plugin.fmt.channels) {
+ // generic format
+ plugin.fmt.bps = 16;
+ plugin.fmt.is_float = 0;
+ plugin.fmt.channels = 2;
+ plugin.fmt.samplerate = 44100;
+ //plugin.fmt.channelmask = 3;
+ }
+
+ trace ("format %dbit %s %dch %dHz channelmask=%X\n", plugin.fmt.bps, plugin.fmt.is_float ? "float" : "int", plugin.fmt.channels, plugin.fmt.samplerate, plugin.fmt.channelmask);
+
+ ss.channels = plugin.fmt.channels;
+ // Try to auto-configure the channel map, see <pulse/channelmap.h> for details
+ pa_channel_map_init_extend(&channel_map, ss.channels, PA_CHANNEL_MAP_DEFAULT);
+ //pa_channel_map_init(&channel_map);
+ trace ("pulse: channels: %d\n", ss.channels);
+
+ // Read samplerate from config
+ //ss.rate = deadbeef->conf_get_int(CONFSTR_PULSE_SAMPLERATE, 44100);
+ ss.rate = plugin.fmt.samplerate;
+ trace ("pulse: samplerate: %d\n", ss.rate);
+
+ switch (plugin.fmt.bps) {
+ case 8:
+ ss.format = PA_SAMPLE_U8;
+ break;
+ case 16:
+#if WORDS_BIGENDIAN
+ ss.format = PA_SAMPLE_S16BE;
+#else
+ ss.format = PA_SAMPLE_S16LE;
+#endif
+ break;
+ case 24:
+#if WORDS_BIGENDIAN
+ ss.format = PA_SAMPLE_S24BE;
+#else
+ ss.format = PA_SAMPLE_S24LE;
+#endif
+ break;
+ case 32:
+ if (plugin.fmt.is_float) {
+#if WORDS_BIGENDIAN
+ ss.format = PA_SAMPLE_FLOAT32BE;
+#else
+ ss.format = PA_SAMPLE_FLOAT32LE;
+#endif
+ }
+ else {
+#if WORDS_BIGENDIAN
+ ss.format = PA_SAMPLE_S32BE;
+#else
+ ss.format = PA_SAMPLE_S32LE;
+#endif
+ }
+ break;
+ };
+
+ return 0;
+}
+
static int pulse_init(void)
{
trace ("pulse_init\n");
@@ -69,18 +149,14 @@ static int pulse_init(void)
// Read serveraddr from config
const char * server = deadbeef->conf_get_str(CONFSTR_PULSE_SERVERADDR, NULL);
+ if (requested_fmt.samplerate != 0) {
+ memcpy (&plugin.fmt, &requested_fmt, sizeof (ddb_waveformat_t));
+ }
+ pulse_set_spec(&plugin.fmt);
+
if (server)
server = strcmp(server, "default") ? server : NULL;
- // Read samplerate from config
- ss.rate = deadbeef->conf_get_int(CONFSTR_PULSE_SAMPLERATE, 44100);
- trace ("pulse: samplerate: %d\n", ss.rate);
-
- // TODO: add config for this
- pa_channel_map * map = NULL;//pa_channel_map_init_stereo(NULL);
- ss.channels = 2;
- ss.format = PA_SAMPLE_S16NE;
-
// TODO: where list of all available devices? add this option to config too..
char * dev = NULL;
@@ -94,10 +170,12 @@ static int pulse_init(void)
buffer_size = deadbeef->conf_get_int(CONFSTR_PULSE_BUFFERSIZE, 4096);
int error;
- s = pa_simple_new(server, "Deadbeef", PA_STREAM_PLAYBACK, dev, "Music", &ss, map, attr, &error);
+ s = pa_simple_new(server, "Deadbeef", PA_STREAM_PLAYBACK, dev, "Music", &ss, &channel_map, attr, &error);
+ //s = pa_simple_new(server, "Deadbeef", PA_STREAM_PLAYBACK, dev, "Music", &ss, NULL, attr, &error);
if (!s)
{
+ trace ("pulse_init failed (%d)\n", error);
return -1;
}
@@ -106,6 +184,44 @@ static int pulse_init(void)
return 0;
}
+static int pulse_setformat (ddb_waveformat_t *fmt)
+{
+ memcpy (&requested_fmt, fmt, sizeof (ddb_waveformat_t));
+ trace ("pulse_setformat %dbit %s %dch %dHz channelmask=%X\n", fmt->bps, fmt->is_float ? "float" : "int", fmt->channels, fmt->samplerate, fmt->channelmask);
+ if (!s) {
+ return -1;
+ }
+ if (!memcmp (fmt, &plugin.fmt, sizeof (ddb_waveformat_t))) {
+ trace ("pulse_setformat ignored\n");
+ return 0;
+ }
+
+ deadbeef->mutex_lock(mutex);
+ int s = state;
+ state = OUTPUT_STATE_STOPPED;
+ // we need to restart pulseaudio for now, since the format is only set upon initialization
+ pulse_free();
+ pulse_init();
+ deadbeef->mutex_unlock(mutex);
+ trace ("new format %dbit %s %dch %dHz channelmask=%X\n", plugin.fmt.bps, plugin.fmt.is_float ? "float" : "int", plugin.fmt.channels, plugin.fmt.samplerate, plugin.fmt.channelmask);
+
+ switch (s) {
+ case OUTPUT_STATE_STOPPED:
+ return pulse_stop ();
+ case OUTPUT_STATE_PLAYING:
+ return pulse_play ();
+ case OUTPUT_STATE_PAUSED:
+ if (0 != pulse_play ()) {
+ return -1;
+ }
+ if (0 != pulse_pause ()) {
+ return -1;
+ }
+ break;
+ }
+ return 0;
+}
+
static int pulse_free(void)
{
trace("pulse_free\n");
@@ -170,41 +286,6 @@ static int pulse_unpause(void)
return 0;
}
-static int pulse_change_rate(int rate)
-{
- pulse_free();
- ss.rate = rate;
-
- if (!pulse_init())
- return -1;
-
- return ss.rate;
-}
-
-static int pulse_get_rate(void)
-{
- return ss.rate;
-}
-
-static int pulse_get_bps(void)
-{
- return 16;
-}
-
-static int pulse_get_channels(void)
-{
- return ss.channels;
-}
-
-static int pulse_get_endianness(void)
-{
-#if WORDS_BIGENDIAN
- return 1;
-#else
- return 0;
-#endif
-}
-
static void pulse_thread(void *context)
{
#ifdef __linux__
@@ -288,26 +369,35 @@ static DB_output_t plugin =
DB_PLUGIN_SET_API_VERSION
.plugin.version_major = 0,
.plugin.version_minor = 1,
- .plugin.nostop = 0,
.plugin.type = DB_PLUGIN_OUTPUT,
.plugin.name = "PulseAudio output plugin",
.plugin.descr = "plays sound via pulse API",
- .plugin.author = "Anton Novikov",
- .plugin.email = "tonn.post@gmail.com",
+ .plugin.copyright =
+ "Copyright (C) 2010-2011 Anton Novikov <tonn.post@gmail.com>\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n",
.plugin.website = "http://deadbeef.sf.net",
.plugin.start = pulse_plugin_start,
.plugin.stop = pulse_plugin_stop,
.plugin.configdialog = settings_dlg,
.init = pulse_init,
.free = pulse_free,
- .change_rate = pulse_change_rate,
+ .setformat = pulse_setformat,
.play = pulse_play,
.stop = pulse_stop,
.pause = pulse_pause,
.unpause = pulse_unpause,
.state = pulse_get_state,
- .samplerate = pulse_get_rate,
- .bitspersample = pulse_get_bps,
- .channels = pulse_get_channels,
- .endianness = pulse_get_endianness,
};