summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am3
-rw-r--r--configure.ac54
-rw-r--r--plugins/notification/notification.c4
-rw-r--r--plugins/oss/Makefile.am6
-rw-r--r--plugins/oss/oss.c330
5 files changed, 391 insertions, 6 deletions
diff --git a/Makefile.am b/Makefile.am
index b5472c65..90b873ba 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -20,7 +20,8 @@ SUBDIRS = gme/Game_Music_Emu-0.5.2\
${VFS_CURL_DIR}\
${CDDA_DIR}\
${GTKUI_DIR}\
- ${FFMPEG_DIR}
+ ${FFMPEG_DIR}\
+ ${OSS_DIR}
dumbpath=@top_srcdir@/dumb
sidpath=@top_srcdir@/sid/sidplay-libs-2.1.0
diff --git a/configure.ac b/configure.ac
index 80ff9970..94e6f780 100644
--- a/configure.ac
+++ b/configure.ac
@@ -35,11 +35,11 @@ esac
test "x$prefix" = xNONE && prefix=$ac_default_prefix
-INSANE_CFLAGS="-Wcomment -Wchar-subscripts -Wunused-function -Wunused-value -Wuninitialized -Wtype-limits -Wbad-function-cast"
-INSANE_CXXFLAGS="-Wcomment -Wchar-subscripts -Wunused-function -Wunused-value -Wuninitialized -Wtype-limits"
+dnl INSANE_CFLAGS="-Wcomment -Wchar-subscripts -Wunused-function -Wunused-value -Wuninitialized -Wtype-limits -Wbad-function-cast"
+dnl INSANE_CXXFLAGS="-Wcomment -Wchar-subscripts -Wunused-function -Wunused-value -Wuninitialized -Wtype-limits"
CXXFLAGS="$CXXFLAGS $INSANE_CXXFLAGS -D_GNU_SOURCE -DLIBDIR=\\\"$libdir\\\" -DPREFIX=\\\"$prefix\\\" -DDOCDIR=\\\"$docdir\\\""
-CFLAGS="$CFLAGS $INSANE_CFLAGS -D_GNU_SOURCE -DLIBDIR=\\\"$libdir\\\" -DPREFIX=\\\"$prefix\\\" -DDOCDIR=\\\"$docdir\\\""
+CFLAGS="$CFLAGS $INSANE_CFLAGS -D_GNU_SOURCE -DLIBDIR=\\\"$libdir\\\" -DPREFIX=\\\"$prefix\\\" -DDOCDIR=\\\"$docdir\\\" -std=c99"
PKG_CHECK_MODULES(DEPS, samplerate)
PKG_CHECK_MODULES(GTKUI_DEPS, gtk+-2.0 >= 2.12 gthread-2.0 glib-2.0, HAVE_GTK=1, NO_GTK=1)
@@ -176,6 +176,52 @@ if test ${HAVE_FFMPEG}; then
AC_SUBST(FFMPEG_DIR)
fi
+dnl *** OSS output (partly stolen from audacious)
+have_oss=no
+
+AC_MSG_CHECKING(for OSS include dir)
+OSS_CFLAGS=""
+if test -f "/etc/oss.conf" ; then
+ for i in `cat /etc/oss.conf`; do
+ t=`echo $i | sed -e 's/OSSLIBDIR=//'`
+ if test "x$i" != "x$t" ; then
+ if test -f "$t/include/sys/soundcard.h" -o -f "$i/include/soundcard.h" ; then
+ OSS_CFLAGS="-I$t/include/sys"
+ AC_MSG_RESULT([$OSS_CFLAGS])
+ have_oss=yes
+ fi
+ fi
+ done
+else
+ AC_MSG_RESULT([not found])
+fi
+
+if test "x$have_oss" != "xyes"; then
+ AC_MSG_CHECKING(for sys/soundcard.h)
+ AC_CHECK_HEADERS(sys/soundcard.h)
+ if test "x${ac_cv_header_sys_soundcard_h}" = "xyes" ; then
+ have_oss=yes
+ AC_MSG_RESULT([found])
+ else
+ AC_MSG_RESULT([not found])
+ fi
+fi
+
+
+if test "x$have_oss" = "xyes"; then
+ OSS_DIR="plugins/oss"
+ AC_SUBST(OSS_CFLAGS)
+ AC_SUBST(OSS_DIR)
+fi
+
+dnl echo
+dnl echo "have_oss=$have_oss"
+dnl echo "OSS_CFLAGS=$OSS_CFLAGS"
+dnl echo "OSS_LIBS=$OSS_LIBS"
+dnl echo "OSS_DIR=$OSS_DIR"
+dnl echo
+
+
dnl print summary
echo
echo "plugin summary:"
@@ -212,6 +258,7 @@ PRINT_PLUGIN_INFO([cdda],[cd audio player],[test $HAVE_CDIO && test $HAVE_CDDB])
PRINT_PLUGIN_INFO([gtkui],[GTK user interface],[test $HAVE_GTK])
PRINT_PLUGIN_INFO([ffmpeg],[ffmpeg codecs],[test $HAVE_FFMPEG])
PRINT_PLUGIN_INFO([notification],[Current track notification],[true])
+PRINT_PLUGIN_INFO([oss],[oss output plugin],[test "x$have_oss" = "xyes"])
echo
AC_OUTPUT([
@@ -239,6 +286,7 @@ plugins/vtx/Makefile
plugins/adplug/Makefile
plugins/ffmpeg/Makefile
plugins/notification/Makefile
+plugins/oss/Makefile
deadbeef.desktop
])
diff --git a/plugins/notification/notification.c b/plugins/notification/notification.c
index 608b01b8..8a1891fe 100644
--- a/plugins/notification/notification.c
+++ b/plugins/notification/notification.c
@@ -17,7 +17,6 @@ show_notification (DB_playItem_t *track)
{
char cmd [1024];
deadbeef->pl_format_title (track, cmd, sizeof (cmd), -1, deadbeef->conf_get_str ("notification.command", DEFAULT_COMMAND));
- printf ("Invoking:\n%s\n", cmd);
system (cmd);
}
@@ -31,12 +30,13 @@ songchanged (DB_event_trackchange_t *ev, uintptr_t data) {
static int
notification_stop (void) {
deadbeef->ev_unsubscribe (DB_PLUGIN (&plugin), DB_EV_SONGCHANGED, DB_CALLBACK (songchanged), 0);
+ return 0;
}
static int
notification_start (void) {
deadbeef->ev_subscribe (DB_PLUGIN (&plugin), DB_EV_SONGCHANGED, DB_CALLBACK (songchanged), 0);
- return 1;
+ return 0;
}
DB_plugin_t *
diff --git a/plugins/oss/Makefile.am b/plugins/oss/Makefile.am
new file mode 100644
index 00000000..697f4d32
--- /dev/null
+++ b/plugins/oss/Makefile.am
@@ -0,0 +1,6 @@
+ossdir = $(libdir)/$(PACKAGE)
+pkglib_LTLIBRARIES = oss.la
+AM_CFLAGS = $(CFLAGS) $(OSS_CFLAGS)
+oss_la_SOURCES = oss.c
+oss_la_LDFLAGS = -module
+
diff --git a/plugins/oss/oss.c b/plugins/oss/oss.c
new file mode 100644
index 00000000..b8602cf7
--- /dev/null
+++ b/plugins/oss/oss.c
@@ -0,0 +1,330 @@
+/*
+ DeaDBeeF - ultimate music player for GNU/Linux systems with X11
+ Copyright (C) 2009-2010 Alexey Yakovenko <waker@users.sourceforge.net>
+
+ 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, see <http://www.gnu.org/licenses/>.
+*/
+#ifdef HAVE_CONFIG_H
+# include "../../config.h"
+#endif
+#include <stdint.h>
+#include <unistd.h>
+#ifdef __linux__
+#include <sys/prctl.h>
+#endif
+#include <stdio.h>
+#include <string.h>
+#if HAVE_SYS_SOUNDCARD_H
+#include <sys/soundcard.h>
+#else
+#include <soundcard.h>
+#endif
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <stdlib.h>
+#include "../../deadbeef.h"
+
+#define trace(...) { fprintf(stderr, __VA_ARGS__); }
+//#define trace(fmt,...)
+
+static DB_output_t plugin;
+DB_functions_t *deadbeef;
+
+static intptr_t oss_tid;
+static int oss_terminate;
+static int oss_rate = 44100;
+static int state;
+static int fd;
+static uintptr_t mutex;
+static int blksize;
+
+static void
+oss_thread (void *context);
+
+static void
+oss_callback (char *stream, int len);
+
+static int
+oss_init (void) {
+ trace ("oss_init\n");
+ state = OUTPUT_STATE_STOPPED;
+ oss_terminate = 0;
+ mutex = 0;
+
+ // prepare oss for playback
+ const char *name = "/dev/dsp";
+ fd = open (name, O_WRONLY);
+ if (fd == -1) {
+ trace ("oss: failed to open file\n");
+ perror (name);
+ plugin.free ();
+ return -1;
+ }
+
+#if OSS_VERSION>=0x040000
+/*
+ int cooked = 1;
+ ioctl (fd, SNDCTL_DSP_COOKEDMODE, &cooked);
+ trace ("oss: cooked_mode=%d\n", cooked);
+
+ int policy = 3;
+ ioctl (fd, SNDCTL_DSP_POLICY, &policy);
+ trace ("oss: policy=%d\n", policy);
+*/
+#endif
+
+ int fmt = AFMT_S16_NE;
+ if (ioctl (fd, SNDCTL_DSP_SETFMT, &fmt) == -1) {
+ trace ("oss: failed to set format\n");
+ perror ("SNDCTL_DSP_SETFMT");
+ plugin.free ();
+ return -1;
+ }
+
+ if (fmt != AFMT_S16_NE) {
+ fprintf (stderr, "oss: device doesn't support 16 bit sample format\n");
+ plugin.free ();
+ return -1;
+ }
+
+ int channels = 2;
+ if (ioctl (fd, SNDCTL_DSP_CHANNELS, &channels) == -1) {
+ trace ("oss: failed to set channels\n");
+ perror ("SNDCTL_DSP_CHANNELS");
+ plugin.free ();
+ return -1;
+ }
+ if (channels != 2) {
+ trace ("oss: device doesn't support stereo output\n");
+ plugin.free ();
+ return -1;
+ }
+
+ if (ioctl (fd, SNDCTL_DSP_SPEED, &oss_rate) == -1) {
+ trace ("oss: failed to set samplerate\n");
+ perror ("SNDCTL_DSP_CHANNELS");
+ plugin.free ();
+ return -1;
+ }
+
+ trace ("oss: samplerate: %d\n", oss_rate);
+
+// audio_buf_info bi;
+// ioctl (fd, SNDCTL_DSP_GETOSPACE, &bi);
+// trace ("oss: bi.bytes=%d, bi.fragsize=%d, bi.fragstotal=%d\n", bi.bytes, bi.fragsize, bi.fragstotal);
+// blksize = bi.fragsize;
+
+ ioctl (fd, SNDCTL_DSP_GETBLKSIZE, &blksize);
+ trace ("oss: blksize: %d\n", blksize);
+
+ mutex = deadbeef->mutex_create ();
+
+ oss_tid = deadbeef->thread_start (oss_thread, NULL);
+ return 0;
+}
+
+static int
+oss_change_rate (int rate) {
+ if (!fd) {
+ oss_rate = rate;
+ return oss_rate;
+ }
+ if (rate == oss_rate) {
+ trace ("oss_change_rate: same rate (%d), ignored\n", rate);
+ return rate;
+ }
+ deadbeef->mutex_lock (mutex);
+ if (ioctl (fd, SNDCTL_DSP_SPEED, &rate) == -1) {
+ trace ("oss: can't switch to %d samplerate\n", rate);
+ perror ("SNDCTL_DSP_CHANNELS");
+ plugin.free ();
+ return -1;
+ }
+ oss_rate = rate;
+ deadbeef->mutex_unlock (mutex);
+ return oss_rate;
+}
+
+static int
+oss_free (void) {
+ trace ("oss_free\n");
+ if (!oss_terminate) {
+ if (oss_tid) {
+ oss_terminate = 1;
+ deadbeef->thread_join (oss_tid);
+ }
+ oss_tid = 0;
+ state = OUTPUT_STATE_STOPPED;
+ oss_terminate = 0;
+ if (fd) {
+ close (fd);
+ }
+ if (mutex) {
+ deadbeef->mutex_free (mutex);
+ mutex = 0;
+ }
+ }
+ return 0;
+}
+
+static int
+oss_play (void) {
+ if (!oss_tid) {
+ oss_init ();
+ }
+ state = OUTPUT_STATE_PLAYING;
+ return 0;
+}
+
+static int
+oss_stop (void) {
+ state = OUTPUT_STATE_STOPPED;
+ deadbeef->streamer_reset (1);
+ return 0;
+}
+
+static int
+oss_pause (void) {
+ if (state == OUTPUT_STATE_STOPPED) {
+ return -1;
+ }
+ // set pause state
+ state = OUTPUT_STATE_PAUSED;
+ return 0;
+}
+
+static int
+oss_unpause (void) {
+ // unset pause state
+ if (state == OUTPUT_STATE_PAUSED) {
+ state = OUTPUT_STATE_PLAYING;
+ }
+ return 0;
+}
+
+static int
+oss_get_rate (void) {
+ return oss_rate;
+}
+
+static int
+oss_get_bps (void) {
+ return 16;
+}
+
+static int
+oss_get_channels (void) {
+ return 2;
+}
+
+static int
+oss_get_endianness (void) {
+#if WORDS_BIGENDIAN
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+static void
+oss_thread (void *context) {
+#ifdef __linux__
+ prctl (PR_SET_NAME, "deadbeef-oss", 0, 0, 0, 0);
+#endif
+ for (;;) {
+ if (oss_terminate) {
+ break;
+ }
+ if (state != OUTPUT_STATE_PLAYING) {
+ usleep (10000);
+ continue;
+ }
+
+ char buf[blksize];
+ oss_callback (buf, sizeof (buf));
+ deadbeef->mutex_lock (mutex);
+ int res = write (fd, buf, sizeof (buf));
+ deadbeef->mutex_unlock (mutex);
+ if (res != sizeof (buf)) {
+ fprintf (stderr, "oss: failed to write buffer\n");
+ }
+ usleep (1000); // this must be here to prevent mutex deadlock
+ }
+}
+
+static void
+oss_callback (char *stream, int len) {
+ if (!deadbeef->streamer_ok_to_read (len)) {
+ memset (stream, 0, len);
+ return;
+ }
+ int bytesread = deadbeef->streamer_read (stream, len);
+ int16_t ivolume = deadbeef->volume_get_amp () * 1000;
+ for (int i = 0; i < bytesread/2; i++) {
+ ((int16_t*)stream)[i] = (int16_t)(((int32_t)(((int16_t*)stream)[i])) * ivolume / 1000);
+ }
+
+ if (bytesread < len) {
+ memset (stream + bytesread, 0, len-bytesread);
+ }
+}
+
+static int
+oss_get_state (void) {
+ return state;
+}
+
+static int
+oss_plugin_start (void) {
+ return 0;
+}
+
+static int
+oss_plugin_stop (void) {
+ return 0;
+}
+
+DB_plugin_t *
+oss_load (DB_functions_t *api) {
+ deadbeef = api;
+ return DB_PLUGIN (&plugin);
+}
+
+// define plugin interface
+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 = "OSS output plugin",
+ .plugin.descr = "plays sound via OSS API",
+ .plugin.author = "Alexey Yakovenko",
+ .plugin.email = "waker@users.sourceforge.net",
+ .plugin.website = "http://deadbeef.sf.net",
+ .plugin.start = oss_plugin_start,
+ .plugin.stop = oss_plugin_stop,
+ .init = oss_init,
+ .free = oss_free,
+ .change_rate = oss_change_rate,
+ .play = oss_play,
+ .stop = oss_stop,
+ .pause = oss_pause,
+ .unpause = oss_unpause,
+ .state = oss_get_state,
+ .samplerate = oss_get_rate,
+ .bitspersample = oss_get_bps,
+ .channels = oss_get_channels,
+ .endianness = oss_get_endianness,
+};