summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2008-10-09 18:15:23 +0200
committerLennart Poettering <lennart@poettering.net>2008-10-09 18:15:23 +0200
commit181e9c6d5d11cb1e5d36a2777eeb233ad8ed00e5 (patch)
tree7c280968ce3fded5b325b1480d7f2440ddf93207
parent30a4b516c8d591c11f05df38531f46452d930d2b (diff)
big pile of updates to match more what happened with libcanberra
-rw-r--r--.gitignore6
-rw-r--r--configure.ac214
-rw-r--r--src/.gitignore4
-rw-r--r--src/Makefile.am280
-rw-r--r--src/add.c32
-rw-r--r--src/add.h20
l---------src/alsa.c1
-rw-r--r--src/bbuffer.c20
-rw-r--r--src/bbuffer.h20
-rw-r--r--src/bswap.c44
-rw-r--r--src/bswap.h20
-rw-r--r--src/bufferq.c46
-rw-r--r--src/bufferq.h20
-rw-r--r--src/common.c1406
-rw-r--r--src/common.h80
-rw-r--r--src/continued-fraction.h20
-rw-r--r--src/converter.c46
-rw-r--r--src/converter.h26
-rw-r--r--src/driver-order.c42
-rw-r--r--src/driver-order.h26
-rw-r--r--src/driver.h62
-rw-r--r--src/dso.c565
-rw-r--r--src/format.c161
-rw-r--r--src/format.h20
-rw-r--r--src/interleave.c26
-rw-r--r--src/interleave.h20
l---------src/jack.c1
-rw-r--r--src/llist.h20
-rw-r--r--src/macro.c34
-rw-r--r--src/macro.h245
-rw-r--r--src/malloc.c159
-rw-r--r--src/malloc.h34
-rw-r--r--src/map-file24
-rw-r--r--src/mutex-posix.c20
-rw-r--r--src/mutex.h20
-rw-r--r--src/null.c111
-rw-r--r--src/oss.c403
-rw-r--r--src/proplist.c413
-rw-r--r--src/proplist.h56
l---------src/pulse.c1
-rw-r--r--src/resample.c32
-rw-r--r--src/resample.h23
-rw-r--r--src/sydney.h541
-rw-r--r--src/test-bufferq.c26
-rw-r--r--src/test-pull.c54
-rw-r--r--src/test-sine.c51
-rw-r--r--src/thread-posix.c27
-rw-r--r--src/thread.h20
-rw-r--r--src/volscale.c34
-rw-r--r--src/volscale.h20
-rw-r--r--src/zero.c71
-rw-r--r--src/zero.h20
52 files changed, 4476 insertions, 1211 deletions
diff --git a/.gitignore b/.gitignore
index 37396d1..ce35ee3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,3 +21,9 @@ config.status
configure
config.rpath
depcomp
+*.o
+*~
+.deps/
+.libs/
+*.la
+*.lo
diff --git a/configure.ac b/configure.ac
index 4d4ee07..dc4d0dd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -82,6 +82,8 @@ esac
AM_CONDITIONAL(OS_IS_WIN32, test "x$os_is_win32" = "x1")
+AM_CONDITIONAL(USE_VERSION_SCRIPT, test "x$supports_anon_versioning" = "xyes" )
+
###################################
# Basic environment checks #
###################################
@@ -228,7 +230,7 @@ AC_ARG_ENABLE([alsa],
[alsa=auto])
if test "x${alsa}" != xno ; then
- PKG_CHECK_MODULES(ASOUNDLIB, [ alsa >= 1.0.0 ],
+ PKG_CHECK_MODULES(ALSA, [ alsa >= 1.0.0 ],
[
HAVE_ALSA=1
AC_DEFINE([HAVE_ALSA], 1, [Have ALSA?])
@@ -243,10 +245,8 @@ else
HAVE_ALSA=0
fi
-AC_SUBST(ASOUNDLIB_CFLAGS)
-AC_SUBST(ASOUNDLIB_LIBS)
-AC_SUBST(HAVE_ALSA)
-AM_CONDITIONAL([HAVE_ALSA], [test "x$HAVE_ALSA" = x1])
+AC_SUBST(ALSA_CFLAGS)
+AC_SUBST(ALSA_LIBS)
### PulseAudio (optional) ####
@@ -317,18 +317,154 @@ fi
AC_SUBST(JACK_CFLAGS)
AC_SUBST(JACK_LIBS)
-AC_SUBST(HAVE_JACK)
-AM_CONDITIONAL([HAVE_JACK], [test "x$HAVE_JACK" = x1])
-### LIBOIL ####
+### Null output (optional) ####
+
+AC_ARG_ENABLE([null],
+ AC_HELP_STRING([--disable-null], [Disable optional null output]),
+ [
+ case "${enableval}" in
+ yes) null=yes ;;
+ no) null=no ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --disable-null) ;;
+ esac
+ ],
+ [null=yes])
+
+if test "x${null}" != xno ; then
+ HAVE_NULL=1
+ AC_DEFINE([HAVE_NULL], 1, [Have NULL output?])
+else
+ HAVE_NULL=0
+fi
+
+### liboil (mandatory) ####
PKG_CHECK_MODULES(LIBOIL, [ liboil-0.3 >= 0.3.0 ])
AC_SUBST(LIBOIL_CFLAGS)
AC_SUBST(LIBOIL_LIBS)
-PKG_CHECK_MODULES(LIBSPEEX, [ speexdsp >= 1.2 ])
-AC_SUBST(LIBSPEEX_CFLAGS)
-AC_SUBST(LIBSPEEX_LIBS)
+### libspeex (mandatory) ####
+
+PKG_CHECK_MODULES(SPEEX, [ speexdsp >= 1.2 ])
+AC_SUBST(SPEEX_CFLAGS)
+AC_SUBST(SPEEX_LIBS)
+
+### Chose builtin driver ###
+
+AC_ARG_WITH([builtin],
+ [AS_HELP_STRING([--with-builtin], [Choose builtin driver])],
+ [],
+ [with_builtin=dso])
+
+HAVE_DSO=0
+BUILTIN_DSO=0
+BUILTIN_PULSE=0
+BUILTIN_ALSA=0
+BUILTIN_OSS=0
+BUILTIN_JACK=0
+BUILTIN_NULL=0
+
+case "x$with_builtin" in
+ xpulse)
+ if test "x$HAVE_PULSE" != x1 ; then
+ AC_MSG_ERROR([*** PulseAudio selected for builtin driver, but not enabled. ***])
+ fi
+
+ BUILTIN_PULSE=1
+ HAVE_ALSA=0
+ HAVE_OSS=0
+ HAVE_JACK=0
+ HAVE_NULL=0
+ ;;
+
+ xalsa)
+ if test "x$HAVE_ALSA" != x1 ; then
+ AC_MSG_ERROR([*** ALSA selected for builtin driver, but not enabled. ***])
+ fi
+
+ BUILTIN_ALSA=1
+ HAVE_OSS=0
+ HAVE_PULSE=0
+ HAVE_JACK=0
+ HAVE_NULL=0
+ ;;
+
+ xoss)
+ if test "x$HAVE_OSS" != x1 ; then
+ AC_MSG_ERROR([*** OSS selected for builtin driver, but not enabled. ***])
+ fi
+
+ BUILTIN_OSS=1
+ HAVE_ALSA=0
+ HAVE_PULSE=0
+ HAVE_JACK=0
+ HAVE_NULL=0
+ ;;
+
+ xjack)
+ if test "x$HAVE_JACK" != x1 ; then
+ AC_MSG_ERROR([*** JACK selected for builtin driver, but not enabled. ***])
+ fi
+
+ BUILTIN_JACK=1
+ HAVE_ALSA=0
+ HAVE_PULSE=0
+ HAVE_JACK=0
+ HAVE_NULL=0
+ ;;
+
+ xnull)
+ if test "x$HAVE_NULL" != x1 ; then
+ AC_MSG_ERROR([*** Null output selected for builtin driver, but not enabled. ***])
+ fi
+
+ BUILTIN_NULL=1
+ HAVE_PULSE=0
+ HAVE_ALSA=0
+ HAVE_OSS=0
+ HAVE_JACK=0
+ ;;
+
+ xdso)
+ BUILTIN_DSO=1
+ HAVE_DSO=1
+ AC_DEFINE([HAVE_DSO], 1, [Have DSO?])
+ ;;
+
+ *)
+ AC_MSG_ERROR([*** Unknown driver $with_builtin selected for builtin ***])
+esac
+
+if test "x$HAVE_PULSE" != x1 -a "x$HAVE_ALSA" != x1 -a "x$HAVE_OSS" != x1 -a "x$HAVE_JACK" != x1 -a "x$HAVE_NULL" != x1 ; then
+ AC_MSG_ERROR([*** No backend enabled. ***])
+fi
+
+AC_SUBST(HAVE_DSO)
+AC_SUBST(HAVE_PULSE)
+AC_SUBST(HAVE_ALSA)
+AC_SUBST(HAVE_OSS)
+AC_SUBST(HAVE_JACK)
+AC_SUBST(HAVE_NULL)
+AC_SUBST(BUILTIN_DSO)
+AC_SUBST(BUILTIN_PULSE)
+AC_SUBST(BUILTIN_ALSA)
+AC_SUBST(BUILTIN_OSS)
+AC_SUBST(BUILTIN_JACK)
+AC_SUBST(BUILTIN_NULL)
+AM_CONDITIONAL([HAVE_PULSE], [test "x$HAVE_PULSE" = x1])
+AM_CONDITIONAL([HAVE_ALSA], [test "x$HAVE_ALSA" = x1])
+AM_CONDITIONAL([HAVE_OSS], [test "x$HAVE_OSS" = x1])
+AM_CONDITIONAL([HAVE_JACK], [test "x$HAVE_JACK" = x1])
+AM_CONDITIONAL([HAVE_NULL], [test "x$HAVE_NULL" = x1])
+AM_CONDITIONAL([BUILTIN_DSO], [test "x$BUILTIN_DSO" = x1])
+AM_CONDITIONAL([BUILTIN_PULSE], [test "x$BUILTIN_PULSE" = x1])
+AM_CONDITIONAL([BUILTIN_ALSA], [test "x$BUILTIN_ALSA" = x1])
+AM_CONDITIONAL([BUILTIN_OSS], [test "x$BUILTIN_OSS" = x1])
+AM_CONDITIONAL([BUILTIN_JACK], [test "x$BUILTIN_JACK" = x1])
+AM_CONDITIONAL([BUILTIN_NULL], [test "x$BUILTIN_NULL" = x1])
+
+GTK_DOC_CHECK(1.9)
###################################
# Output #
@@ -342,30 +478,55 @@ libsydney.pc
AC_OUTPUT
# ==========================================================================
-ENABLE_OSS=no
-if test "x$HAVE_OSS" = "x1" ; then
- ENABLE_OSS=yes
+ENABLE_BUILTIN_DSO=no
+if test "x$BUILTIN_DSO" = "x1" ; then
+ ENABLE_BUILTIN_DSO=yes
+fi
+
+ENABLE_PULSE=no
+if test "x$HAVE_PULSE" = "x1" ; then
+ ENABLE_PULSE=yes
+fi
+ENABLE_BUILTIN_PULSE=no
+if test "x$BUILTIN_PULSE" = "x1" ; then
+ ENABLE_BUILTIN_PULSE=yes
fi
ENABLE_ALSA=no
if test "x$HAVE_ALSA" = "x1" ; then
ENABLE_ALSA=yes
fi
-
-ENABLE_PULSE=no
-if test "x$HAVE_PULSE" = "x1" ; then
- ENABLE_PULSE=yes
+ENABLE_BUILTIN_ALSA=no
+if test "x$BUILTIN_ALSA" = "x1" ; then
+ ENABLE_BUILTIN_ALSA=yes
fi
-ENABLE_SOLARIS=no
-if test "x$HAVE_SOLARIS" = "x1" ; then
- ENABLE_SOLARIS=yes
+ENABLE_OSS=no
+if test "x$HAVE_OSS" = "x1" ; then
+ ENABLE_OSS=yes
+fi
+ENABLE_BUILTIN_OSS=no
+if test "x$BUILTIN_OSS" = "x1" ; then
+ ENABLE_BUILTIN_OSS=yes
fi
ENABLE_JACK=no
if test "x$HAVE_JACK" = "x1" ; then
ENABLE_JACK=yes
fi
+ENABLE_BUILTIN_JACK=no
+if test "x$BUILTIN_JACK" = "x1" ; then
+ ENABLE_BUILTIN_JACK=yes
+fi
+
+ENABLE_NULL=no
+if test "x$HAVE_NULL" = "x1" ; then
+ ENABLE_NULL=yes
+fi
+ENABLE_BUILTIN_NULL=no
+if test "x$BUILTIN_NULL" = "x1" ; then
+ ENABLE_BUILTIN_NULL=yes
+fi
echo "
---{ $PACKAGE_NAME $VERSION }---
@@ -377,8 +538,15 @@ echo "
CFLAGS: ${CFLAGS}
C++-Compiler: ${CXX}
CXXFLAGS: ${CXXFLAGS}
- Enable OSS: ${ENABLE_OSS}
- Enable Alsa: ${ENABLE_ALSA}
+ Builtin DSO: ${ENABLE_BUILTIN_DSO}
Enable PulseAudio: ${ENABLE_PULSE}
+ Builtin PulseAudio: ${ENABLE_BUILTIN_PULSE}
+ Enable ALSA: ${ENABLE_ALSA}
+ Builtin ALSA: ${ENABLE_BUILTIN_ALSA}
+ Enable OSS: ${ENABLE_OSS}
+ Builtin OSS: ${ENABLE_BUILTIN_OSS}
Enable Jack: ${ENABLE_JACK}
+ Builtin Jack: ${ENABLE_BUILTIN_JACK}
+ Enable Null Output: ${ENABLE_NULL}
+ Builtin Null Output: ${ENABLE_BUILTIN_NULL}
"
diff --git a/src/.gitignore b/src/.gitignore
new file mode 100644
index 0000000..781b4c8
--- /dev/null
+++ b/src/.gitignore
@@ -0,0 +1,4 @@
+test-bufferq
+test-llist
+test-pull
+test-sine
diff --git a/src/Makefile.am b/src/Makefile.am
index 522b4f4..9a6107e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -16,9 +16,10 @@
# License along with libsydney. If not, see
# <http://www.gnu.org/licenses/>.
-AM_CFLAGS = $(PTHREAD_CFLAGS)
+plugindir = $(libdir)/libsydney-@PACKAGE_VERSION@
+
+AM_CFLAGS = $(PTHREAD_CFLAGS) -DSA_PLUGIN_PATH=\"$(plugindir)\"
AM_CXXFLAGS = $(PTHREAD_CFLAGS)
-AM_LIBADD = $(PTHREAD_LIBS)
AM_LDADD = $(PTHREAD_LIBS)
EXTRA_DIST = \
@@ -35,13 +36,13 @@ noinst_PROGRAMS = \
test-llist \
test-sine \
test-pull
-# test-asyncq
libsydney_la_SOURCES = \
sydney.h \
common.c common.h \
malloc.c malloc.h \
- oss.c oss.h \
+ macro.c macro.h \
+ llist.h \
bbuffer.c bbuffer.h \
format.c fomat.h \
volscale.c volscale.h \
@@ -55,16 +56,269 @@ libsydney_la_SOURCES = \
g711.c g711.h \
mutex-posix.c mutex.h \
thread-posix.c thread.h \
- bufferq.c buffer.h
-# asyncq.c asyncq.h
+ bufferq.c buffer.h \
+ proplist.c proplist.h \
+ driver.h
+libsydney_la_CFLAGS = \
+ $(AM_CFLAGS) \
+ $(LIBOIL_CFLAGS) \
+ $(SPEEX_CFLAGS)
libsydney_la_LIBADD = \
$(AM_LIBADD) \
$(LIBOIL_LIBS) \
$(SPEEX_LIBS)
-libsydney_la_CXXFLAGS = \
- $(AM_CXXFLAGS) \
- $(LIBOIL_CFLAGS) \
- $(SPEEX_CFLAGS)
+libsydney_la_LDFLAGS = \
+ -export-dynamic \
+ -version-info $(LIBSYDNEY_VERSION_INFO)
+
+if USE_VERSION_SCRIPT
+libsydney_la_LDFLAGS += -Wl,-version-script=$(srcdir)/map-file
+endif
+
+plugin_LTLIBRARIES =
+
+if BUILTIN_DSO
+
+libsydney_la_SOURCES += \
+ dso.c \
+ driver-order.c driver-order.h
+libsydney_la_CFLAGS += \
+ $(LTDLINCL)
+libsydney_la_LIBADD += \
+ $(LIBLTDL)
+
+endif
+
+if HAVE_ALSA
+if BUILTIN_ALSA
+
+libsydney_la_SOURCES += \
+ alsa.c
+libsydney_la_CFLAGS += \
+ $(ALSA_CFLAGS)
+libsydney_la_LIBADD += \
+ $(ALSA_LIBS)
+
+else
+
+plugin_LTLIBRARIES += \
+ libsydney-alsa.la
+
+libsydney_alsa_la_SOURCES = \
+ alsa.c
+libsydney_alsa_la_CFLAGS = \
+ $(ALSA_CFLAGS) \
+ -Ddriver_open=alsa_driver_open \
+ -Ddriver_destroy=alsa_driver_destroy \
+ -Ddriver_change_write_latency=alsa_driver_change_write_latency \
+ -Ddriver_change_read_latency=alsa_driver_change_read_latency \
+ -Ddriver_change_device=alsa_driver_change_device \
+ -Ddriver_change_read_volume=alsa_driver_change_read_volume \
+ -Ddriver_change_write_volume=alsa_driver_change_write_volume \
+ -Ddriver_change_pcm_rate=alsa_driver_change_pcm_rate \
+ -Ddriver_change_props=alsa_driver_change_props \
+ -Ddriver_get_state=alsa_driver_get_state \
+ -Ddriver_get_position=alsa_driver_get_position \
+ -Ddriver_wait=alsa_driver_wait \
+ -Ddriver_read=alsa_driver_read \
+ -Ddriver_read_ni=alsa_driver_read_ni \
+ -Ddriver_pwrite=alsa_driver_pwrite \
+ -Ddriver_pwrite_ni=alsa_driver_pwrite_ni \
+ -Ddriver_get_read_size=alsa_driver_get_read_size \
+ -Ddriver_get_write_size=alsa_driver_get_write_size \
+ -Ddriver_resume=alsa_driver_resume \
+ -Ddriver_pause=alsa_driver_pause \
+ -Ddriver_drain=alsa_driver_drain
+libsydney_alsa_la_LIBADD = \
+ $(ALSA_LIBS) \
+ libsydney.la
+libsydney_alsa_la_LDFLAGS = \
+ -avoid-version -module -export-dynamic
+
+endif
+endif
+
+if HAVE_OSS
+if BUILTIN_OSS
+
+libsydney_la_SOURCES += \
+ oss.c
+
+else
+
+plugin_LTLIBRARIES += \
+ libsydney-oss.la
+
+libsydney_oss_la_SOURCES = \
+ oss.c
+libsydney_oss_la_CFLAGS = \
+ -Ddriver_open=oss_driver_open \
+ -Ddriver_destroy=oss_driver_destroy \
+ -Ddriver_change_write_latency=oss_driver_change_write_latency \
+ -Ddriver_change_read_latency=oss_driver_change_read_latency \
+ -Ddriver_change_device=oss_driver_change_device \
+ -Ddriver_change_read_volume=oss_driver_change_read_volume \
+ -Ddriver_change_write_volume=oss_driver_change_write_volume \
+ -Ddriver_change_pcm_rate=oss_driver_change_pcm_rate \
+ -Ddriver_change_props=oss_driver_change_props \
+ -Ddriver_get_state=oss_driver_get_state \
+ -Ddriver_get_position=oss_driver_get_position \
+ -Ddriver_wait=oss_driver_wait \
+ -Ddriver_read=oss_driver_read \
+ -Ddriver_read_ni=oss_driver_read_ni \
+ -Ddriver_pwrite=oss_driver_pwrite \
+ -Ddriver_pwrite_ni=oss_driver_pwrite_ni \
+ -Ddriver_get_read_size=oss_driver_get_read_size \
+ -Ddriver_get_write_size=oss_driver_get_write_size \
+ -Ddriver_resume=oss_driver_resume \
+ -Ddriver_pause=oss_driver_pause \
+ -Ddriver_drain=oss_driver_drain
+libsydney_oss_la_LIBADD = \
+ libsydney.la
+libsydney_oss_la_LDFLAGS = \
+ -avoid-version -module -export-dynamic
+endif
+endif
+
+if HAVE_PULSE
+if BUILTIN_PULSE
+
+libsydney_la_SOURCES += \
+ pulse.c
+libsydney_la_CFLAGS += \
+ $(PULSE_CFLAGS)
+libsydney_la_LIBADD += \
+ $(PULSE_LIBS)
+
+else
+
+plugin_LTLIBRARIES += \
+ libsydney-pulse.la
+
+libsydney_pulse_la_SOURCES = \
+ pulse.c
+libsydney_pulse_la_CFLAGS = \
+ $(PULSE_CFLAGS) \
+ -Ddriver_open=pulse_driver_open \
+ -Ddriver_destroy=pulse_driver_destroy \
+ -Ddriver_change_write_latency=pulse_driver_change_write_latency \
+ -Ddriver_change_read_latency=pulse_driver_change_read_latency \
+ -Ddriver_change_device=pulse_driver_change_device \
+ -Ddriver_change_read_volume=pulse_driver_change_read_volume \
+ -Ddriver_change_write_volume=pulse_driver_change_write_volume \
+ -Ddriver_change_pcm_rate=pulse_driver_change_pcm_rate \
+ -Ddriver_change_props=pulse_driver_change_props \
+ -Ddriver_get_state=pulse_driver_get_state \
+ -Ddriver_get_position=pulse_driver_get_position \
+ -Ddriver_wait=pulse_driver_wait \
+ -Ddriver_read=pulse_driver_read \
+ -Ddriver_read_ni=pulse_driver_read_ni \
+ -Ddriver_pwrite=pulse_driver_pwrite \
+ -Ddriver_pwrite_ni=pulse_driver_pwrite_ni \
+ -Ddriver_get_read_size=pulse_driver_get_read_size \
+ -Ddriver_get_write_size=pulse_driver_get_write_size \
+ -Ddriver_resume=pulse_driver_resume \
+ -Ddriver_pause=pulse_driver_pause \
+ -Ddriver_drain=pulse_driver_drain
+libsydney_pulse_la_LIBADD = \
+ $(PULSE_LIBS) \
+ libsydney.la
+libsydney_pulse_la_LDFLAGS = \
+ -avoid-version -module -export-dynamic
+
+endif
+endif
+
+if HAVE_JACK
+if BUILTIN_JACK
+
+libsydney_la_SOURCES += \
+ jack.c
+libsydney_la_CFLAGS += \
+ $(JACK_CFLAGS)
+libsydney_la_LIBADD += \
+ $(JACK_LIBS)
+
+else
+
+plugin_LTLIBRARIES += \
+ libsydney-jack.la
+
+libsydney_jack_la_SOURCES = \
+ jack.c
+libsydney_jack_la_CFLAGS = \
+ $(JACK_CFLAGS) \
+ -Ddriver_open=jack_driver_open \
+ -Ddriver_destroy=jack_driver_destroy \
+ -Ddriver_change_write_latency=jack_driver_change_write_latency \
+ -Ddriver_change_read_latency=jack_driver_change_read_latency \
+ -Ddriver_change_device=jack_driver_change_device \
+ -Ddriver_change_read_volume=jack_driver_change_read_volume \
+ -Ddriver_change_write_volume=jack_driver_change_write_volume \
+ -Ddriver_change_pcm_rate=jack_driver_change_pcm_rate \
+ -Ddriver_change_props=jack_driver_change_props \
+ -Ddriver_get_state=jack_driver_get_state \
+ -Ddriver_get_position=jack_driver_get_position \
+ -Ddriver_wait=jack_driver_wait \
+ -Ddriver_read=jack_driver_read \
+ -Ddriver_read_ni=jack_driver_read_ni \
+ -Ddriver_pwrite=jack_driver_pwrite \
+ -Ddriver_pwrite_ni=jack_driver_pwrite_ni \
+ -Ddriver_get_read_size=jack_driver_get_read_size \
+ -Ddriver_get_write_size=jack_driver_get_write_size \
+ -Ddriver_resume=jack_driver_resume \
+ -Ddriver_pause=jack_driver_pause \
+ -Ddriver_drain=jack_driver_drain
+libsydney_jack_la_LIBADD = \
+ $(JACK_LIBS) \
+ libsydney.la
+libsydney_jack_la_LDFLAGS = \
+ -avoid-version -module -export-dynamic
+
+endif
+endif
+
+if HAVE_NULL
+if BUILTIN_NULL
+
+libsydney_la_SOURCES += \
+ null.c
+
+else
+
+plugin_LTLIBRARIES += \
+ libsydney-null.la
+
+libsydney_null_la_SOURCES = \
+ null.c
+libsydney_null_la_CFLAGS = \
+ -Ddriver_open=null_driver_open \
+ -Ddriver_destroy=null_driver_destroy \
+ -Ddriver_change_write_latency=null_driver_change_write_latency \
+ -Ddriver_change_read_latency=null_driver_change_read_latency \
+ -Ddriver_change_device=null_driver_change_device \
+ -Ddriver_change_read_volume=null_driver_change_read_volume \
+ -Ddriver_change_write_volume=null_driver_change_write_volume \
+ -Ddriver_change_pcm_rate=null_driver_change_pcm_rate \
+ -Ddriver_change_props=null_driver_change_props \
+ -Ddriver_get_state=null_driver_get_state \
+ -Ddriver_get_position=null_driver_get_position \
+ -Ddriver_wait=null_driver_wait \
+ -Ddriver_read=null_driver_read \
+ -Ddriver_read_ni=null_driver_read_ni \
+ -Ddriver_pwrite=null_driver_pwrite \
+ -Ddriver_pwrite_ni=null_driver_pwrite_ni \
+ -Ddriver_get_read_size=null_driver_get_read_size \
+ -Ddriver_get_write_size=null_driver_get_write_size \
+ -Ddriver_resume=null_driver_resume \
+ -Ddriver_pause=null_driver_pause \
+ -Ddriver_drain=null_driver_drain
+libsydney_null_la_LIBADD = \
+ libsydney.la
+libsydney_null_la_LDFLAGS = \
+ -avoid-version -module -export-dynamic
+endif
+endif
test_bufferq_SOURCES = \
test-bufferq.c
@@ -90,12 +344,6 @@ test_pull_LDADD = \
$(AM_LDADD) \
libsydney.la
-#test_asyncq_SOURCES = \
-# test-asyncq.c
-#test_asyncq_LDADD = \
-# $(AM_LDADD) \
-# libsydney.la
-
fixme:
find -name '*.c' -exec fgrep -H -A 3 -B 3 -i FIXME \{\} \;
diff --git a/src/add.c b/src/add.c
index 74eef31..6701b62 100644
--- a/src/add.c
+++ b/src/add.c
@@ -1,3 +1,23 @@
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@@ -12,15 +32,15 @@ static void add_u8(void *dst, size_t dstr, const void *src1, size_t sstr1, const
const uint8_t *s1 = src1, *s2 = src2;
for (; bytes > 0; bytes--, d += dstr, s1 += sstr1, s2 += sstr2) {
- int16_t v = (int16_t) *s1 + (int16_t) *s2 - 0x80;
+ int16_t v = (int16_t) *s1 + (int16_t) *s2 - (int16_t) 0x80;
- v = CLAMP(v, 0, 0xFF);
+ v = SA_CLAMP(v, (int16_t) 0, (int16_t) 0xFF);
*d = (uint8_t) v;
}
}
static void add_s16(void *dst, size_t dstr, const void *src1, size_t sstr1, const void *src2, size_t sstr2, size_t bytes) {
- oil_vectoradd_s_s16(dst, dstr, src1, sstr1, src2, sstr2, bytes/sizeof(int16_t));
+ oil_vectoradd_s_s16(dst, (int) dstr, src1, (int) sstr1, src2, (int) sstr2, (int) (bytes/sizeof(int16_t)));
}
static void add_s32(void *dst, size_t dstr, const void *src1, size_t sstr1, const void *src2, size_t sstr2, size_t bytes) {
@@ -28,16 +48,16 @@ static void add_s32(void *dst, size_t dstr, const void *src1, size_t sstr1, cons
const int32_t *s1 = src1, *s2 = src2;
for (; bytes > 0; bytes--, d += dstr/sizeof(int32_t), s1 += sstr1/sizeof(int32_t), s2 += sstr2/sizeof(int32_t)) {
- int64_t v = (int64_t) *s1 + (uint64_t) *s2;
+ int64_t v = (int64_t) *s1 + (int64_t) *s2;
- v = CLAMP(v, -0x80000000, 0x7FFFFFFF);
+ v = SA_CLAMP(v, -0x80000000LL, 0x7FFFFFFFLL);
*d = (int32_t) v;
}
}
static void add_f32(void *dst, size_t dstr, const void *src1, size_t sstr1, const void *src2, size_t sstr2, size_t bytes) {
float a = 1, b = 1;
- oil_vectoradd_f32(dst, dstr, src1, sstr1, src2, sstr2, bytes/sizeof(int32_t), &a, &b);
+ oil_vectoradd_f32(dst, (int) dstr, src1, (int) sstr1, src2, (int) sstr2, (int) (bytes/sizeof(int32_t)), &a, &b);
}
sa_add_func_t sa_get_add_func(sa_pcm_format_t f) {
diff --git a/src/add.h b/src/add.h
index 6a31bc5..721baaf 100644
--- a/src/add.h
+++ b/src/add.h
@@ -1,6 +1,26 @@
#ifndef foosydneyaddhfoo
#define foosydneyaddhfoo
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
#include <sys/types.h>
#include <inttypes.h>
diff --git a/src/alsa.c b/src/alsa.c
new file mode 120000
index 0000000..cc3e685
--- /dev/null
+++ b/src/alsa.c
@@ -0,0 +1 @@
+null.c \ No newline at end of file
diff --git a/src/bbuffer.c b/src/bbuffer.c
index 733db4d..c0aff25 100644
--- a/src/bbuffer.c
+++ b/src/bbuffer.c
@@ -1,3 +1,23 @@
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
diff --git a/src/bbuffer.h b/src/bbuffer.h
index 0c5731b..ec94884 100644
--- a/src/bbuffer.h
+++ b/src/bbuffer.h
@@ -1,6 +1,26 @@
#ifndef foosydneybbufferhfoo
#define foosydneybbufferhfoo
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
#include <sys/types.h>
#include "macro.h"
diff --git a/src/bswap.c b/src/bswap.c
index 501f98a..4e965ad 100644
--- a/src/bswap.c
+++ b/src/bswap.c
@@ -1,11 +1,27 @@
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
-#ifdef HAVE_BYTESWAP_H
-#include <byteswap.h>
-#endif
-
#include <inttypes.h>
#include "macro.h"
@@ -14,15 +30,10 @@
static void byteswap16(void *_dst, size_t dstr, const void *_src, size_t sstr, size_t bytes) {
uint16_t *dst = _dst;
const uint16_t *src = _src;
- unsigned n = bytes / sizeof(uint16_t);
+ size_t n = bytes / sizeof(uint16_t);
for (; n > 0; n--) {
-
-#ifdef HAVE_BYTESWAP_H
- *dst = bswap_16(*src);
-#else
- *dst = (*src >> 8) | (*src << 8);
-#endif
+ *dst = SA_UINT16_SWAP(*src);
src += sstr / sizeof(uint16_t);
dst += dstr / sizeof(uint16_t);
@@ -32,7 +43,7 @@ static void byteswap16(void *_dst, size_t dstr, const void *_src, size_t sstr, s
static void byteswap24(void *_dst, size_t dstr, const void *_src, size_t sstr, size_t bytes) {
uint8_t *dst = _dst;
const uint8_t *src = _src;
- unsigned n = bytes / (sizeof(uint8_t)*3);
+ size_t n = bytes / 3;
for (; n > 0; n--) {
dst[0] = src[2];
@@ -46,14 +57,11 @@ static void byteswap24(void *_dst, size_t dstr, const void *_src, size_t sstr, s
static void byteswap32(void *_dst, size_t dstr, const void *_src, size_t sstr, size_t bytes) {
uint32_t *dst = _dst;
const uint32_t *src = _src;
- unsigned n = bytes / sizeof(uint32_t);
+ size_t n = bytes / sizeof(uint32_t);
for (; n > 0; n--) {
-#ifdef HAVE_BYTESWAP_H
- *dst = bswap_32(*src);
-#else
- *dst = (*src << 24) | ((*src & 0xFF00) << 8) | ((*src >> 8) & 0xFF00) | (*src >> 24);
-#endif
+ *dst = SA_UINT32_SWAP(*src);
+
src += sstr / sizeof(uint32_t);
dst += dstr / sizeof(uint32_t);
}
diff --git a/src/bswap.h b/src/bswap.h
index 4eeb24f..1866d0e 100644
--- a/src/bswap.h
+++ b/src/bswap.h
@@ -1,6 +1,26 @@
#ifndef foosydneybswaphfoo
#define foosydneybswaphfoo
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
#include <sys/types.h>
#include "sydney.h"
diff --git a/src/bufferq.c b/src/bufferq.c
index 46f9bbc..f2effd1 100644
--- a/src/bufferq.c
+++ b/src/bufferq.c
@@ -1,3 +1,23 @@
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@@ -122,12 +142,12 @@ int sa_bufferq_push(sa_bufferq_t *q, unsigned channel, const void *data, size_t
if (q->read_index > idx && type != SA_BUFFERQ_ITEM_DYNAMIC) {
int64_t l = q->read_index - idx;
- if (l > nbytes)
- l = nbytes;
+ if (l > (int64_t) nbytes)
+ l = (int64_t) nbytes;
idx += l;
data = (const uint8_t*) data + l;
- nbytes -= l;
+ nbytes -= (size_t) l;
}
@@ -136,12 +156,12 @@ int sa_bufferq_push(sa_bufferq_t *q, unsigned channel, const void *data, size_t
return SA_ERROR_OOM;
/* Find the position where we need to insert the new entry */
- for (i = q->items[channel]; i && idx >= i->idx + i->size; i = i->bufferq_next)
+ for (i = q->items[channel]; i && idx >= i->idx + (int64_t) i->size; i = i->bufferq_next)
;
/* Shorten the current entry if necessary */
if (i && idx > i->idx) {
- i->size = idx - i->idx;
+ i->size = (size_t) (idx - i->idx);
i = i->bufferq_next;
}
@@ -158,13 +178,13 @@ int sa_bufferq_push(sa_bufferq_t *q, unsigned channel, const void *data, size_t
}
/* Now kick all the entries that overlap entirely with our new entry */
- for (i = j->bufferq_next; i && i->idx + i->size < j->idx + j->size ; i = n) {
+ for (i = j->bufferq_next; i && i->idx + (int64_t) i->size < j->idx + (int64_t) j->size ; i = n) {
n = i->bufferq_next;
SA_LLIST_REMOVE(sa_bufferq_item_t, bufferq, q->items[channel], i);
bufferq_item_free(i);
}
- q->write_index = idx + nbytes;
+ q->write_index = idx + (int64_t) nbytes;
if (q->write_index > q->end_index)
q->end_index = q->write_index;
@@ -190,22 +210,22 @@ void sa_bufferq_get(sa_bufferq_t *q, void *i[], size_t *bytes) {
l = q->items[u]->idx - q->read_index;
if (first) {
- *bytes = l;
+ *bytes = (size_t) l;
first = FALSE;
} else
- *bytes = l < *bytes ? l : *bytes;
+ *bytes = l < (int64_t) *bytes ? (size_t) l : *bytes;
} else {
int64_t l;
i[u] = (uint8_t*) q->items[u]->data + q->read_index - q->items[u]->idx;
- l = q->items[u]->size - (q->read_index - q->items[u]->idx);
+ l = (int64_t) q->items[u]->size - (q->read_index - q->items[u]->idx);
if (first) {
- *bytes = l;
+ *bytes = (size_t) l;
first = FALSE;
} else
- *bytes = l < *bytes ? l : *bytes;
+ *bytes = l < (int64_t) *bytes ? (size_t) l : *bytes;
}
} else
@@ -225,7 +245,7 @@ void sa_bufferq_drop(sa_bufferq_t *q, int64_t bytes) {
i = q->items[u];
- while (i && q->read_index >= i->idx + i->size) {
+ while (i && q->read_index >= i->idx + (int64_t) i->size) {
sa_bufferq_item_t *n = i->bufferq_next;
SA_LLIST_REMOVE(sa_bufferq_item_t, bufferq, q->items[u], i);
diff --git a/src/bufferq.h b/src/bufferq.h
index 0f87fc9..53e4cf3 100644
--- a/src/bufferq.h
+++ b/src/bufferq.h
@@ -1,6 +1,26 @@
#ifndef foosydneybufferqhfoo
#define foosydneybufferqhfoo
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
#include <inttypes.h>
#include "macro.h"
diff --git a/src/common.c b/src/common.c
index 0187990..5a50f9e 100644
--- a/src/common.c
+++ b/src/common.c
@@ -1,9 +1,30 @@
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <errno.h>
+#include <math.h>
#include <liboil/liboil.h>
#include "sydney.h"
@@ -12,72 +33,114 @@
#include "common.h"
#include "driver.h"
#include "mutex.h"
+#include "proplist.h"
+
+/*
+ Requirements & General observations
+
+ - In sync mode, the device will automatically write data so that an
+ initial read causes writes of zeros to be issued to that one can
+ do "while (1); {read(); write()}
+ - All functions are thread-safe and can be called in any thread
+ context. None of the functions is async-signal safe.
+ - It is assumed that duplex streams have a single clock (synchronised)
+ - Property set extensible. To be kept in sync with PulseAudio and libcanberra
+ - Error codes are returned immediately, as negative integers
+ - It is recommended to set most properties before the _open() call.
+
+*/
-/* contains code */
-#include "meta-name-table.h"
+#define DEFAULT_LATENCY_USEC (2000000ULL) /* 2s */
+#define DEFAULT_PROCESS_TIME_USEC (20000ULL) /* 20ms */
-static sa_stream_t *stream_alloc(void) {
- sa_stream_t *d;
+static int stream_alloc(sa_stream **_s) {
+ sa_stream *s;
+ const char *d;
+ int ret;
+
+ sa_assert(_s);
- if (!(d = sa_new0(sa_stream_t, 1)))
- return NULL;
+ if (!(s = sa_new0(sa_stream, 1))) {
+ ret = SA_ERROR_OOM;
+ goto fail;
+ }
/* All fields a carefully chosen in a way that initializing them
- * NUL bytes is sufficient */
+ * with NUL bytes is sufficient */
- if (!(d->mutex = sa_mutex_new(FALSE, TRUE))) {
- sa_free(d);
- return NULL;
+ if (!(s->mutex = sa_mutex_new(TRUE, TRUE))) {
+ ret = SA_ERROR_OOM;
+ goto fail;
}
- return d;
+ if ((ret = sa_proplist_create(&s->props)) < 0)
+ goto fail;
+
+ if ((d = getenv("SYDNEY_DRIVER")))
+ if ((ret = sa_stream_set_driver(s, d)) < 0)
+ goto fail;
+
+ if ((d = getenv("SYDNEY_DEVICE")))
+ if ((ret = sa_stream_change_device(s, d)) < 0)
+ goto fail;
+
+ *_s = s;
+
+ return SA_SUCCESS;
+
+fail:
+
+ if (s)
+ sa_assert_se(sa_stream_destroy(s) == SA_SUCCESS);
+
+ return ret;
}
int sa_stream_create_opaque(
- sa_stream_t **s,
- const char *client_name,
+ sa_stream **_s,
sa_mode_t mode,
const char *codec) {
- int error;
+ int ret;
+ sa_stream *s;
- sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(_s, SA_ERROR_INVALID);
sa_return_val_if_fail(mode == SA_MODE_RDONLY || mode == SA_MODE_WRONLY || mode == SA_MODE_RDWR, SA_ERROR_INVALID);
sa_return_val_if_fail(codec, SA_ERROR_INVALID);
- if (!(*s = stream_alloc()))
+ if ((ret = stream_alloc(&s)) < 0)
return SA_ERROR_OOM;
- (*s)->mode = mode;
+ s->mode = mode;
- if (!((*s)->codec = sa_strdup(codec))) {
- error = SA_ERROR_OOM;
+ if (!(s->codec = sa_strdup(codec))) {
+ ret = SA_ERROR_OOM;
goto fail;
}
oil_init();
- if (client_name)
- if ((error = sa_stream_change_meta_data(*s, SA_META_CLIENT_NAME, client_name, strlen(client_name)+1)) < 0)
- goto fail;
+ *_s = s;
return SA_SUCCESS;
fail:
- sa_stream_destroy(*s);
- return error;
+
+ if (s)
+ sa_assert_se(sa_stream_destroy(s) == SA_SUCCESS);
+
+ return ret;
}
int sa_stream_create_pcm(
- sa_stream_t **s,
- const char *client_name,
+ sa_stream **_s,
sa_mode_t mode,
sa_pcm_format_t format,
unsigned rate,
unsigned nchannels) {
int ret;
- size_t lwm;
+ sa_stream *s;
sa_return_val_if_fail(s, SA_ERROR_INVALID);
sa_return_val_if_fail(mode == SA_MODE_RDONLY || mode == SA_MODE_WRONLY || mode == SA_MODE_RDWR, SA_ERROR_INVALID);
@@ -85,90 +148,122 @@ int sa_stream_create_pcm(
sa_return_val_if_fail(rate > 0, SA_ERROR_INVALID);
sa_return_val_if_fail(nchannels > 0, SA_ERROR_INVALID);
- if (!(*s = stream_alloc()))
+ if ((ret = stream_alloc(&s)) < 0)
return SA_ERROR_OOM;
- (*s)->mode = mode;
- (*s)->pcm_attrs.format = format;
- (*s)->pcm_attrs.nchannels = nchannels;
- (*s)->pcm_sample_size = sa_get_pcm_sample_size(format);
- (*s)->pcm_frame_size = (*s)->pcm_sample_size * nchannels;
+ s->mode = mode;
+ s->pcm_attrs.format = format;
+ s->pcm_attrs.nchannels = nchannels;
+ s->pcm_sample_size = sa_get_pcm_sample_size(format);
+ s->pcm_frame_size = s->pcm_sample_size * nchannels;
+
+ if ((ret = sa_stream_change_pcm_rate(s, rate)))
+ goto fail;
if (nchannels <= 2) {
static const sa_channel_t map_stereo[2] = { SA_CHANNEL_LEFT, SA_CHANNEL_RIGHT };
static const sa_channel_t map_mono[1] = { SA_CHANNEL_MONO };
- if ((ret = sa_stream_set_channel_map(*s, nchannels == 2 ? map_stereo : map_mono, nchannels)))
+ if ((ret = sa_stream_set_channel_map(s, nchannels == 2 ? map_stereo : map_mono, nchannels)))
goto fail;
}
- if ((ret = sa_stream_change_rate(*s, rate)))
- goto fail;
+ oil_init();
- lwm = ((*s)->pcm_frame_size * (*s)->pcm_attrs.rate) / 20; /* 50 ms */
+ *_s = s;
- if (lwm <= 0)
- lwm = (*s)->pcm_frame_size * (*s)->pcm_attrs.rate; /* 1s */
+ return SA_SUCCESS;
-/* if (mode & SA_MODE_RDONLY) { */
+fail:
-/* if ((ret = sa_stream_set_read_lower_watermark(*s, lwm))) */
-/* goto fail; */
+ sa_assert_se(sa_stream_destroy(s) == SA_SUCCESS);
+ return ret;
+}
-/* if ((ret = sa_stream_set_read_upper_watermark(*s, lwm*2))) */
-/* goto fail; */
-/* } */
+static int fix_latency(sa_stream *s, size_t *latency_nbytes, size_t *process_time_nbytes) {
-/* if (mode & SA_MODE_WRONLY) { */
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(latency_nbytes, SA_ERROR_INVALID);
+ sa_return_val_if_fail(process_time_nbytes, SA_ERROR_INVALID);
-/* if ((ret = sa_stream_set_write_lower_watermark(*s, lwm))) */
-/* goto fail; */
+ if (*latency_nbytes <= 0)
+ *latency_nbytes = sa_stream_usec_to_bytes(s, DEFAULT_LATENCY_USEC, 0);
-/* if ((ret = sa_stream_set_write_upper_watermark(*s, lwm*2))) */
-/* goto fail; */
-/* } */
+ if (*process_time_nbytes <= 0) {
+ size_t n, m;
- oil_init();
+ n = sa_stream_frames_to_bytes(s, sa_stream_bytes_to_frames(s, *latency_nbytes, 1)/2);
+ m = sa_stream_usec_to_bytes(s, DEFAULT_PROCESS_TIME_USEC, 0);
- if (client_name)
- if ((ret = sa_stream_change_meta_data(*s, SA_META_CLIENT_NAME, client_name, strlen(client_name))) < 0)
- goto fail;
+ *process_time_nbytes = SA_MIN(n, m);
+ }
+
+ sa_return_val_if_fail(*latency_nbytes > 0, SA_ERROR_INVALID);
+ sa_return_val_if_fail(*process_time_nbytes >= *latency_nbytes, SA_ERROR_INVALID);
+ sa_return_val_if_fail(sa_stream_frame_aligned(s, (int64_t) *latency_nbytes), SA_ERROR_INVALID);
+ sa_return_val_if_fail(sa_stream_frame_aligned(s, (int64_t) *process_time_nbytes), SA_ERROR_INVALID);
return SA_SUCCESS;
+}
-fail:
- sa_stream_destroy(*s);
+static int stream_open_unlocked(sa_stream *s) {
+ int ret;
+
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->codec || s->pcm_attrs.channel_map, SA_ERROR_STATE);
+
+ if (s->state == SA_STATE_DEAD)
+ return SA_ERROR_STATE;
+ else if (s->state != SA_STATE_INIT)
+ return SA_SUCCESS;
+
+ if (s->mode & SA_MODE_RDONLY)
+ if ((ret = fix_latency(s, &s->read_latency, &s->read_process_time)) < 0)
+ return ret;
+
+ if (s->mode & SA_MODE_WRONLY)
+ if ((ret = fix_latency(s, &s->write_latency, &s->write_process_time)) < 0)
+ return ret;
+
+ if ((ret = driver_open(s)) == SA_SUCCESS)
+ s->state = SA_STATE_STOPPED;
+
return ret;
}
-int sa_stream_open(sa_stream_t *s) {
+int sa_stream_open(sa_stream *s) {
int ret;
sa_return_val_if_fail(s, SA_ERROR_INVALID);
sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_INIT, SA_ERROR_STATE);
- sa_return_val_if_fail_mutex(s->mutex, s->codec || s->pcm_attrs.channel_map, SA_ERROR_NO_INIT);
-/* sa_return_val_if_fail_mutex(s->mutex, !(s->mode & SA_MODE_RDONLY) || (s->read_lower_watermark <= s->read_upper_watermark), SA_ERROR_INVALID); */
-/* sa_return_val_if_fail_mutex(s->mutex, !(s->mode & SA_MODE_WRONLY) || (s->write_lower_watermark <= s->write_upper_watermark), SA_ERROR_INVALID); */
-/* sa_return_val_if_fail_mutex(s->mutex, !(s->mode & SA_MODE_RDONLY) || !s->codec || (s->read_lower_watermark > 0 && s->read_upper_watermark > 0), SA_ERROR_NO_INIT); */
-/* sa_return_val_if_fail_mutex(s->mutex, !(s->mode & SA_MODE_WRONLY) || !s->codec || (s->write_lower_watermark > 0 && s->write_upper_watermark > 0), SA_ERROR_NO_INIT); */
-
- if ((ret = driver_open(s)) == 0)
- s->state = SA_STATE_STOPPED;
+
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_INIT, SA_ERROR_STATE, s->mutex);
+
+ ret = stream_open_unlocked(s);
sa_mutex_unlock(s->mutex);
return ret;
}
-int sa_stream_destroy(sa_stream_t *s) {
- int ret;
- unsigned u;
+int sa_stream_destroy(sa_stream *s) {
+ int ret = SA_SUCCESS;
sa_return_val_if_fail(s, SA_ERROR_INVALID);
- ret = driver_destroy(s);
+ /* There's no locking necessary here, because the application is
+ * broken anyway if it destructs this object in one thread and
+ * still is calling a method of it in another. */
+
+ if (s->state != SA_STATE_INIT)
+ ret = driver_destroy(s);
+
+ if (s->props)
+ sa_assert_se(sa_proplist_destroy(s->props) == SA_SUCCESS);
+
+ if (s->mutex)
+ sa_mutex_free(s->mutex);
sa_free(s->codec);
sa_free(s->driver);
@@ -176,106 +271,100 @@ int sa_stream_destroy(sa_stream_t *s) {
sa_free(s->pcm_attrs.channel_map);
sa_free(s->read_volume);
sa_free(s->write_volume);
-
- for (u = 0; u < _META_NAMES_MAX; u++)
- sa_free(s->meta_data[u]);
-
- sa_mutex_free(s->mutex);
sa_free(s);
+
return ret;
}
-/* int sa_stream_set_write_lower_watermark(sa_stream_t *s, size_t size) { */
-
-/* sa_return_val_if_fail(s, SA_ERROR_INVALID); */
-/* sa_return_val_if_fail(size > 0, SA_ERROR_INVALID); */
-/* sa_mutex_lock(s->mutex); */
-/* sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_INIT, SA_ERROR_STATE); */
-/* sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_WRONLY, SA_ERROR_STATE); */
+int sa_stream_change_write_latency(sa_stream *s, size_t latency_nbytes, size_t process_time_nbytes) {
+ int ret;
-/* s->write_lower_watermark = size; */
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->mode & SA_MODE_WRONLY, SA_ERROR_STATE);
-/* sa_mutex_unlock(s->mutex); */
+ if ((ret = fix_latency(s, &latency_nbytes, &process_time_nbytes)) < 0)
+ return ret;
-/* return SA_SUCCESS; */
-/* } */
+ sa_mutex_lock(s->mutex);
+ sa_return_val_if_fail_unlock(s->state != SA_STATE_DEAD, SA_ERROR_STATE, s->mutex);
-/* int sa_stream_set_read_lower_watermark(sa_stream_t *s, size_t size) { */
+ ret = s->state == SA_STATE_INIT ? SA_SUCCESS : driver_change_write_latency(s, &latency_nbytes, &process_time_nbytes);
-/* sa_return_val_if_fail(s, SA_ERROR_INVALID); */
-/* sa_return_val_if_fail(size > 0, SA_ERROR_INVALID); */
-/* sa_mutex_lock(s->mutex); */
-/* sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_INIT, SA_ERROR_STATE); */
-/* sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_RDONLY, SA_ERROR_STATE); */
+ if (ret == SA_SUCCESS) {
+ s->write_latency = latency_nbytes;
+ s->write_process_time = process_time_nbytes;
+ }
-/* s->read_lower_watermark = size; */
+ sa_mutex_unlock(s->mutex);
-/* sa_mutex_unlock(s->mutex); */
-/* return SA_SUCCESS; */
-/* } */
+ return ret;
+}
-/* int sa_stream_set_write_upper_watermark(sa_stream_t *s, size_t size) { */
+int sa_stream_change_read_latency(sa_stream *s, size_t latency_nbytes, size_t process_time_nbytes) {
+ int ret;
-/* sa_return_val_if_fail(s, SA_ERROR_INVALID); */
-/* sa_return_val_if_fail(size > 0, SA_ERROR_INVALID); */
-/* sa_mutex_lock(s->mutex); */
-/* sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_INIT, SA_ERROR_STATE); */
-/* sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_WRONLY, SA_ERROR_STATE); */
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->mode & SA_MODE_RDONLY, SA_ERROR_STATE);
-/* s->write_upper_watermark = size; */
+ if ((ret = fix_latency(s, &latency_nbytes, &process_time_nbytes)) < 0)
+ return ret;
-/* sa_mutex_unlock(s->mutex); */
-/* return SA_SUCCESS; */
-/* } */
+ sa_mutex_lock(s->mutex);
+ sa_return_val_if_fail_unlock(s->state != SA_STATE_DEAD, SA_ERROR_STATE, s->mutex);
-/* int sa_stream_set_read_upper_watermark(sa_stream_t *s, size_t size) { */
+ ret = s->state == SA_STATE_INIT ? SA_SUCCESS : driver_change_read_latency(s, &latency_nbytes, &process_time_nbytes);
-/* sa_return_val_if_fail(s, SA_ERROR_INVALID); */
-/* sa_return_val_if_fail(size > 0, SA_ERROR_INVALID); */
-/* sa_mutex_lock(s->mutex); */
-/* sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_INIT, SA_ERROR_STATE); */
-/* sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_RDONLY, SA_ERROR_STATE); */
+ if (ret == SA_SUCCESS) {
+ s->read_latency = latency_nbytes;
+ s->read_process_time = process_time_nbytes;
+ }
-/* s->read_upper_watermark = size; */
+ sa_mutex_unlock(s->mutex);
-/* sa_mutex_unlock(s->mutex); */
-/* return SA_SUCCESS; */
-/* } */
+ return ret;
+}
-int sa_stream_set_channel_map(sa_stream_t *s, const sa_channel_t *map, unsigned n) {
+int sa_stream_set_channel_map(sa_stream *s, const sa_channel_t *map, unsigned n) {
const sa_channel_t *c;
sa_channel_t *m;
+ int ret;
sa_return_val_if_fail(s, SA_ERROR_INVALID);
sa_return_val_if_fail(map, SA_ERROR_INVALID);
+ sa_return_val_if_fail(!s->codec, SA_ERROR_STATE);
+ sa_return_val_if_fail(n == s->pcm_attrs.nchannels, SA_ERROR_INVALID);
+
sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_INIT, SA_ERROR_STATE);
- sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE);
- sa_return_val_if_fail_mutex(s->mutex, n == s->pcm_attrs.nchannels, SA_ERROR_INVALID);
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_INIT, SA_ERROR_STATE, s->mutex);
for (c = map; n > 0; c++, n--)
if (*c >= _SA_CHANNEL_MAX) {
- sa_mutex_unlock(s->mutex);
- return SA_ERROR_INVALID;
+ ret = SA_ERROR_INVALID;
+ goto fail;
}
if (!(m = sa_memdup(map, sizeof(sa_channel_t) * s->pcm_attrs.nchannels))) {
- sa_mutex_unlock(s->mutex);
- return SA_ERROR_OOM;
+ ret = SA_ERROR_OOM;
+ goto fail;
}
sa_free(s->pcm_attrs.channel_map);
s->pcm_attrs.channel_map = m;
+ ret = SA_SUCCESS;
+
+fail:
sa_mutex_unlock(s->mutex);
- return SA_SUCCESS;
+
+ return ret;
}
-int sa_stream_set_xrun_mode(sa_stream_t *s, sa_xrun_mode_t mode) {
+int sa_stream_set_xrun_mode(sa_stream *s, sa_xrun_mode_t mode) {
sa_return_val_if_fail(s, SA_ERROR_INVALID);
sa_return_val_if_fail(mode == SA_XRUN_MODE_STOP || mode == SA_XRUN_MODE_SPIN, SA_ERROR_INVALID);
+
sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_INIT, SA_ERROR_STATE);
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_INIT, SA_ERROR_STATE, s->mutex);
s->xrun_mode = mode;
@@ -283,11 +372,12 @@ int sa_stream_set_xrun_mode(sa_stream_t *s, sa_xrun_mode_t mode) {
return SA_SUCCESS;
}
-int sa_stream_set_non_interleaved(sa_stream_t *s, int enable) {
+int sa_stream_set_non_interleaved(sa_stream *s, int enable) {
sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(!s->codec, SA_ERROR_STATE);
+
sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_INIT, SA_ERROR_INVALID);
- sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE);
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_INIT, SA_ERROR_INVALID, s->mutex);
s->ni_enabled = !!enable;
@@ -295,11 +385,12 @@ int sa_stream_set_non_interleaved(sa_stream_t *s, int enable) {
return SA_SUCCESS;
}
-int sa_stream_set_dynamic_rate(sa_stream_t *s, int enable) {
+int sa_stream_set_dynamic_pcm_rate(sa_stream *s, int enable) {
sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(!s->codec, SA_ERROR_STATE);
+
sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_INIT, SA_ERROR_INVALID);
- sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE);
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_INIT, SA_ERROR_INVALID, s->mutex);
s->dynamic_rate_enabled = !!enable;
@@ -307,74 +398,63 @@ int sa_stream_set_dynamic_rate(sa_stream_t *s, int enable) {
return SA_SUCCESS;
}
-int sa_stream_set_driver(sa_stream_t *s, const char *driver) {
+int sa_stream_set_driver(sa_stream *s, const char *driver) {
char *d;
+ int ret;
sa_return_val_if_fail(s, SA_ERROR_INVALID);
- sa_return_val_if_fail(driver, SA_ERROR_INVALID);
+
sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_INIT, SA_ERROR_STATE);
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_INIT, SA_ERROR_STATE, s->mutex);
- if (!(d = sa_strdup(driver))) {
- sa_mutex_unlock(s->mutex);
- return SA_ERROR_OOM;
+ if (!driver)
+ d = NULL;
+ else if (!(d = sa_strdup(driver))) {
+ ret = SA_ERROR_OOM;
+ goto fail;
}
sa_free(s->driver);
s->driver = d;
- sa_mutex_unlock(s->mutex);
- return SA_SUCCESS;
-}
-
-int sa_stream_start_thread(sa_stream_t *s, sa_event_callback_t callback) {
- int r;
-
- sa_return_val_if_fail(s, SA_ERROR_INVALID);
- sa_return_val_if_fail(callback, SA_ERROR_INVALID);
- sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE);
- sa_return_val_if_fail_mutex(s->mutex, !s->callback, SA_ERROR_STATE);
-
- r = driver_start_thread(s, callback);
-
- if (r == SA_SUCCESS)
- s->callback = callback;
+ ret = SA_SUCCESS;
+fail:
sa_mutex_unlock(s->mutex);
- return r;
-}
-int sa_stream_stop_thread(sa_stream_t *s) {
- int r;
+ return ret;
+}
+int sa_stream_set_event_callback(sa_stream *s, sa_event_callback_t callback) {
sa_return_val_if_fail(s, SA_ERROR_INVALID);
- sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE);
- sa_return_val_if_fail_mutex(s->mutex, s->callback, SA_ERROR_STATE);
- r = driver_stop_thread(s);
+ sa_mutex_lock(s->mutex);
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_INIT, SA_ERROR_STATE, s->mutex);
- if (r == SA_SUCCESS)
- s->callback = NULL;
+ s->callback = callback;
sa_mutex_unlock(s->mutex);
- return r;
+
+ return SA_SUCCESS;
}
-int sa_stream_change_device(sa_stream_t *s, const char *device_name) {
+int sa_stream_change_device(sa_stream *s, const char *device) {
char *d;
int ret;
sa_return_val_if_fail(s, SA_ERROR_INVALID);
- sa_return_val_if_fail(device_name, SA_ERROR_INVALID);
-
- if (!(d = sa_strdup(device_name)))
- return SA_ERROR_OOM;
sa_mutex_lock(s->mutex);
+ sa_return_val_if_fail_unlock(s->state != SA_STATE_DEAD, SA_ERROR_STATE, s->mutex);
- ret = s->state == SA_STATE_INIT ? SA_SUCCESS : driver_change_device(s, device_name);
+ if (!device)
+ d = NULL;
+ else if (!(d = sa_strdup(device))) {
+ ret = SA_ERROR_OOM;
+ goto fail;
+ }
+
+ ret = s->state == SA_STATE_INIT ? SA_SUCCESS : driver_change_device(s, d);
if (ret == SA_SUCCESS) {
sa_free(s->device);
@@ -382,31 +462,36 @@ int sa_stream_change_device(sa_stream_t *s, const char *device_name) {
} else
sa_free(d);
+fail:
sa_mutex_unlock(s->mutex);
return ret;
}
-int sa_stream_change_read_volume(sa_stream_t *s, const int32_t vol[], unsigned n) {
+int sa_stream_change_read_volume(sa_stream *s, const int32_t vol[], unsigned n) {
int *v, ret;
sa_return_val_if_fail(s, SA_ERROR_INVALID);
sa_return_val_if_fail(vol, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->mode & SA_MODE_RDONLY, SA_ERROR_STATE);
+ sa_return_val_if_fail(!s->codec, SA_ERROR_STATE);
+ sa_return_val_if_fail(n == s->pcm_attrs.nchannels || n == 1, SA_ERROR_INVALID);
+
sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_RDONLY, SA_ERROR_STATE);
- sa_return_val_if_fail_mutex(s->mutex, (!s->codec && n == s->pcm_attrs.nchannels) || s->pcm_attrs.nchannels == 1, SA_ERROR_INVALID);
- if (s->codec || s->pcm_attrs.nchannels == n) {
+ if (s->pcm_attrs.nchannels == n) {
if (!(v = sa_newdup(int32_t, vol, n))) {
- sa_mutex_unlock(s->mutex);
- return SA_ERROR_OOM;
+ ret = SA_ERROR_OOM;
+ goto fail;
}
} else {
unsigned i;
+ sa_assert_se(n == 1);
+
if (!(v = sa_new(int32_t, s->pcm_attrs.nchannels))) {
- sa_mutex_unlock(s->mutex);
- return SA_ERROR_OOM;
+ ret = SA_ERROR_OOM;
+ goto fail;
}
for (i = 0; i < s->pcm_attrs.nchannels; i++)
@@ -421,30 +506,36 @@ int sa_stream_change_read_volume(sa_stream_t *s, const int32_t vol[], unsigned n
} else
sa_free(v);
+ ret = SA_SUCCESS;
+
+fail:
sa_mutex_unlock(s->mutex);
+
return ret;
}
-int sa_stream_change_write_volume(sa_stream_t *s, const int32_t vol[], unsigned n) {
+int sa_stream_change_write_volume(sa_stream *s, const int32_t vol[], unsigned n) {
int *v, ret;
sa_return_val_if_fail(s, SA_ERROR_INVALID);
sa_return_val_if_fail(vol, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->mode & SA_MODE_WRONLY, SA_ERROR_STATE);
+ sa_return_val_if_fail(!s->codec, SA_ERROR_STATE);
+ sa_return_val_if_fail(n == s->pcm_attrs.nchannels || n == 1, SA_ERROR_INVALID);
+
sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_WRONLY, SA_ERROR_STATE);
- sa_return_val_if_fail_mutex(s->mutex, (!s->codec && n == s->pcm_attrs.nchannels) || s->pcm_attrs.nchannels == 1, SA_ERROR_INVALID);
- if (s->codec || s->pcm_attrs.nchannels == n) {
+ if (s->pcm_attrs.nchannels == n) {
if (!(v = sa_newdup(int32_t, vol, n))) {
- sa_mutex_unlock(s->mutex);
- return SA_ERROR_OOM;
+ ret = SA_ERROR_OOM;
+ goto fail;
}
} else {
unsigned i;
if (!(v = sa_new(int32_t, s->pcm_attrs.nchannels))) {
- sa_mutex_unlock(s->mutex);
- return SA_ERROR_OOM;
+ ret = SA_ERROR_OOM;
+ goto fail;
}
for (i = 0; i < s->pcm_attrs.nchannels; i++)
@@ -459,20 +550,23 @@ int sa_stream_change_write_volume(sa_stream_t *s, const int32_t vol[], unsigned
} else
sa_free(v);
+fail:
sa_mutex_unlock(s->mutex);
+
return ret;
}
-int sa_stream_change_rate(sa_stream_t *s, unsigned rate) {
+int sa_stream_change_pcm_rate(sa_stream *s, unsigned rate) {
int ret;
sa_return_val_if_fail(s, SA_ERROR_INVALID);
sa_return_val_if_fail(rate > 0, SA_ERROR_INVALID);
+ sa_return_val_if_fail(!s->codec, SA_ERROR_STATE);
+
sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE);
- sa_return_val_if_fail_mutex(s->mutex, s->dynamic_rate_enabled || s->state == SA_STATE_INIT, SA_ERROR_STATE);
+ sa_return_val_if_fail_unlock(s->dynamic_rate_enabled || s->state == SA_STATE_INIT, SA_ERROR_STATE, s->mutex);
- ret = s->state == SA_STATE_INIT ? SA_SUCCESS : driver_change_rate(s, rate);
+ ret = s->state == SA_STATE_INIT ? SA_SUCCESS : driver_change_pcm_rate(s, rate);
if (ret == SA_SUCCESS)
s->pcm_attrs.rate = rate;
@@ -481,7 +575,55 @@ int sa_stream_change_rate(sa_stream_t *s, unsigned rate) {
return ret;
}
-int sa_stream_change_user_data(sa_stream_t *s, const void *value) {
+int sa_stream_change_props(sa_stream *s, ...) {
+ va_list ap;
+ int ret;
+ sa_proplist *p = NULL;
+
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+
+ va_start(ap, s);
+ ret = sa_proplist_from_ap(&p, ap);
+ va_end(ap);
+
+ if (ret < 0)
+ return ret;
+
+ ret = sa_stream_change_props_full(s, p);
+
+ sa_assert_se(sa_proplist_destroy(p) == 0);
+
+ return ret;
+}
+
+int sa_stream_change_props_full(sa_stream *s, sa_proplist *p) {
+ int ret;
+ sa_proplist *merged;
+
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(p, SA_ERROR_INVALID);
+
+ sa_mutex_lock(s->mutex);
+
+ if ((ret = sa_proplist_merge(&merged, s->props, p)) < 0)
+ goto finish;
+
+ ret = s->state == SA_STATE_INIT ? SA_SUCCESS : driver_change_props(s, p, merged);
+
+ if (ret == SA_SUCCESS) {
+ sa_assert_se(sa_proplist_destroy(s->props) == SA_SUCCESS);
+ s->props = merged;
+ } else
+ sa_assert_se(sa_proplist_destroy(merged) == SA_SUCCESS);
+
+finish:
+
+ sa_mutex_unlock(s->mutex);
+
+ return ret;
+}
+
+int sa_stream_change_user_data(sa_stream *s, const void *value) {
sa_return_val_if_fail(s->mutex, SA_ERROR_INVALID);
sa_mutex_lock(s->mutex);
@@ -491,11 +633,12 @@ int sa_stream_change_user_data(sa_stream_t *s, const void *value) {
return SA_SUCCESS;
}
-int sa_stream_set_adjust_rate(sa_stream_t *s, sa_adjust_t direction) {
+int sa_stream_set_adjust_rate(sa_stream *s, sa_adjust_t direction) {
sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(!s->codec, SA_ERROR_STATE);
+
sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE);
- sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_INIT, SA_ERROR_STATE);
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_INIT, SA_ERROR_STATE, s->mutex);
s->adjust_rate = direction;
@@ -503,11 +646,12 @@ int sa_stream_set_adjust_rate(sa_stream_t *s, sa_adjust_t direction) {
return SA_SUCCESS;
}
-int sa_stream_set_adjust_nchannels(sa_stream_t *s, sa_adjust_t direction) {
+int sa_stream_set_adjust_nchannels(sa_stream *s, sa_adjust_t direction) {
sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(!s->codec, SA_ERROR_STATE);
+
sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE);
- sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_INIT, SA_ERROR_STATE);
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_INIT, SA_ERROR_STATE, s->mutex);
s->adjust_rate = direction;
@@ -515,11 +659,12 @@ int sa_stream_set_adjust_nchannels(sa_stream_t *s, sa_adjust_t direction) {
return SA_SUCCESS;
}
-int sa_stream_set_adjust_pcm_format(sa_stream_t *s, sa_adjust_t direction) {
+int sa_stream_set_adjust_pcm_format(sa_stream *s, sa_adjust_t direction) {
sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(!s->codec, SA_ERROR_STATE);
+
sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE);
- sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_INIT, SA_ERROR_STATE);
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_INIT, SA_ERROR_STATE, s->mutex);
s->adjust_pcm_format = direction;
@@ -527,22 +672,12 @@ int sa_stream_set_adjust_pcm_format(sa_stream_t *s, sa_adjust_t direction) {
return SA_SUCCESS;
}
-/* int sa_stream_set_adjust_watermarks(sa_stream_t *s, sa_adjust_t direction) { */
-/* sa_return_val_if_fail(s, SA_ERROR_INVALID); */
-/* sa_mutex_lock(s->mutex); */
-/* sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_INIT, SA_ERROR_STATE); */
-
-/* s->adjust_watermarks = direction; */
-
-/* sa_mutex_unlock(s->mutex); */
-/* return SA_SUCCESS; */
-/* } */
-
-int sa_stream_get_state(sa_stream_t *s, sa_state_t *state) {
+int sa_stream_get_state(sa_stream *s, sa_state_t *state) {
int ret;
sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(state, SA_ERROR_INVALID);
+
sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, state, SA_ERROR_INVALID);
if (s->state == SA_STATE_INIT) {
*state = s->state;
@@ -554,508 +689,713 @@ int sa_stream_get_state(sa_stream_t *s, sa_state_t *state) {
return ret;
}
-int sa_stream_get_rate(sa_stream_t *s, unsigned *rate) {
+int sa_stream_get_pcm_rate(sa_stream *s, unsigned *rate) {
sa_return_val_if_fail(s, SA_ERROR_INVALID);
sa_return_val_if_fail(rate, SA_ERROR_INVALID);
- sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE);
+ sa_return_val_if_fail(!s->codec, SA_ERROR_STATE);
+ sa_mutex_lock(s->mutex);
*rate = s->pcm_attrs.rate;
-
sa_mutex_unlock(s->mutex);
+
return SA_SUCCESS;
}
-int sa_stream_get_nchannels(sa_stream_t *s, int *nchannels) {
+int sa_stream_get_pcm_nchannels(sa_stream *s, unsigned *nchannels) {
sa_return_val_if_fail(s, SA_ERROR_INVALID);
sa_return_val_if_fail(nchannels, SA_ERROR_INVALID);
- sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE);
+ sa_return_val_if_fail(!s->codec, SA_ERROR_STATE);
+ /* No locking necessary since we only touch immutable fields here */
*nchannels = s->pcm_attrs.nchannels;
- sa_mutex_unlock(s->mutex);
return SA_SUCCESS;
}
-int sa_stream_get_pcm_format(sa_stream_t *s, sa_pcm_format_t *pcm_format) {
+int sa_stream_get_pcm_format(sa_stream *s, sa_pcm_format_t *pcm_format) {
sa_return_val_if_fail(s, SA_ERROR_INVALID);
sa_return_val_if_fail(pcm_format, SA_ERROR_INVALID);
- sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE);
+ sa_return_val_if_fail(!s->codec, SA_ERROR_STATE);
+ /* No locking necessary since we only touch immutable fields here */
*pcm_format = s->pcm_attrs.format;
- sa_mutex_unlock(s->mutex);
+
return SA_SUCCESS;
}
-int sa_stream_get_mode(sa_stream_t *s, sa_mode_t *access_mode) {
+int sa_stream_get_mode(sa_stream *s, sa_mode_t *access_mode) {
sa_return_val_if_fail(s, SA_ERROR_INVALID);
sa_return_val_if_fail(access_mode, SA_ERROR_INVALID);
- sa_mutex_lock(s->mutex);
+ /* No locking necessary since we only touch immutable fields here */
*access_mode = s->mode;
- sa_mutex_unlock(s->mutex);
+
return SA_SUCCESS;
}
-int sa_stream_get_codec(sa_stream_t *s, char *codec, size_t *size) {
- size_t n;
+int sa_stream_get_codec(sa_stream *s, char **codec) {
+ char *t;
sa_return_val_if_fail(s, SA_ERROR_INVALID);
- sa_return_val_if_fail(size && (*size == 0 || codec), SA_ERROR_INVALID);
+ sa_return_val_if_fail(codec, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->codec, SA_ERROR_STATE);
+
+ /* No locking necessary since we only touch immutable fields here */
+ if (!(t = sa_strdup(s->codec)))
+ return SA_ERROR_OOM;
+
+ *codec = t;
+ return SA_SUCCESS;
+}
+
+int sa_stream_get_write_latency(sa_stream *s, size_t *nbytes) {
+ size_t latency, process_time;
+ int ret;
+
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(nbytes, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->mode & SA_MODE_WRONLY, SA_ERROR_STATE);
+
sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, s->codec, SA_ERROR_STATE);
- n = strlen(s->codec)+1;
- if (*size < n) {
- sa_mutex_unlock(s->mutex);
- return SA_ERROR_NO_SPACE;
- }
+ latency = s->write_latency;
+ process_time = s->write_process_time;
- if (codec)
- strcpy(codec, s->codec);
- *size = n;
+ /* In case the latency is not fixated yet, we calculate what it
+ * would be fixated to */
+ if ((ret = fix_latency(s, &latency, &process_time)) < 0)
+ goto fail;
+
+ *nbytes = latency;
+ ret = SA_SUCCESS;
+
+fail:
sa_mutex_unlock(s->mutex);
- return SA_SUCCESS;
+ return ret;
+}
+
+int sa_stream_get_read_latency(sa_stream *s, size_t *nbytes) {
+ size_t latency, process_time;
+ int ret;
+
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(nbytes, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->mode & SA_MODE_WRONLY, SA_ERROR_STATE);
+
+ sa_mutex_lock(s->mutex);
+
+ latency = s->read_latency;
+ process_time = s->read_process_time;
+
+ /* In case the latency is not fixated yet, we calculate what it
+ * would be fixated to */
+
+ if ((ret = fix_latency(s, &latency, &process_time)) < 0)
+ goto fail;
+
+ *nbytes = latency;
+ ret = SA_SUCCESS;
+
+fail:
+ sa_mutex_unlock(s->mutex);
+ return ret;
}
-/* int sa_stream_get_write_lower_watermark(sa_stream_t *s, size_t *size) { */
-/* sa_return_val_if_fail(s, SA_ERROR_INVALID); */
-/* sa_return_val_if_fail(size, SA_ERROR_INVALID); */
-/* sa_mutex_lock(s->mutex); */
-/* sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_WRONLY, SA_ERROR_STATE); */
+int sa_stream_get_write_process_time(sa_stream *s, size_t *nbytes) {
+ size_t latency, process_time;
+ int ret;
+
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(nbytes, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->mode & SA_MODE_WRONLY, SA_ERROR_STATE);
+
+ sa_mutex_lock(s->mutex);
+
+ latency = s->write_latency;
+ process_time = s->write_process_time;
+
+ /* In case the latency is not fixated yet, we calculate what it
+ * would be fixated to */
+
+ if ((ret = fix_latency(s, &latency, &process_time)) < 0)
+ goto fail;
-/* *size = s->write_lower_watermark; */
+ *nbytes = process_time;
+ ret = SA_SUCCESS;
-/* sa_mutex_unlock(s->mutex); */
-/* return SA_SUCCESS; */
-/* } */
+fail:
+ sa_mutex_unlock(s->mutex);
+ return ret;
+}
-/* int sa_stream_get_read_lower_watermark(sa_stream_t *s, size_t *size) { */
-/* sa_return_val_if_fail(s, SA_ERROR_INVALID); */
-/* sa_return_val_if_fail(size, SA_ERROR_INVALID); */
-/* sa_mutex_lock(s->mutex); */
-/* sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_RDONLY, SA_ERROR_STATE); */
+int sa_stream_get_read_process_time(sa_stream *s, size_t *nbytes) {
+ size_t latency, process_time;
+ int ret;
-/* *size = s->read_lower_watermark; */
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(nbytes, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->mode & SA_MODE_WRONLY, SA_ERROR_STATE);
-/* sa_mutex_unlock(s->mutex); */
-/* return SA_SUCCESS; */
-/* } */
+ sa_mutex_lock(s->mutex);
-/* int sa_stream_get_write_upper_watermark(sa_stream_t *s, size_t *size) { */
-/* sa_return_val_if_fail(s, SA_ERROR_INVALID); */
-/* sa_return_val_if_fail(size, SA_ERROR_INVALID); */
-/* sa_mutex_lock(s->mutex); */
-/* sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_WRONLY, SA_ERROR_STATE); */
+ latency = s->read_latency;
+ process_time = s->read_process_time;
-/* *size = s->write_upper_watermark; */
+ /* In case the latency is not fixated yet, we calculate what it
+ * would be fixated to */
-/* sa_mutex_unlock(s->mutex); */
-/* return SA_SUCCESS; */
-/* } */
+ if ((ret = fix_latency(s, &latency, &process_time)) < 0)
+ goto fail;
-/* int sa_stream_get_read_upper_watermark(sa_stream_t *s, size_t *size) { */
-/* sa_return_val_if_fail(s, SA_ERROR_INVALID); */
-/* sa_return_val_if_fail(size, SA_ERROR_INVALID); */
-/* sa_mutex_lock(s->mutex); */
-/* sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_RDONLY, SA_ERROR_STATE); */
+ *nbytes = process_time;
+ ret = SA_SUCCESS;
-/* *size = s->read_upper_watermark; */
+fail:
+ sa_mutex_unlock(s->mutex);
+ return ret;
+}
-/* sa_mutex_unlock(s->mutex); */
-/* return SA_SUCCESS; */
-/* } */
+int sa_stream_get_pcm_channel_map(sa_stream *s, sa_channel_t **map, unsigned *n) {
+ sa_channel_t *m;
+ int ret;
-int sa_stream_get_channel_map(sa_stream_t *s, sa_channel_t *map, unsigned *n) {
sa_return_val_if_fail(s, SA_ERROR_INVALID);
- sa_return_val_if_fail(n && (*n == 0 || map), SA_ERROR_INVALID);
+ sa_return_val_if_fail(map, SA_ERROR_INVALID);
+ sa_return_val_if_fail(n, SA_ERROR_INVALID);
+ sa_return_val_if_fail(!s->codec, SA_ERROR_STATE);
+
sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE);
- if (*n < s->pcm_attrs.nchannels) {
- sa_mutex_unlock(s->mutex);
- return SA_ERROR_NO_SPACE;
+ if (!(m = sa_newdup(sa_channel_t, s->pcm_attrs.channel_map, s->pcm_attrs.nchannels))) {
+ ret = SA_ERROR_OOM;
+ goto fail;
}
- if (map)
- memcpy(map, s->pcm_attrs.channel_map, s->pcm_attrs.nchannels * sizeof(sa_channel_t));
+ *map = m;
*n = s->pcm_attrs.nchannels;
+ ret = SA_SUCCESS;
+fail:
sa_mutex_unlock(s->mutex);
- return SA_SUCCESS;
+ return ret;
}
-int sa_stream_get_xrun_mode(sa_stream_t *s, sa_xrun_mode_t *mode) {
+int sa_stream_get_xrun_mode(sa_stream *s, sa_xrun_mode_t *mode) {
sa_return_val_if_fail(s, SA_ERROR_INVALID);
sa_return_val_if_fail(mode, SA_ERROR_INVALID);
- sa_mutex_lock(s->mutex);
+ sa_mutex_lock(s->mutex);
*mode = s->xrun_mode;
-
sa_mutex_unlock(s->mutex);
+
return SA_SUCCESS;
}
-int sa_stream_get_non_interleaved(sa_stream_t *s, int *enabled) {
+int sa_stream_get_non_interleaved(sa_stream *s, int *enabled) {
sa_return_val_if_fail(s, SA_ERROR_INVALID);
sa_return_val_if_fail(enabled, SA_ERROR_INVALID);
- sa_mutex_lock(s->mutex);
+ sa_mutex_lock(s->mutex);
*enabled = s->ni_enabled;
-
sa_mutex_unlock(s->mutex);
+
return SA_SUCCESS;
}
-int sa_stream_get_dynamic_rate(sa_stream_t *s, int *enabled) {
+int sa_stream_get_dynamic_pcm_rate(sa_stream *s, int *enabled) {
sa_return_val_if_fail(s, SA_ERROR_INVALID);
sa_return_val_if_fail(enabled, SA_ERROR_INVALID);
- sa_mutex_lock(s->mutex);
+ sa_mutex_lock(s->mutex);
*enabled = s->dynamic_rate_enabled;
-
sa_mutex_unlock(s->mutex);
+
return SA_SUCCESS;
}
-int sa_stream_get_driver(sa_stream_t *s, char *driver, size_t *size) {
- size_t n;
+int sa_stream_get_driver(sa_stream *s, char **driver) {
+ char *t;
+ int ret;
sa_return_val_if_fail(s, SA_ERROR_INVALID);
- sa_return_val_if_fail(size && (*size == 0 || driver), SA_ERROR_INVALID);
+ sa_return_val_if_fail(driver, SA_ERROR_INVALID);
+
sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, s->driver, SA_ERROR_STATE);
- n = strlen(s->driver)+1;
- if (*size < n) {
- sa_mutex_unlock(s->mutex);
- return SA_ERROR_NO_SPACE;
+ sa_return_val_if_fail_unlock(s->driver, SA_ERROR_STATE, s->mutex);
+
+ if (!(t = sa_strdup(s->driver))) {
+ ret = SA_ERROR_OOM;
+ goto fail;
}
- if (driver)
- strcpy(driver, s->driver);
- *size = n;
+ *driver = t;
+ ret = SA_SUCCESS;
+fail:
sa_mutex_unlock(s->mutex);
- return SA_SUCCESS;
+
+ return ret;
}
-int sa_stream_get_device(sa_stream_t *s, char *device, size_t *size) {
- size_t n;
+int sa_stream_get_device(sa_stream *s, char **device) {
+ char *t;
+ int ret;
sa_return_val_if_fail(s, SA_ERROR_INVALID);
- sa_return_val_if_fail(size && (*size == 0 || device), SA_ERROR_INVALID);
+ sa_return_val_if_fail(device, SA_ERROR_INVALID);
+
sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, s->device, SA_ERROR_STATE);
- n = strlen(s->device)+1;
- if (*size < n) {
- sa_mutex_unlock(s->mutex);
- return SA_ERROR_NO_SPACE;
+ sa_return_val_if_fail_unlock(s->device, SA_ERROR_STATE, s->mutex);
+
+ if (!(t = sa_strdup(s->device))) {
+ ret = SA_ERROR_OOM;
+ goto fail;
}
- if (device)
- strcpy(device, s->device);
- *size = n;
+ *device = t;
+ ret = SA_SUCCESS;
+fail:
sa_mutex_unlock(s->mutex);
- return SA_SUCCESS;
+
+ return ret;
}
-int sa_stream_get_read_volume(sa_stream_t *s, int32_t vol[], unsigned *n) {
+int sa_stream_get_read_volume(sa_stream *s, int32_t **vol, unsigned *n) {
+ int32_t *v;
+ int ret;
+
sa_return_val_if_fail(s, SA_ERROR_INVALID);
- sa_return_val_if_fail(n && (*n == 0 || vol), SA_ERROR_INVALID);
+ sa_return_val_if_fail(vol, SA_ERROR_INVALID);
+ sa_return_val_if_fail(n, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->mode & SA_MODE_RDONLY, SA_ERROR_STATE);
+
sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_RDONLY, SA_ERROR_STATE);
- sa_return_val_if_fail_mutex(s->mutex, s->read_volume, SA_ERROR_STATE);
- if (*n < s->pcm_attrs.nchannels) {
- sa_mutex_unlock(s->mutex);
- return SA_ERROR_NO_SPACE;
+ sa_return_val_if_fail_unlock(s->read_volume, SA_ERROR_STATE, s->mutex);
+
+ if (!(v = sa_newdup(int32_t, s->read_volume, s->pcm_attrs.nchannels))) {
+ ret = SA_ERROR_OOM;
+ goto fail;
}
- if (vol)
- memcpy(vol, s->read_volume, s->pcm_attrs.nchannels * sizeof(int32_t));
+ *vol = v;
*n = s->pcm_attrs.nchannels;
+ ret = SA_SUCCESS;
+fail:
sa_mutex_unlock(s->mutex);
- return SA_SUCCESS;
+ return ret;
}
-int sa_stream_get_write_volume(sa_stream_t *s, int32_t vol[], unsigned *n) {
+int sa_stream_get_write_volume(sa_stream *s, int32_t **vol, unsigned *n) {
+ int32_t *v;
+ int ret;
+
sa_return_val_if_fail(s, SA_ERROR_INVALID);
- sa_return_val_if_fail(n && (*n == 0 || vol), SA_ERROR_INVALID);
+ sa_return_val_if_fail(vol, SA_ERROR_INVALID);
+ sa_return_val_if_fail(n, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->mode & SA_MODE_WRONLY, SA_ERROR_STATE);
+
sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_WRONLY, SA_ERROR_STATE);
- sa_return_val_if_fail_mutex(s->mutex, s->write_volume, SA_ERROR_STATE);
- if (*n < s->pcm_attrs.nchannels) {
- sa_mutex_unlock(s->mutex);
- return SA_ERROR_NO_SPACE;
+ sa_return_val_if_fail_unlock(s->write_volume, SA_ERROR_STATE, s->mutex);
+
+ if (!(v = sa_newdup(int32_t, s->write_volume, s->pcm_attrs.nchannels))) {
+ ret = SA_ERROR_OOM;
+ goto fail;
}
- if (vol)
- memcpy(vol, s->write_volume, s->pcm_attrs.nchannels * sizeof(int32_t));
+ *vol = v;
*n = s->pcm_attrs.nchannels;
+ ret = SA_SUCCESS;
+fail:
sa_mutex_unlock(s->mutex);
- return SA_SUCCESS;
+ return ret;
}
-int sa_stream_get_adjust_rate(sa_stream_t *s, sa_adjust_t *direction) {
+int sa_stream_get_adjust_pcm_rate(sa_stream *s, sa_adjust_t *direction) {
sa_return_val_if_fail(s, SA_ERROR_INVALID);
sa_return_val_if_fail(direction, SA_ERROR_INVALID);
- sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE);
+ sa_return_val_if_fail(!s->codec, SA_ERROR_STATE);
+ sa_mutex_lock(s->mutex);
*direction = s->adjust_rate;
-
sa_mutex_unlock(s->mutex);
+
return SA_SUCCESS;
}
-int sa_stream_get_adjust_nchannels(sa_stream_t *s, sa_adjust_t *direction) {
+int sa_stream_get_adjust_pcm_nchannels(sa_stream *s, sa_adjust_t *direction) {
sa_return_val_if_fail(s, SA_ERROR_INVALID);
sa_return_val_if_fail(direction, SA_ERROR_INVALID);
- sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE);
+ sa_return_val_if_fail(!s->codec, SA_ERROR_STATE);
+ sa_mutex_lock(s->mutex);
*direction = s->adjust_nchannels;
-
sa_mutex_unlock(s->mutex);
+
return SA_SUCCESS;
}
-int sa_stream_get_adjust_pcm_format(sa_stream_t *s, sa_adjust_t *direction) {
+int sa_stream_get_adjust_pcm_format(sa_stream *s, sa_adjust_t *direction) {
sa_return_val_if_fail(s, SA_ERROR_INVALID);
sa_return_val_if_fail(direction, SA_ERROR_INVALID);
- sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE);
+ sa_return_val_if_fail(!s->codec, SA_ERROR_STATE);
+ sa_mutex_lock(s->mutex);
*direction = s->adjust_pcm_format;
-
sa_mutex_unlock(s->mutex);
+
return SA_SUCCESS;
}
-/* int sa_stream_get_adjust_watermarks(sa_stream_t *s, sa_adjust_t *direction) { */
-/* sa_return_val_if_fail_mutex(s->mutex, s, SA_ERROR_INVALID); */
-/* sa_return_val_if_fail_mutex(s->mutex, direction, SA_ERROR_INVALID); */
-/* sa_mutex_lock(s->mutex); */
-
-/* *direction = s->adjust_watermarks; */
-
-/* sa_mutex_unlock(s->mutex); */
-/* return SA_SUCCESS; */
-/* } */
-
-int sa_stream_get_user_data(sa_stream_t *s, void **value) {
+int sa_stream_get_user_data(sa_stream *s, void **value) {
sa_return_val_if_fail(s, SA_ERROR_INVALID);
sa_return_val_if_fail(value, SA_ERROR_INVALID);
- sa_mutex_lock(s->mutex);
+ sa_mutex_lock(s->mutex);
*value = s->user_data;
-
sa_mutex_unlock(s->mutex);
+
return SA_SUCCESS;
}
-int sa_stream_get_event_error(sa_stream_t *s, sa_error_t *error) {
+int sa_stream_get_event_error(sa_stream *s, int *error) {
+ int ret;
+
sa_return_val_if_fail(s, SA_ERROR_INVALID);
sa_return_val_if_fail(error, SA_ERROR_INVALID);
+
sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, s->event == SA_EVENT_ERROR, SA_ERROR_STATE);
+
+ if ((ret = stream_open_unlocked(s)) < 0)
+ goto fail;
+
+ sa_return_val_if_fail_unlock(s->event == SA_EVENT_ERROR, SA_ERROR_STATE, s->mutex);
*error = s->error;
+fail:
sa_mutex_unlock(s->mutex);
+
return SA_SUCCESS;
}
-int sa_stream_get_event_notify(sa_stream_t *s, sa_notify_t *notify) {
+int sa_stream_get_event_notify(sa_stream *s, sa_notify_t *notify, void **data, size_t *data_nbytes) {
+ int ret;
+
sa_return_val_if_fail(s, SA_ERROR_INVALID);
sa_return_val_if_fail(notify, SA_ERROR_INVALID);
+
sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, s->event == SA_EVENT_NOTIFY, SA_ERROR_STATE);
+
+ if ((ret = stream_open_unlocked(s)) < 0)
+ goto fail;
+
+ sa_return_val_if_fail_unlock(s->event == SA_EVENT_NOTIFY, SA_ERROR_STATE, s->mutex);
+
+ if (data && s->notify_data) {
+
+ if (s->notify_data_nbytes > 0) {
+ void *d;
+
+ if (!(d = sa_memdup(s->notify_data, s->notify_data_nbytes))) {
+ ret = SA_ERROR_OOM;
+ goto fail;
+ }
+
+ *data = d;
+ } else
+ *data = s->notify_data;
+ }
+
+ if (data_nbytes && s->notify_data_nbytes)
+ *data_nbytes = s->notify_data_nbytes;
*notify = s->notify;
+ ret = SA_SUCCESS;
+fail:
sa_mutex_unlock(s->mutex);
- return SA_SUCCESS;
+ return ret;
}
-int sa_stream_get_position(sa_stream_t *s, sa_position_t position, int64_t *pos) {
+int sa_stream_get_position(sa_stream *s, sa_position_t position, int64_t *pos) {
int ret;
sa_return_val_if_fail(s, SA_ERROR_INVALID);
sa_return_val_if_fail(pos, SA_ERROR_INVALID);
sa_return_val_if_fail(position < _SA_POSITION_MAX, SA_ERROR_INVALID);
+
sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE);
+
+ if ((ret = stream_open_unlocked(s)) < 0)
+ goto fail;
+
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE, s->mutex);
ret = driver_get_position(s, position, pos);
+fail:
+ sa_mutex_unlock(s->mutex);
+
+ return ret;
+}
+
+int sa_stream_wait(sa_stream *s, sa_event_t *event) {
+ int ret;
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(event, SA_ERROR_INVALID);
+
+ sa_mutex_lock(s->mutex);
+
+ sa_return_val_if_fail_unlock(!s->callback, SA_ERROR_STATE, s->mutex);
+
+ if ((ret = stream_open_unlocked(s)) < 0)
+ goto fail;
+
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE, s->mutex);
+
+ ret = driver_wait(s);
+
+ if (ret == SA_SUCCESS)
+ *event = s->event;
+
+fail:
sa_mutex_unlock(s->mutex);
+
return ret;
}
-int sa_stream_read(sa_stream_t *s, void *data, size_t nbytes) {
+int sa_stream_read(sa_stream *s, void *data, size_t nbytes) {
int ret;
sa_return_val_if_fail(s, SA_ERROR_INVALID);
sa_return_val_if_fail(data, SA_ERROR_INVALID);
sa_return_val_if_fail(nbytes > 0, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->codec || sa_stream_frame_aligned(s, (int64_t) nbytes), SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->mode & SA_MODE_RDONLY, SA_ERROR_STATE);
+
sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, !s->ni_enabled, SA_ERROR_STATE);
- sa_return_val_if_fail_mutex(s->mutex, s->codec || (nbytes % s->pcm_frame_size) == 0, SA_ERROR_INVALID);
- sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_RDONLY, SA_ERROR_STATE);
- sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE);
+
+ sa_return_val_if_fail_unlock(!s->ni_enabled, SA_ERROR_STATE, s->mutex);
+
+ if ((ret = stream_open_unlocked(s)) < 0)
+ goto fail;
+
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE, s->mutex);
ret = driver_read(s, data, nbytes);
+fail:
sa_mutex_unlock(s->mutex);
+
return ret;
}
-int sa_stream_read_ni(sa_stream_t *s, unsigned channel, void *data, size_t nbytes) {
+int sa_stream_read_ni(sa_stream *s, unsigned channel, void *data, size_t nbytes) {
int ret;
sa_return_val_if_fail(s, SA_ERROR_INVALID);
sa_return_val_if_fail(data, SA_ERROR_INVALID);
sa_return_val_if_fail(nbytes > 0, SA_ERROR_INVALID);
+ sa_return_val_if_fail(!s->codec, SA_ERROR_STATE);
+ sa_return_val_if_fail(channel < s->pcm_attrs.nchannels, SA_ERROR_INVALID);
+ sa_return_val_if_fail(sa_stream_frame_aligned(s, (int64_t) nbytes), SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->mode & SA_MODE_RDONLY, SA_ERROR_STATE);
+
sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE);
- sa_return_val_if_fail_mutex(s->mutex, channel < s->pcm_attrs.nchannels, SA_ERROR_INVALID);
- sa_return_val_if_fail_mutex(s->mutex, s->ni_enabled, SA_ERROR_STATE);
- sa_return_val_if_fail_mutex(s->mutex, (nbytes % s->pcm_sample_size) == 0, SA_ERROR_INVALID);
- sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_RDONLY, SA_ERROR_STATE);
- sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE);
+
+ sa_return_val_if_fail_unlock(s->ni_enabled, SA_ERROR_STATE, s->mutex);
+
+ if ((ret = stream_open_unlocked(s)) < 0)
+ goto fail;
+
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE, s->mutex);
ret = driver_read_ni(s, channel, data, nbytes);
+fail:
sa_mutex_unlock(s->mutex);
+
return ret;
}
-int sa_stream_write(sa_stream_t *s, const void *data, size_t nbytes) {
+int sa_stream_write(sa_stream *s, const void *data, size_t nbytes) {
return sa_stream_pwrite(s, data, nbytes, 0, SA_SEEK_RELATIVE);
}
-int sa_stream_write_ni(sa_stream_t *s, unsigned channel, const void *data, size_t nbytes) {
+int sa_stream_write_ni(sa_stream *s, unsigned channel, const void *data, size_t nbytes) {
return sa_stream_pwrite_ni(s, channel, data, nbytes, 0, SA_SEEK_RELATIVE);
}
-int sa_stream_pwrite(sa_stream_t *s, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence) {
+int sa_stream_pwrite(sa_stream *s, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence) {
int ret;
sa_return_val_if_fail(s, SA_ERROR_INVALID);
sa_return_val_if_fail(data, SA_ERROR_INVALID);
sa_return_val_if_fail(nbytes > 0, SA_ERROR_INVALID);
sa_return_val_if_fail(whence == SA_SEEK_RELATIVE || whence == SA_SEEK_ABSOLUTE || whence == SA_SEEK_RELATIVE_END, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->codec || sa_stream_frame_aligned(s, (int64_t) nbytes), SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->codec || sa_stream_frame_aligned(s, (int64_t) offset), SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->mode & SA_MODE_WRONLY, SA_ERROR_STATE);
+
sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, !s->ni_enabled, SA_ERROR_STATE);
- sa_return_val_if_fail_mutex(s->mutex, s->codec || (nbytes % s->pcm_frame_size) == 0, SA_ERROR_INVALID);
- sa_return_val_if_fail_mutex(s->mutex, s->codec || (offset % s->pcm_frame_size) == 0, SA_ERROR_INVALID);
- sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_WRONLY, SA_ERROR_STATE);
- sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE);
+
+ sa_return_val_if_fail_unlock(!s->ni_enabled, SA_ERROR_STATE, s->mutex);
+
+ if ((ret = stream_open_unlocked(s)) < 0)
+ goto fail;
+
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE, s->mutex);
ret = driver_pwrite(s, data, nbytes, offset, whence);
+fail:
sa_mutex_unlock(s->mutex);
+
return ret;
}
-int sa_stream_pwrite_ni(sa_stream_t *s, unsigned channel, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence) {
+int sa_stream_pwrite_ni(sa_stream *s, unsigned channel, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence) {
int ret;
sa_return_val_if_fail(s, SA_ERROR_INVALID);
sa_return_val_if_fail(data, SA_ERROR_INVALID);
sa_return_val_if_fail(nbytes > 0, SA_ERROR_INVALID);
sa_return_val_if_fail(whence == SA_SEEK_RELATIVE || whence == SA_SEEK_ABSOLUTE || whence == SA_SEEK_RELATIVE_END, SA_ERROR_INVALID);
+ sa_return_val_if_fail(!s->codec, SA_ERROR_STATE);
+ sa_return_val_if_fail(channel < s->pcm_attrs.nchannels, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->codec || sa_stream_frame_aligned(s, (int64_t) nbytes), SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->codec || sa_stream_frame_aligned(s, (int64_t) offset), SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->mode & SA_MODE_WRONLY, SA_ERROR_STATE);
+
sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, !s->codec, SA_ERROR_STATE);
- sa_return_val_if_fail_mutex(s->mutex, channel < s->pcm_attrs.nchannels, SA_ERROR_INVALID);
- sa_return_val_if_fail_mutex(s->mutex, s->ni_enabled, SA_ERROR_STATE);
- sa_return_val_if_fail_mutex(s->mutex, (nbytes % s->pcm_sample_size) == 0, SA_ERROR_INVALID);
- sa_return_val_if_fail_mutex(s->mutex, (offset % s->pcm_sample_size) == 0, SA_ERROR_INVALID);
- sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_WRONLY, SA_ERROR_STATE);
- sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE);
+
+ sa_return_val_if_fail_unlock(s->ni_enabled, SA_ERROR_STATE, s->mutex);
+
+ if ((ret = stream_open_unlocked(s)) < 0)
+ goto fail;
+
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE, s->mutex);
ret = driver_pwrite_ni(s, channel, data, nbytes, offset, whence);
+fail:
sa_mutex_unlock(s->mutex);
+
return ret;
}
-int sa_stream_get_read_size(sa_stream_t *s, size_t *size) {
+int sa_stream_get_read_size(sa_stream *s, size_t *nbytes) {
int ret;
sa_return_val_if_fail(s, SA_ERROR_INVALID);
- sa_return_val_if_fail(size, SA_ERROR_INVALID);
+ sa_return_val_if_fail(nbytes, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->mode & SA_MODE_RDONLY, SA_ERROR_STATE);
+
sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_RDONLY, SA_ERROR_STATE);
- sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE);
- ret = driver_get_read_size(s, size);
+ if ((ret = stream_open_unlocked(s)) < 0)
+ goto fail;
+
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE, s->mutex);
+
+ ret = driver_get_read_size(s, nbytes);
+fail:
sa_mutex_unlock(s->mutex);
+
return ret;
}
-int sa_stream_get_write_size(sa_stream_t *s, size_t *size) {
+int sa_stream_get_write_size(sa_stream *s, size_t *nbytes) {
int ret;
sa_return_val_if_fail(s, SA_ERROR_INVALID);
- sa_return_val_if_fail(size, SA_ERROR_INVALID);
+ sa_return_val_if_fail(nbytes, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->mode & SA_MODE_WRONLY, SA_ERROR_STATE);
+
sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_WRONLY, SA_ERROR_STATE);
- sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE);
- ret = driver_get_write_size(s, size);
+ if ((ret = stream_open_unlocked(s)) < 0)
+ goto fail;
+
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE, s->mutex);
+
+ ret = driver_get_write_size(s, nbytes);
+fail:
sa_mutex_unlock(s->mutex);
+
return ret;
}
-int sa_stream_resume(sa_stream_t *s) {
+int sa_stream_start(sa_stream *s) {
int ret;
sa_return_val_if_fail(s, SA_ERROR_INVALID);
+
sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE);
+
+ if ((ret = stream_open_unlocked(s)) < 0)
+ goto fail;
+
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE, s->mutex);
ret = driver_resume(s);
+fail:
sa_mutex_unlock(s->mutex);
+
return ret;
}
-int sa_stream_pause(sa_stream_t *s) {
+int sa_stream_stop(sa_stream *s) {
int ret;
sa_return_val_if_fail(s, SA_ERROR_INVALID);
+
sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE);
+
+ if ((ret = stream_open_unlocked(s)) < 0)
+ goto fail;
+
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE, s->mutex);
ret = driver_pause(s);
+fail:
sa_mutex_unlock(s->mutex);
+
return ret;
}
-int sa_stream_drain(sa_stream_t *s) {
+int sa_stream_drain(sa_stream *s) {
int ret;
sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->mode & SA_MODE_WRONLY, SA_ERROR_STATE);
+
sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, s->mode & SA_MODE_WRONLY, SA_ERROR_STATE);
- sa_return_val_if_fail_mutex(s->mutex, s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE);
+
+ sa_return_val_if_fail_unlock(!s->callback, SA_ERROR_STATE, s->mutex);
+
+ if ((ret = stream_open_unlocked(s)) < 0)
+ goto fail;
+
+ sa_return_val_if_fail_unlock(s->state == SA_STATE_RUNNING || s->state == SA_STATE_STOPPED, SA_ERROR_STATE, s->mutex);
ret = driver_drain(s);
+fail:
+
sa_mutex_unlock(s->mutex);
+
return ret;
}
@@ -1088,184 +1428,148 @@ size_t sa_get_pcm_sample_size(sa_pcm_format_t f) {
sa_assert_not_reached();
}
-static int meta_check_png(const void *data, size_t size) {
- static const uint8_t png_signature[] = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A };
- sa_assert(data);
+const char *sa_strerror(int code) {
+ const char * const error_table[-_SA_ERROR_MAX] = {
+ [-SA_SUCCESS] = "Success",
+ [-SA_ERROR_NOTSUPPORTED] = "Operation not supported",
+ [-SA_ERROR_INVALID] = "Invalid argument",
+ [-SA_ERROR_STATE] = "Invalid state",
+ [-SA_ERROR_OOM] = "Out of memory",
+ [-SA_ERROR_NODRIVER] = "No such driver",
+ [-SA_ERROR_SYSTEM] = "System error",
+ [-SA_ERROR_CORRUPT] = "File or data corrupt",
+ [-SA_ERROR_TOOBIG] = "File or data too large",
+ [-SA_ERROR_NOTFOUND] = "File or data not found",
+ [-SA_ERROR_DESTROYED] = "Destroyed",
+ [-SA_ERROR_CANCELED] = "Canceled",
+ [-SA_ERROR_NOTAVAILABLE] = "Not available",
+ [-SA_ERROR_ACCESS] = "Acess forbidden",
+ [-SA_ERROR_IO] = "IO error",
+ [-SA_ERROR_INTERNAL] = "Internal error",
+ [-SA_ERROR_DISABLED] = "Sound disabled",
+ [-SA_ERROR_NODEVICE] = "No such device",
+ [-SA_ERROR_NOCODEC] = "No such codec",
+ [-SA_ERROR_NOPCMFORMAT] = "No such PCM format"
+ };
- if (size < sizeof(png_signature))
- return 0;
+ sa_return_val_if_fail(code <= 0, NULL);
+ sa_return_val_if_fail(code > _SA_ERROR_MAX, NULL);
- return memcmp(data, png_signature, 8) == 0;
+ return error_table[-code];
}
-static int meta_check_utf8(const void *data, size_t size) {
- int32_t idx;
-
- oil_utf8_validate(&idx, data, size);
-
- return (size_t) idx == size;
+float volume_to_dB(int32_t v) {
+ return (float) v / 100.0f;
}
-static int meta_check_pid(const void *data, size_t size) {
- long int pid;
- char *t;
-
- if (size <= 0)
- return 0;
+int32_t volume_from_dB(float dB) {
+ return (int32_t) lrintf(dB * 100.0f);
+}
- if (memchr(data, 0, size))
- return 0;
+float volume_to_linear(int32_t v) {
- if (!(t = sa_strndup(data, size)))
+ if (v <= SA_VOLUME_MUTED)
return 0;
- errno = 0;
- pid = strtol(t, NULL, 10);
- sa_free(t);
+ return powf(10.0f, volume_to_dB(v) / 20.0f);
+}
- if (errno != 0)
- return 0;
+int32_t volume_from_linear(float f) {
- if (pid <= 1)
- return 0;
+ if (f <= 0)
+ return SA_VOLUME_MUTED;
- return 1;
+ return volume_from_dB(20.0f * log10f(f));
}
-static int meta_check_icon_name(const void *data, size_t size) {
- const char *t = data;
+unsigned sa_stream_bytes_to_frames(sa_stream *s, size_t nbytes, sa_bool_t round_up) {
+ sa_return_val_if_fail(s, (unsigned) -1);
+ sa_return_val_if_fail(!s->codec, (unsigned) -1);
- if (size <= 0)
- return 0;
+ /* We don't lock here since the data we access here is immutable */
- if (memchr(data, 0, size))
- return 0;
+ if (round_up)
+ nbytes += s->pcm_frame_size - 1U;
- if (size == 1 && t[0] == '.')
- return 0;
+ return (unsigned) (nbytes / s->pcm_frame_size);
+}
- if (size == 2 && t[0] == '.' && t[1] == '.')
- return 0;
+size_t sa_stream_frames_to_bytes(sa_stream *s, unsigned nframes) {
+ sa_return_val_if_fail(s, (size_t) -1);
+ sa_return_val_if_fail(!s->codec, (size_t) -1);
- if (memchr(t, '/', size))
- return 0;
+ /* We don't lock here since the data we access here is immutable */
- return 1;
+ return (size_t) nframes * s->pcm_frame_size;
}
-static int meta_check_word(const void *data, size_t size) {
- const char *t = data;
+uint64_t sa_stream_bytes_to_usec(sa_stream *s, size_t nbytes, sa_bool_t round_up) {
+ unsigned nframes;
+
+ sa_return_val_if_fail(s, (uint64_t) -1);
+ sa_return_val_if_fail(!s->codec, (uint64_t) -1);
- for (; size > 0; size --, t++)
- if (*t <= 32 || *t >= 127)
- return 0;
+ /* We don't lock here since the data we access here is immutable */
- return 1;
+ nframes = sa_stream_bytes_to_frames(s, nbytes, round_up);
+ return sa_stream_frames_to_usec(s, nframes, round_up);
}
-typedef int (*meta_check_func_t)(const void *data, size_t size);
+size_t sa_stream_usec_to_bytes(sa_stream *s, uint64_t usec, sa_bool_t round_up) {
+ unsigned nframes;
-int sa_stream_change_meta_data(sa_stream_t *s, const char *name, const void *data, size_t size) {
- void *d = NULL;
- const struct meta_name *m;
- int ret;
+ sa_return_val_if_fail(s, (size_t) -1);
+ sa_return_val_if_fail(!s->codec, (size_t) -1);
- static const meta_check_func_t check_table[] = {
- meta_check_utf8,
- meta_check_pid,
- meta_check_word, /* FIXME */
- meta_check_utf8,
- meta_check_icon_name,
- meta_check_png,
- meta_check_word, /* FIXME */
- meta_check_word, /* FIXME */
- };
+ /* We don't lock here since the data we access here is immutable */
- sa_return_val_if_fail(s, SA_ERROR_INVALID);
- sa_return_val_if_fail(name, SA_ERROR_INVALID);
- sa_mutex_lock(s->mutex);
- sa_return_val_if_fail_mutex(s->mutex, data || size == 0, SA_ERROR_INVALID);
+ nframes = sa_stream_usec_to_frames(s, usec, round_up);
+ return sa_stream_frames_to_bytes(s, nframes);
+}
- if (!(m = sa_lookup_meta_name(name, strlen(name)))) {
- sa_mutex_unlock(s->mutex);
- return SA_ERROR_NO_META;
- }
+uint64_t sa_stream_frames_to_usec(sa_stream *s, unsigned nframes, sa_bool_t round_up) {
+ uint64_t u;
+ sa_return_val_if_fail(s, (uint64_t) -1);
+ sa_return_val_if_fail(!s->codec, (uint64_t) -1);
- if (!check_table[m->idx](data, size)) {
- sa_mutex_unlock(s->mutex);
- return SA_ERROR_INVALID;
- }
+ u = (uint64_t) nframes;
+ u *= 1000000LLU;
- if (data)
- if (!(d = sa_memdup(data, size))) {
- sa_mutex_unlock(s->mutex);
- return SA_ERROR_OOM;
- }
+ sa_mutex_lock(s->mutex);
- ret = s->state == SA_STATE_INIT ? SA_SUCCESS : driver_change_meta_data(s, name, data, size);
+ if (round_up)
+ u += (uint64_t) s->pcm_attrs.rate - 1LLU;
- if (ret == SA_SUCCESS) {
- sa_free(s->meta_data[m->idx]);
- s->meta_data[m->idx] = d;
- s->meta_data_size[m->idx] = size;
- } else
- sa_free(d);
+ u /= (uint64_t) s->pcm_attrs.rate;
sa_mutex_unlock(s->mutex);
- return ret;
+
+ return u;
}
-int sa_stream_get_meta_data(sa_stream_t *s, const char *name, void *data, size_t *size) {
- const struct meta_name *m;
+unsigned sa_stream_usec_to_frames(sa_stream *s, uint64_t usec, sa_bool_t round_up) {
+ sa_return_val_if_fail(s, (unsigned) -1);
+ sa_return_val_if_fail(!s->codec, (unsigned) -1);
- sa_return_val_if_fail(s, SA_ERROR_INVALID);
- sa_return_val_if_fail(name, SA_ERROR_INVALID);
- sa_return_val_if_fail(size && (*size == 0 || data), SA_ERROR_INVALID);
sa_mutex_lock(s->mutex);
- if (!(m = sa_lookup_meta_name(name, strlen(name)))) {
- sa_mutex_unlock(s->mutex);
- return SA_ERROR_NO_META;
- }
-
- if (!s->meta_data[m->idx]) {
- sa_mutex_unlock(s->mutex);
- return SA_ERROR_NO_DATA;
- }
+ usec *= (uint64_t) s->pcm_attrs.rate;
- if (*size < s->meta_data_size[m->idx]) {
- sa_mutex_unlock(s->mutex);
- return SA_ERROR_NO_SPACE;
- }
+ sa_mutex_unlock(s->mutex);
- if (data)
- memcpy(data, s->meta_data[m->idx], s->meta_data_size[m->idx]);
+ if (round_up)
+ usec += 999999LLU;
- *size = s->meta_data_size[m->idx];
+ usec /= 1000000LLU;
- sa_mutex_unlock(s->mutex);
- return SA_SUCCESS;
+ return (unsigned) usec;
}
-const char *sa_strerror(int code) {
- const char * const error_table[-_SA_ERROR_MAX] = {
- [-SA_SUCCESS] = "Success",
- [-SA_ERROR_NOT_SUPPORTED] = "Operation not supported",
- [-SA_ERROR_INVALID] = "Invalid argument",
- [-SA_ERROR_STATE] = "Invalid state",
- [-SA_ERROR_OOM] = "Out of memory",
- [-SA_ERROR_NO_DEVICE] = "No such device",
- [-SA_ERROR_NO_DRIVER] = "No such driver",
- [-SA_ERROR_NO_CODEC] = "No such codec",
- [-SA_ERROR_NO_PCM_FORMAT] = "No such PCM format",
- [-SA_ERROR_SYSTEM] = "System error",
- [-SA_ERROR_NO_INIT] = "Not initialized",
- [-SA_ERROR_NO_META] = "No such meta name",
- [-SA_ERROR_NO_DATA] = "No such data"
- };
+sa_bool_t sa_stream_frame_aligned(sa_stream *s, int64_t nbytes) {
+ sa_return_val_if_fail(s, FALSE);
+ sa_return_val_if_fail(!s->codec, FALSE);
- sa_return_val_if_fail(code <= 0, NULL);
- sa_return_val_if_fail(code > _SA_ERROR_MAX, NULL);
+ /* We don't lock here since the data we access here is immutable */
- return error_table[-code];
+ return (nbytes % (int64_t) s->pcm_frame_size) == 0;
}
diff --git a/src/common.h b/src/common.h
index 9d01c44..a89c55f 100644
--- a/src/common.h
+++ b/src/common.h
@@ -1,12 +1,32 @@
#ifndef foosydneycommonh
#define foosydneycommonh
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdarg.h>
+
#include "sydney.h"
#include "mutex.h"
#include "macro.h"
-#define _META_NAMES_MAX 9
-
typedef struct sa_pcm_attrs {
sa_pcm_format_t format;
unsigned rate;
@@ -15,18 +35,24 @@ typedef struct sa_pcm_attrs {
} pcm_attrs_t;
struct sa_stream {
- sa_mode_t mode;
+ sa_mutex *mutex;
+
+ sa_mode_t mode; /* immutable -- this means accessing this doesn't require locking */
- pcm_attrs_t pcm_attrs;
- size_t pcm_sample_size;
- size_t pcm_frame_size;
+ pcm_attrs_t pcm_attrs; /* immutable, except for .rate */
+ size_t pcm_sample_size; /* immutable */
+ size_t pcm_frame_size; /* immutable */
- char *codec;
+ char *codec; /* immutable */
+
+ sa_state_t state;
-/* size_t read_lower_watermark; */
-/* size_t read_upper_watermark; */
-/* size_t write_lower_watermark; */
-/* size_t write_upper_watermark; */
+ sa_proplist *props;
+
+ size_t read_latency;
+ size_t read_process_time;
+ size_t write_latency;
+ size_t write_process_time;
sa_xrun_mode_t xrun_mode;
sa_bool_t ni_enabled;
@@ -34,35 +60,39 @@ struct sa_stream {
sa_event_callback_t event_callback;
- char *device;
char *driver;
+ char *device;
int32_t *read_volume;
int32_t *write_volume;
+ sa_event_callback_t callback;
void *user_data;
- sa_state_t state;
-
sa_adjust_t adjust_rate;
sa_adjust_t adjust_nchannels;
sa_adjust_t adjust_pcm_format;
-/* sa_adjust_t adjust_watermarks; */
- sa_error_t error;
- sa_notify_t notify;
+ /* Current event data */
sa_event_t event;
+ int error;
+ sa_notify_t notify;
+ void *notify_data;
+ size_t notify_data_nbytes;
- void *driver_data; /* driver specific data */
-
- void *meta_data[_META_NAMES_MAX];
- size_t meta_data_size[_META_NAMES_MAX];
-
- sa_mutex *mutex;
-
- sa_event_callback_t callback;
+ void *private; /* driver specific data */
+#ifdef HAVE_DSO
+ void *private_dso;
+#endif
};
size_t sa_get_pcm_sample_size(sa_pcm_format_t f);
+float volume_to_dB(int32_t v);
+float volume_to_linear(int32_t v);
+int32_t volume_from_dB(float dB);
+int32_t volume_from_linear(float f);
+
+sa_bool_t sa_stream_frame_aligned(sa_stream *s, int64_t nbytes);
+
#endif
diff --git a/src/continued-fraction.h b/src/continued-fraction.h
index 2026b50..9f8f136 100644
--- a/src/continued-fraction.h
+++ b/src/continued-fraction.h
@@ -1,6 +1,26 @@
#ifndef foosydneycontinuedfractionhfoo
#define foosydneycontinuedfractionhfoo
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
void sa_continued_fraction(double val, int max_denom, int *res_num, int *res_denom);
#endif
diff --git a/src/converter.c b/src/converter.c
index 90dba34..1fd1bf7 100644
--- a/src/converter.c
+++ b/src/converter.c
@@ -1,3 +1,23 @@
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@@ -5,7 +25,7 @@
#include <math.h>
#include <string.h>
-#include "speex/speex_resampler.h"
+#include <speex/speex_resampler.h>
#include "converter.h"
#include "sydney.h"
@@ -172,12 +192,10 @@ static sa_pcm_format_t fix_work_format_for_resample(sa_pcm_format_t f) {
case SA_PCM_FORMAT_U8:
case SA_PCM_FORMAT_S16_NE:
return SA_PCM_FORMAT_S16_NE;
- break;
case SA_PCM_FORMAT_S32_NE:
case SA_PCM_FORMAT_FLOAT32_NE:
return SA_PCM_FORMAT_FLOAT32_NE;
- break;
default:
;
@@ -222,14 +240,14 @@ int sa_converter_init(
if (u != t)
c->remap_required = TRUE;
- c->channel_map_table[u * (from->nchannels+1) + k++] += t;
+ c->channel_map_table[u * (from->nchannels+1) + k++] += (int) t;
}
}
if (k > 1)
c->sum_required = TRUE;
- c->channel_map_table[k] = (unsigned) -1;
+ c->channel_map_table[k] = (int) -1;
}
if (c->from_nchannels != c->to_nchannels)
@@ -310,7 +328,7 @@ int sa_converter_init(
if (!(c->volume_divisor = sa_new(int32_t, c->from_nchannels)))
goto fail;
- c->no_volume = 1;
+ c->no_volume = TRUE;
/* Initialize bounce buffers */
@@ -333,8 +351,6 @@ int sa_converter_init(
if (sa_bbuffer_init(&c->bb_tmp, 1, 1) < 0)
goto fail;
- if (c
-
return 0;
fail:
@@ -400,7 +416,7 @@ int sa_converter_go(
size_t* stride;
void** process_data;
sa_bool_t is_bounce;
- sa_bool_t interleave;
+ sa_interleave_t interleave;
unsigned i;
sa_assert(c);
@@ -693,6 +709,7 @@ void sa_converter_set_volume(sa_converter_t *c, const int32_t vol[]) {
sa_bool_t no_volume = TRUE;
sa_assert(c);
+ sa_assert(vol);
for (i = 0; i < c->from_nchannels; i++) {
int num, denom;
@@ -705,7 +722,7 @@ void sa_converter_set_volume(sa_converter_t *c, const int32_t vol[]) {
c->volume_divisor[i] = 1;
no_volume = 0;
} else {
- float f = powf(10.0, (float) vol[i] / 2000);
+ float f = volume_to_linear(vol[i]);
sa_continued_fraction(f, 0x7FFF, &num, &denom);
@@ -723,12 +740,17 @@ void sa_converter_set_volume(sa_converter_t *c, const int32_t vol[]) {
int sa_converter_go_interleaved(
sa_converter_t *c,
const void *const data,
- void **dst[], size_t *dstr[], sa_bool_t dinterleave,
+ void **dst[], size_t *dstr[], sa_interleave_t dinterleave,
size_t *size) {
unsigned i;
const uint8_t *d = data;
- unsigned stride = c->from_nchannels * c->from_sample_size;
+ size_t stride;
+
+ sa_assert(c);
+ sa_assert(data);
+
+ stride = c->from_nchannels * c->from_sample_size;
for (i = 0; i < c->from_nchannels; i++) {
c->from_process_data[i] = (void*) d;
diff --git a/src/converter.h b/src/converter.h
index a3ec182..37c98f7 100644
--- a/src/converter.h
+++ b/src/converter.h
@@ -1,6 +1,26 @@
#ifndef foosydneyconverterhfoo
#define foosydneyconverterhfoo
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
#include "sydney.h"
#include "volscale.h"
#include "bswap.h"
@@ -28,6 +48,9 @@ struct sa_converter {
sa_bool_t sum_required;
sa_bool_t remap_required;
+ sa_bool_t no_volume;
+ int32_t *volume_factor, *volume_divisor;
+
sa_pcm_format_t work_pcm_format;
size_t from_sample_size, work_sample_size, to_sample_size;
@@ -55,9 +78,6 @@ struct sa_converter {
void **from_process_data, **to_process_data;
size_t *from_stride, *to_stride;
- int32_t *volume_factor, *volume_divisor;
- sa_bool_t no_volume;
-
int *channel_map_table;
void *zero_buffer;
diff --git a/src/driver-order.c b/src/driver-order.c
new file mode 100644
index 0000000..98164c8
--- /dev/null
+++ b/src/driver-order.c
@@ -0,0 +1,42 @@
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#include "sydney.h"
+#include "driver-order.h"
+
+const char* const sa_driver_order[] = {
+#ifdef HAVE_PULSE
+ "pulse",
+#endif
+#ifdef HAVE_ALSA
+ "alsa",
+#endif
+#ifdef HAVE_OSS
+ "oss",
+#endif
+ /* ... */
+ NULL
+};
diff --git a/src/driver-order.h b/src/driver-order.h
new file mode 100644
index 0000000..a799fd2
--- /dev/null
+++ b/src/driver-order.h
@@ -0,0 +1,26 @@
+#ifndef foosydneydriverorderhfoo
+#define foosydneydriverorderhfoo
+
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
+extern const char* const sa_driver_order[];
+
+#endif
diff --git a/src/driver.h b/src/driver.h
index 15d690e..c49d534 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -1,34 +1,56 @@
#ifndef foosydneydriverhfoo
#define foosydneydriverhfoo
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
#include "sydney.h"
-int driver_open(sa_stream_t *dev);
-int driver_destroy(sa_stream_t *dev);
+int driver_open(sa_stream *s);
+int driver_destroy(sa_stream *s);
+
+int driver_change_write_latency(sa_stream *s, size_t *latency, size_t *process_time);
+int driver_change_read_latency(sa_stream *s, size_t *latency, size_t *process_time);
-int driver_start_thread(sa_stream_t *dev, sa_event_callback_t callback);
-int driver_stop_thread(sa_stream_t *dev);
+int driver_change_device(sa_stream *s, const char *device_name);
+int driver_change_read_volume(sa_stream *s, const int32_t vol[]);
+int driver_change_write_volume(sa_stream *s, const int32_t vol[]);
+int driver_change_pcm_rate(sa_stream *s, unsigned rate);
+int driver_change_props(sa_stream *s, sa_proplist *changed, sa_proplist *merged);
-int driver_change_device(sa_stream_t *dev, const char *device_name);
-int driver_change_read_volume(sa_stream_t *dev, const int32_t vol[]);
-int driver_change_write_volume(sa_stream_t *dev, const int32_t vol[]);
-int driver_change_rate(sa_stream_t *dev, unsigned rate);
-int driver_change_meta_data(sa_stream_t *dev, const char *name, const void *data, size_t size);
+int driver_get_state(sa_stream *s, sa_state_t *state);
+int driver_get_position(sa_stream *s, sa_position_t position, int64_t *pos);
-int driver_get_state(sa_stream_t *dev, sa_state_t *state);
-int driver_get_position(sa_stream_t *dev, sa_position_t position, int64_t *pos);
+int driver_wait(sa_stream *s);
-int driver_read(sa_stream_t *dev, void *data, size_t nbytes);
-int driver_read_ni(sa_stream_t *dev, unsigned channel, void *data, size_t nbytes);
+int driver_read(sa_stream *s, void *data, size_t nbytes);
+int driver_read_ni(sa_stream *s, unsigned channel, void *data, size_t nbytes);
-int driver_pwrite(sa_stream_t *dev, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence);
-int driver_pwrite_ni(sa_stream_t *dev, unsigned channel, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence);
+int driver_pwrite(sa_stream *s, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence);
+int driver_pwrite_ni(sa_stream *s, unsigned channel, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence);
-int driver_get_read_size(sa_stream_t *dev, size_t *size);
-int driver_get_write_size(sa_stream_t *dev, size_t *size);
+int driver_get_read_size(sa_stream *s, size_t *size);
+int driver_get_write_size(sa_stream *s, size_t *size);
-int driver_resume(sa_stream_t *dev);
-int driver_pause(sa_stream_t *dev);
-int driver_drain(sa_stream_t *dev);
+int driver_resume(sa_stream *s);
+int driver_pause(sa_stream *s);
+int driver_drain(sa_stream *s);
#endif
diff --git a/src/dso.c b/src/dso.c
new file mode 100644
index 0000000..71c8fd7
--- /dev/null
+++ b/src/dso.c
@@ -0,0 +1,565 @@
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ltdl.h>
+#include <string.h>
+#include <errno.h>
+
+#include "driver.h"
+#include "common.h"
+#include "malloc.h"
+#include "driver-order.h"
+
+struct private_dso {
+ lt_dlhandle module;
+ sa_bool_t ltdl_initialized;
+
+ int (*driver_open)(sa_stream *s);
+ int (*driver_destroy)(sa_stream *s);
+
+
+ int (*driver_change_write_latency)(sa_stream *s, size_t *latency, size_t *process_time);
+ int (*driver_change_read_latency)(sa_stream *s, size_t *latency, size_t *process_time);
+
+ int (*driver_change_device)(sa_stream *s, const char *device);
+ int (*driver_change_read_volume)(sa_stream *s, const int32_t vol[]);
+ int (*driver_change_write_volume)(sa_stream *s, const int32_t vol[]);
+ int (*driver_change_pcm_rate)(sa_stream *s, unsigned rate);
+
+ int (*driver_change_props)(sa_stream *s, sa_proplist *changed, sa_proplist *merged);
+
+ int (*driver_get_state)(sa_stream *s, sa_state_t *state);
+ int (*driver_get_position)(sa_stream *s, sa_position_t position, int64_t *pos);
+
+ int (*driver_wait)(sa_stream *s);
+
+ int (*driver_read)(sa_stream *s, void *data, size_t nbytes);
+ int (*driver_read_ni)(sa_stream *s, unsigned channel, void *data, size_t nbytes);
+
+ int (*driver_pwrite)(sa_stream *s, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence);
+ int (*driver_pwrite_ni)(sa_stream *s, unsigned channel, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence);
+
+ int (*driver_get_read_size)(sa_stream *s, size_t *size);
+ int (*driver_get_write_size)(sa_stream *s, size_t *size);
+
+ int (*driver_resume)(sa_stream *s);
+ int (*driver_pause)(sa_stream *s);
+ int (*driver_drain)(sa_stream *s);
+};
+
+#define PRIVATE_DSO(s) ((struct private_dso *) ((s)->private_dso))
+
+static int sa_error_from_lt_error(int code) {
+
+ static const int table[] = {
+ [LT_ERROR_UNKNOWN] = SA_ERROR_INTERNAL,
+ [LT_ERROR_DLOPEN_NOT_SUPPORTED] = SA_ERROR_NOTSUPPORTED,
+ [LT_ERROR_INVALID_LOADER] = SA_ERROR_INTERNAL,
+ [LT_ERROR_INIT_LOADER] = SA_ERROR_INTERNAL,
+ [LT_ERROR_REMOVE_LOADER] = SA_ERROR_INTERNAL,
+ [LT_ERROR_FILE_NOT_FOUND] = SA_ERROR_NOTFOUND,
+ [LT_ERROR_DEPLIB_NOT_FOUND] = SA_ERROR_NOTFOUND,
+ [LT_ERROR_NO_SYMBOLS] = SA_ERROR_NOTFOUND,
+ [LT_ERROR_CANNOT_OPEN] = SA_ERROR_ACCESS,
+ [LT_ERROR_CANNOT_CLOSE] = SA_ERROR_INTERNAL,
+ [LT_ERROR_SYMBOL_NOT_FOUND] = SA_ERROR_NOTFOUND,
+ [LT_ERROR_NO_MEMORY] = SA_ERROR_OOM,
+ [LT_ERROR_INVALID_HANDLE] = SA_ERROR_INVALID,
+ [LT_ERROR_BUFFER_OVERFLOW] = SA_ERROR_TOOBIG,
+ [LT_ERROR_INVALID_ERRORCODE] = SA_ERROR_INVALID,
+ [LT_ERROR_SHUTDOWN] = SA_ERROR_INTERNAL,
+ [LT_ERROR_CLOSE_RESIDENT_MODULE] = SA_ERROR_INTERNAL,
+ [LT_ERROR_INVALID_MUTEX_ARGS] = SA_ERROR_INTERNAL,
+ [LT_ERROR_INVALID_POSITION] = SA_ERROR_INTERNAL
+ };
+
+ if (code < 0 || code >= LT_ERROR_MAX)
+ return SA_ERROR_INTERNAL;
+
+ return table[code];
+}
+
+static int lt_error_from_string(const char *t) {
+
+ struct lt_error_code {
+ int code;
+ const char *text;
+ };
+
+ static const struct lt_error_code lt_error_codes[] = {
+ /* This is so disgustingly ugly, it makes me vomit. But that's
+ * all ltdl's fault. */
+#define LT_ERROR(u, s) { .code = LT_ERROR_ ## u, .text = s },
+ lt_dlerror_table
+#undef LT_ERROR
+
+ { .code = 0, .text = NULL }
+ };
+
+ const struct lt_error_code *c;
+
+ for (c = lt_error_codes; c->text; c++)
+ if (sa_streq(t, c->text))
+ return c->code;
+
+ return -1;
+}
+
+static int sa_error_from_string(const char *t) {
+ int err;
+
+ if ((err = lt_error_from_string(t)) < 0)
+ return SA_ERROR_INTERNAL;
+
+ return sa_error_from_lt_error(err);
+}
+
+static int try_open(sa_stream *s, const char *t) {
+ char *mn;
+ struct private_dso *p;
+
+ p = PRIVATE_DSO(s);
+
+ if (!(mn = sa_sprintf_malloc(SA_PLUGIN_PATH "/libsydney-%s", t)))
+ return SA_ERROR_OOM;
+
+ errno = 0;
+ p->module = lt_dlopenext(mn);
+ sa_free(mn);
+
+ if (!p->module) {
+ int ret;
+
+ if (errno == ENOENT)
+ ret = SA_ERROR_NOTFOUND;
+ else
+ ret = sa_error_from_string(lt_dlerror());
+
+ if (ret == SA_ERROR_NOTFOUND)
+ ret = SA_ERROR_NODRIVER;
+
+ return ret;
+ }
+
+ return SA_SUCCESS;
+}
+
+static void* real_dlsym(lt_module m, const char *name, const char *symbol) {
+ char sn[256];
+ char *s;
+ void *r;
+
+ sa_return_null_if_fail(m);
+ sa_return_null_if_fail(name);
+ sa_return_null_if_fail(symbol);
+
+ snprintf(sn, sizeof(sn), "%s_%s", name, symbol);
+ sn[sizeof(sn)-1] = 0;
+
+ for (s = sn; *s; s++) {
+ if (*s >= 'a' && *s <= 'z')
+ continue;
+ if (*s >= 'A' && *s <= 'Z')
+ continue;
+ if (*s >= '0' && *s <= '9')
+ continue;
+
+ *s = '_';
+ }
+
+ if ((r = lt_dlsym(m, sn)))
+ return r;
+
+ return lt_dlsym(m, symbol);
+}
+
+#define MAKE_FUNC_PTR(ret, args, x) ((ret (*) args ) (size_t) (x))
+#define GET_FUNC_PTR(module, name, symbol, ret, args) MAKE_FUNC_PTR(ret, args, real_dlsym((module), (name), (symbol)))
+
+int driver_open(sa_stream *s) {
+ int ret;
+ struct private_dso *p;
+ char *driver;
+
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(!PRIVATE_DSO(s), SA_ERROR_STATE);
+
+ if (!(s->private_dso = p = sa_new0(struct private_dso, 1)))
+ return SA_ERROR_OOM;
+
+ if (lt_dlinit() != 0) {
+ ret = sa_error_from_string(lt_dlerror());
+ driver_destroy(s);
+ return ret;
+ }
+
+ p->ltdl_initialized = TRUE;
+
+ if (s->driver) {
+ char *e;
+ size_t n;
+
+ if (!(e = sa_strdup(s->driver))) {
+ driver_destroy(s);
+ return SA_ERROR_OOM;
+ }
+
+ n = strcspn(e, ",:");
+ e[n] = 0;
+
+ if (n == 0) {
+ driver_destroy(s);
+ sa_free(e);
+ return SA_ERROR_INVALID;
+ }
+
+ if ((ret = try_open(s, e)) < 0) {
+ driver_destroy(s);
+ sa_free(e);
+ return ret;
+ }
+
+ driver = e;
+
+ } else {
+ const char *const * e;
+
+ for (e = sa_driver_order; *e; e++) {
+
+ if ((ret = try_open(s, *e)) == SA_SUCCESS)
+ break;
+
+ if (ret != SA_ERROR_NODRIVER &&
+ ret != SA_ERROR_NOTAVAILABLE &&
+ ret != SA_ERROR_NOTFOUND) {
+
+ driver_destroy(s);
+ return ret;
+ }
+ }
+
+ if (!*e) {
+ driver_destroy(s);
+ return SA_ERROR_NODRIVER;
+ }
+
+ if (!(driver = sa_strdup(*e))) {
+ driver_destroy(s);
+ return SA_ERROR_OOM;
+ }
+ }
+
+ sa_assert(p->module);
+
+ if (!(p->driver_open = GET_FUNC_PTR(p->module, driver, "driver_open", int, (sa_stream*))) ||
+ !(p->driver_destroy = GET_FUNC_PTR(p->module, driver, "driver_destroy", int, (sa_stream*))) ||
+ !(p->driver_change_write_latency = GET_FUNC_PTR(p->module, driver, "driver_change_write_latency", int, (sa_stream *s, size_t *latency, size_t *process_time))) ||
+ !(p->driver_change_read_latency = GET_FUNC_PTR(p->module, driver, "driver_change_read_latency", int, (sa_stream *s, size_t *latency, size_t *process_time))) ||
+ !(p->driver_change_device = GET_FUNC_PTR(p->module, driver, "driver_change_device", int, (sa_stream*, const char *))) ||
+ !(p->driver_change_read_volume = GET_FUNC_PTR(p->module, driver, "driver_change_read_volume", int, (sa_stream *s, const int32_t vol[]))) ||
+ !(p->driver_change_write_volume = GET_FUNC_PTR(p->module, driver, "driver_change_write_volume", int, (sa_stream *s, const int32_t vol[]))) ||
+ !(p->driver_change_pcm_rate = GET_FUNC_PTR(p->module, driver, "driver_change_pcm_rate", int, (sa_stream *s, unsigned rate))) ||
+ !(p->driver_change_props = GET_FUNC_PTR(p->module, driver, "driver_change_props", int, (sa_stream *, sa_proplist *, sa_proplist *))) ||
+ !(p->driver_get_state = GET_FUNC_PTR(p->module, driver, "driver_get_state", int, (sa_stream *s, sa_state_t *state))) ||
+ !(p->driver_get_position = GET_FUNC_PTR(p->module, driver, "driver_get_position", int, (sa_stream *s, sa_position_t position, int64_t *pos))) ||
+ !(p->driver_wait = GET_FUNC_PTR(p->module, driver, "driver_wait", int, (sa_stream *s))) ||
+ !(p->driver_read = GET_FUNC_PTR(p->module, driver, "driver_read", int, (sa_stream *s, void *data, size_t nbytes))) ||
+ !(p->driver_read_ni = GET_FUNC_PTR(p->module, driver, "driver_read_ni", int, (sa_stream *s, unsigned channel, void *data, size_t nbytes))) ||
+ !(p->driver_pwrite = GET_FUNC_PTR(p->module, driver, "driver_pwrite", int, (sa_stream *s, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence))) ||
+ !(p->driver_pwrite_ni = GET_FUNC_PTR(p->module, driver, "driver_pwrite_ni", int, (sa_stream *s, unsigned channel, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence))) ||
+ !(p->driver_get_read_size = GET_FUNC_PTR(p->module, driver, "driver_get_read_size", int, (sa_stream *s, size_t *size))) ||
+ !(p->driver_get_write_size = GET_FUNC_PTR(p->module, driver, "driver_get_write_size", int, (sa_stream *s, size_t *size))) ||
+ !(p->driver_resume = GET_FUNC_PTR(p->module, driver, "driver_resume", int, (sa_stream *s))) ||
+ !(p->driver_pause = GET_FUNC_PTR(p->module, driver, "driver_pause", int, (sa_stream *s))) ||
+ !(p->driver_drain = GET_FUNC_PTR(p->module, driver, "driver_drain", int, (sa_stream *s)))) {
+
+ sa_free(driver);
+ driver_destroy(s);
+ return SA_ERROR_CORRUPT;
+ }
+
+ sa_free(driver);
+
+ if ((ret = p->driver_open(s)) < 0) {
+ driver_destroy(s);
+ return ret;
+ }
+
+ return SA_SUCCESS;
+}
+
+int driver_destroy(sa_stream *s) {
+ struct private_dso *p;
+ int ret = SA_SUCCESS;
+
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->private_dso, SA_ERROR_STATE);
+
+ p = PRIVATE_DSO(s);
+
+ if (p->driver_destroy)
+ ret = p->driver_destroy(s);
+
+ if (p->module)
+ lt_dlclose(p->module);
+
+ if (p->ltdl_initialized) {
+ lt_dlexit();
+ p->ltdl_initialized = FALSE;
+ }
+
+ sa_free(p);
+
+ s->private_dso = NULL;
+
+ return ret;
+}
+
+int driver_change_write_latency(sa_stream *s, size_t *latency, size_t *process_time) {
+ struct private_dso *p;
+
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->private_dso, SA_ERROR_STATE);
+
+ p = PRIVATE_DSO(s);
+ sa_return_val_if_fail(p->driver_change_write_latency, SA_ERROR_STATE);
+
+ return p->driver_change_write_latency(s, latency, process_time);
+}
+
+int driver_change_read_latency(sa_stream *s, size_t *latency, size_t *process_time) {
+ struct private_dso *p;
+
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->private_dso, SA_ERROR_STATE);
+
+ p = PRIVATE_DSO(s);
+ sa_return_val_if_fail(p->driver_change_read_latency, SA_ERROR_STATE);
+
+ return p->driver_change_read_latency(s, latency, process_time);
+}
+
+int driver_change_device(sa_stream *s, const char *device) {
+ struct private_dso *p;
+
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->private_dso, SA_ERROR_STATE);
+
+ p = PRIVATE_DSO(s);
+ sa_return_val_if_fail(p->driver_change_device, SA_ERROR_STATE);
+
+ return p->driver_change_device(s, device);
+}
+
+int driver_change_read_volume(sa_stream *s, const int32_t vol[]) {
+ struct private_dso *p;
+
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->private_dso, SA_ERROR_STATE);
+
+ p = PRIVATE_DSO(s);
+ sa_return_val_if_fail(p->driver_change_read_volume, SA_ERROR_STATE);
+
+ return p->driver_change_read_volume(s, vol);
+}
+
+int driver_change_write_volume(sa_stream *s, const int32_t vol[]) {
+ struct private_dso *p;
+
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->private_dso, SA_ERROR_STATE);
+
+ p = PRIVATE_DSO(s);
+ sa_return_val_if_fail(p->driver_change_write_volume, SA_ERROR_STATE);
+
+ return p->driver_change_write_volume(s, vol);
+}
+
+int driver_change_pcm_rate(sa_stream *s, unsigned rate) {
+ struct private_dso *p;
+
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->private_dso, SA_ERROR_STATE);
+
+ p = PRIVATE_DSO(s);
+ sa_return_val_if_fail(p->driver_change_pcm_rate, SA_ERROR_STATE);
+
+ return p->driver_change_pcm_rate(s, rate);
+}
+
+int driver_change_props(sa_stream *s, sa_proplist *changed, sa_proplist *merged) {
+ struct private_dso *p;
+
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->private_dso, SA_ERROR_STATE);
+
+ p = PRIVATE_DSO(s);
+ sa_return_val_if_fail(p->driver_change_props, SA_ERROR_STATE);
+
+ return p->driver_change_props(s, changed, merged);
+}
+
+int driver_get_state(sa_stream *s, sa_state_t *state) {
+ struct private_dso *p;
+
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->private_dso, SA_ERROR_STATE);
+
+ p = PRIVATE_DSO(s);
+ sa_return_val_if_fail(p->driver_get_state, SA_ERROR_STATE);
+
+ return p->driver_get_state(s, state);
+}
+
+int driver_get_position(sa_stream *s, sa_position_t position, int64_t *pos) {
+ struct private_dso *p;
+
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->private_dso, SA_ERROR_STATE);
+
+ p = PRIVATE_DSO(s);
+ sa_return_val_if_fail(p->driver_get_position, SA_ERROR_STATE);
+
+ return p->driver_get_position(s, position, pos);
+}
+
+int driver_wait(sa_stream *s) {
+ struct private_dso *p;
+
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->private_dso, SA_ERROR_STATE);
+
+ p = PRIVATE_DSO(s);
+ sa_return_val_if_fail(p->driver_wait, SA_ERROR_STATE);
+
+ return p->driver_wait(s);
+}
+
+int driver_read(sa_stream *s, void *data, size_t nbytes) {
+ struct private_dso *p;
+
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->private_dso, SA_ERROR_STATE);
+
+ p = PRIVATE_DSO(s);
+ sa_return_val_if_fail(p->driver_read, SA_ERROR_STATE);
+
+ return p->driver_read(s, data, nbytes);
+}
+
+int driver_read_ni(sa_stream *s, unsigned channel, void *data, size_t nbytes) {
+ struct private_dso *p;
+
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->private_dso, SA_ERROR_STATE);
+
+ p = PRIVATE_DSO(s);
+ sa_return_val_if_fail(p->driver_read_ni, SA_ERROR_STATE);
+
+ return p->driver_read_ni(s, channel, data, nbytes);
+}
+
+int driver_pwrite(sa_stream *s, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence) {
+ struct private_dso *p;
+
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->private_dso, SA_ERROR_STATE);
+
+ p = PRIVATE_DSO(s);
+ sa_return_val_if_fail(p->driver_pwrite, SA_ERROR_STATE);
+
+ return p->driver_pwrite(s, data, nbytes, offset, whence);
+}
+
+int driver_pwrite_ni(sa_stream *s, unsigned channel, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence) {
+ struct private_dso *p;
+
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->private_dso, SA_ERROR_STATE);
+
+ p = PRIVATE_DSO(s);
+ sa_return_val_if_fail(p->driver_pwrite_ni, SA_ERROR_STATE);
+
+ return p->driver_pwrite_ni(s, channel, data, nbytes, offset, whence);
+}
+
+int driver_get_read_size(sa_stream *s, size_t *size) {
+ struct private_dso *p;
+
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->private_dso, SA_ERROR_STATE);
+
+ p = PRIVATE_DSO(s);
+ sa_return_val_if_fail(p->driver_get_read_size, SA_ERROR_STATE);
+
+ return p->driver_get_read_size(s, size);
+}
+
+int driver_get_write_size(sa_stream *s, size_t *size) {
+ struct private_dso *p;
+
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->private_dso, SA_ERROR_STATE);
+
+ p = PRIVATE_DSO(s);
+ sa_return_val_if_fail(p->driver_get_write_size, SA_ERROR_STATE);
+
+ return p->driver_get_write_size(s, size);
+}
+
+int driver_resume(sa_stream *s) {
+ struct private_dso *p;
+
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->private_dso, SA_ERROR_STATE);
+
+ p = PRIVATE_DSO(s);
+ sa_return_val_if_fail(p->driver_resume, SA_ERROR_STATE);
+
+ return p->driver_resume(s);
+}
+
+int driver_pause(sa_stream *s) {
+ struct private_dso *p;
+
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->private_dso, SA_ERROR_STATE);
+
+ p = PRIVATE_DSO(s);
+ sa_return_val_if_fail(p->driver_pause, SA_ERROR_STATE);
+
+ return p->driver_pause(s);
+}
+
+int driver_drain(sa_stream *s) {
+ struct private_dso *p;
+
+ sa_return_val_if_fail(s, SA_ERROR_INVALID);
+ sa_return_val_if_fail(s->private_dso, SA_ERROR_STATE);
+
+ p = PRIVATE_DSO(s);
+ sa_return_val_if_fail(p->driver_drain, SA_ERROR_STATE);
+
+ return p->driver_drain(s);
+}
diff --git a/src/format.c b/src/format.c
index adac878..6faa878 100644
--- a/src/format.c
+++ b/src/format.c
@@ -1,3 +1,23 @@
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@@ -16,9 +36,9 @@
static int format_u8_to_s16(sa_bbuffer_t *b, void *dst, size_t dstr, const void *src, size_t sstr, size_t bytes) {
int16_t d = -0x80, f = 0x100;
- oil_conv_s16_u8(dst, dstr, src, sstr, bytes);
- oil_scalaradd_s16(dst, dstr, dst, dstr, &d, bytes);
- oil_scalarmult_s16(dst, dstr, dst, dstr, &f, bytes);
+ oil_conv_s16_u8(dst, (int) dstr, src, (int) sstr, (int) bytes);
+ oil_scalaradd_s16(dst, (int) dstr, dst, (int) dstr, &d, (int) bytes);
+ oil_scalarmult_s16(dst, (int) dstr, dst, (int) dstr, &f, (int) bytes);
return SA_SUCCESS;
}
@@ -26,19 +46,19 @@ static int format_u8_to_s16(sa_bbuffer_t *b, void *dst, size_t dstr, const void
static int format_u8_to_s32(sa_bbuffer_t *b, void *dst, size_t dstr, const void *src, size_t sstr, size_t bytes) {
int32_t d = -0x80, f = 0x1000000;
- oil_conv_s16_u8(dst, dstr, src, sstr, bytes);
- oil_scalaradd_s32(dst, dstr, dst, dstr, &d, bytes);
- oil_scalarmult_s32(dst, dstr, dst, dstr, &f, bytes);
+ oil_conv_s16_u8(dst, (int) dstr, src, (int) sstr, (int) bytes);
+ oil_scalaradd_s32(dst, (int) dstr, dst, (int) dstr, &d, (int) bytes);
+ oil_scalarmult_s32(dst, (int) dstr, dst, (int) dstr, &f, (int) bytes);
return SA_SUCCESS;
}
static int format_u8_to_f32(sa_bbuffer_t *b, void *dst, size_t dstr, const void *src, size_t sstr, size_t bytes) {
- float d = -0x80, f = 1.0/0x7F;
+ float d = (float) -0x80, f = 1.0f/0x7F;
- oil_conv_f32_u8(dst, dstr, src, sstr, bytes);
- oil_scalaradd_f32(dst, dstr, dst, dstr, &d, bytes);
- oil_scalarmult_f32(dst, dstr, dst, dstr, &f, bytes);
+ oil_conv_f32_u8(dst, (int) dstr, src, (int) sstr, (int) bytes);
+ oil_scalaradd_f32(dst, (int) dstr, dst, (int) dstr, &d, (int) bytes);
+ oil_scalarmult_f32(dst, (int) dstr, dst, (int) dstr, &f, (int) bytes);
return SA_SUCCESS;
}
@@ -70,7 +90,7 @@ static int format_ulaw_to_f32(sa_bbuffer_t *b, void *dst, size_t dstr, const voi
const uint8_t *s = src;
for (; bytes > 0; bytes --, d += dstr/sizeof(float), s += sstr)
- *d = sa_ulaw2linear16(*s * 1.0F / 0x7FFF);
+ *d = (float) sa_ulaw2linear16(*s) / (float) 0x7FFF;
return SA_SUCCESS;
}
@@ -92,7 +112,7 @@ static int format_alaw_to_s32(sa_bbuffer_t *b, void *dst, size_t dstr, const voi
const uint8_t *s = src;
for (; bytes > 0; bytes --, d += dstr/sizeof(int32_t), s += sstr)
- *d = (int32_t) sa_alaw2linear16(*(s++)) * 0x10000;
+ *d = (int32_t) sa_alaw2linear16(*s) * 0x10000;
return SA_SUCCESS;
}
@@ -102,7 +122,7 @@ static int format_alaw_to_f32(sa_bbuffer_t *b, void *dst, size_t dstr, const voi
const uint8_t *s = src;
for (; bytes > 0; bytes --, d += dstr/sizeof(float), s += sstr)
- *d = sa_alaw2linear16(*(s++) * 1.0F / 0x7FFF);
+ *d = (float) sa_alaw2linear16(*s) / (float) 0x7FFF;
return SA_SUCCESS;
}
@@ -112,7 +132,7 @@ static int format_alaw_to_f32(sa_bbuffer_t *b, void *dst, size_t dstr, const voi
static int format_s16_to_u8(sa_bbuffer_t *b, void *dst, size_t dstr, const void *src, size_t sstr, size_t bytes) {
uint8_t *d = dst;
const int16_t *s = src;
- unsigned n = bytes/sizeof(int16_t);
+ size_t n = bytes/sizeof(int16_t);
for (; n > 0; n--, d += dstr, s += sstr/sizeof(int16_t))
*d = (uint8_t) (*s / 0x100 + 0x80);
@@ -123,7 +143,7 @@ static int format_s16_to_u8(sa_bbuffer_t *b, void *dst, size_t dstr, const void
static int format_s16_to_ulaw(sa_bbuffer_t *b, void *dst, size_t dstr, const void *src, size_t sstr, size_t bytes) {
uint8_t *d = dst;
const int16_t *s = src;
- unsigned n = bytes/sizeof(int16_t);
+ size_t n = bytes/sizeof(int16_t);
for (; n > 0; n --, d += dstr, s += sstr/sizeof(int16_t))
*d = sa_14linear2ulaw(*s);
@@ -134,7 +154,7 @@ static int format_s16_to_ulaw(sa_bbuffer_t *b, void *dst, size_t dstr, const voi
static int format_s16_to_alaw(sa_bbuffer_t *b, void *dst, size_t dstr, const void *src, size_t sstr, size_t bytes) {
uint8_t *d = dst;
const int16_t *s = src;
- unsigned n = bytes/sizeof(int16_t);
+ size_t n = bytes/sizeof(int16_t);
for (; n > 0; n --, d += dstr, s += sstr/sizeof(int16_t))
*d = sa_13linear2alaw(*s);
@@ -144,20 +164,20 @@ static int format_s16_to_alaw(sa_bbuffer_t *b, void *dst, size_t dstr, const voi
static int format_s16_to_s32(sa_bbuffer_t *b, void *dst, size_t dstr, const void *src, size_t sstr, size_t bytes) {
int f = 0x10000;
- unsigned n = bytes/sizeof(int16_t);
+ size_t n = bytes/sizeof(int16_t);
- oil_conv_s32_s16(dst, dstr, src, sstr, n);
- oil_scalarmult_s32(dst, dstr, dst, dstr, &f, n);
+ oil_conv_s32_s16(dst, (int) dstr, src, (int) sstr, (int) n);
+ oil_scalarmult_s32(dst, (int) dstr, dst, (int) dstr, &f, (int) n);
return SA_SUCCESS;
}
static int format_s16_to_f32(sa_bbuffer_t *b, void *dst, size_t dstr, const void *src, size_t sstr, size_t bytes) {
- float f = 1.0/0x7ffff;
- unsigned n = bytes/sizeof(int16_t);
+ float f = 1.0f/0x7ffff;
+ size_t n = bytes/sizeof(int16_t);
- oil_conv_f32_s16(dst, dstr, src, sstr, n);
- oil_scalarmult_f32(dst, dstr, dst, dstr, &f, n);
+ oil_conv_f32_s16(dst, (int) dstr, src, (int) sstr, (int) n);
+ oil_scalarmult_f32(dst, (int) dstr, dst, (int) dstr, &f, (int) n);
return SA_SUCCESS;
}
@@ -167,13 +187,13 @@ static int format_s16_to_f32(sa_bbuffer_t *b, void *dst, size_t dstr, const void
static int format_s24_to_s32(sa_bbuffer_t *b, void *dst, size_t dstr, const void *src, size_t sstr, size_t bytes) {
int32_t *d = dst;
const uint8_t *s = src;
- unsigned n = bytes/3;
+ size_t n = bytes/3;
for (; n > 0; n--, d += dstr/sizeof(int32_t), s += sstr/3)
#if defined(SA_LITTLE_ENDIAN)
- *d = (int32_t) ((int8_t) s[2]) * 0x1000000 + s[1] * 0x10000 + s[0] * 0x100;
+ *d = (int32_t) ((int32_t) (int8_t) s[2] * 0x1000000 + (int32_t) s[1] * 0x10000 + (int32_t) s[0] * 0x100);
#elif defined(SA_BIG_ENDIAN)
- *d = (int32_t) ((int8_t) s[0]) * 0x1000000 + s[1] * 0x10000 + s[2] * 0x100;
+ *d = (int32_t) ((int32_t) (int8_t) s[0] * 0x1000000 + (int32_t) s[1] * 0x10000 + (int32_t) s[2] * 0x100);
#else
#error "Unknown byte order"
#endif
@@ -184,13 +204,13 @@ static int format_s24_to_s32(sa_bbuffer_t *b, void *dst, size_t dstr, const void
static int format_s24_to_f32(sa_bbuffer_t *b, void *dst, size_t dstr, const void *src, size_t sstr, size_t bytes) {
float *d = dst;
const uint8_t *s = src;
- unsigned n = bytes/3;
+ size_t n = bytes/3;
for (; n > 0; n--, d += dstr/sizeof(float), s += sstr/3)
#if defined(SA_LITTLE_ENDIAN)
- *d = ((float) ((int8_t) s[2]) * 0x10000 + s[1] * 0x100 + s[0]) / 0x7fffff;
+ *d = (float) ((int32_t) (int8_t) s[2] * 0x10000 + (int32_t) s[1] * 0x100 + (int32_t) s[0]) / (float) 0x7fffff;
#elif defined(SA_BIG_ENDIAN)
- *d = ((float) ((int8_t) s[0]) * 0x10000 + s[1] * 0x100 + s[2]) / 0x7fffff;
+ *d = (float) ((int32_t) (int8_t) s[0] * 0x10000 + (int32_t) s[1] * 0x100 + (int32_t) s[2]) / (float) 0x7fffff;
#else
#error "Unknown byte order"
#endif
@@ -203,7 +223,7 @@ static int format_s24_to_f32(sa_bbuffer_t *b, void *dst, size_t dstr, const void
static int format_s32_to_u8(sa_bbuffer_t *b, void *dst, size_t dstr, const void *src, size_t sstr, size_t bytes) {
uint8_t *d = dst;
const int32_t *s = src;
- unsigned n = bytes/sizeof(int32_t);
+ size_t n = bytes/sizeof(int32_t);
for (; n > 0; n--, d += dstr, s += sstr/sizeof(int32_t))
*d = (uint8_t) (*s / 0x1000000 + 0x80);
@@ -214,10 +234,10 @@ static int format_s32_to_u8(sa_bbuffer_t *b, void *dst, size_t dstr, const void
static int format_s32_to_ulaw(sa_bbuffer_t *b, void *dst, size_t dstr, const void *src, size_t sstr, size_t bytes) {
uint8_t *d = dst;
const int32_t *s = src;
- unsigned n = bytes/sizeof(int32_t);
+ size_t n = bytes/sizeof(int32_t);
for (; n > 0; n--, d += dstr, s += sstr/sizeof(int32_t))
- *d = sa_14linear2ulaw(*s / 0x10000);
+ *d = sa_14linear2ulaw((int16_t) (*s / 0x10000));
return SA_SUCCESS;
}
@@ -225,10 +245,10 @@ static int format_s32_to_ulaw(sa_bbuffer_t *b, void *dst, size_t dstr, const voi
static int format_s32_to_alaw(sa_bbuffer_t *b, void *dst, size_t dstr, const void *src, size_t sstr, size_t bytes) {
uint8_t *d = dst;
const int32_t *s = src;
- unsigned n = bytes/sizeof(int32_t);
+ size_t n = bytes/sizeof(int32_t);
for (; n > 0; n--, d += dstr, s += sstr/sizeof(int32_t))
- *d = sa_13linear2alaw(*s / 0x10000);
+ *d = sa_13linear2alaw((int16_t) (*s / 0x10000));
return SA_SUCCESS;
}
@@ -236,7 +256,7 @@ static int format_s32_to_alaw(sa_bbuffer_t *b, void *dst, size_t dstr, const voi
static int format_s32_to_s16(sa_bbuffer_t *b, void *dst, size_t dstr, const void *src, size_t sstr, size_t bytes) {
int16_t *d = dst;
const int32_t *s = src;
- unsigned n = bytes/sizeof(int32_t);
+ size_t n = bytes/sizeof(int32_t);
for (; n > 0; n--, d += dstr/sizeof(int16_t), s += sstr/sizeof(int32_t))
*d = (int16_t) (*s / 0x10000);
@@ -247,19 +267,19 @@ static int format_s32_to_s16(sa_bbuffer_t *b, void *dst, size_t dstr, const void
static int format_s32_to_s24(sa_bbuffer_t *b, void *dst, size_t dstr, const void *src, size_t sstr, size_t bytes) {
uint8_t *d = dst;
const int32_t *s = src;
- unsigned n = bytes/sizeof(float);
+ size_t n = bytes/sizeof(float);
for (; n > 0; n--, d += dstr/3, s += sstr/sizeof(int32_t)) {
uint32_t j = (uint32_t) (*s) >> 8;
#if defined(SA_LITTLE_ENDIAN)
- d[0] = j & 0xFF;
- d[1] = (j >> 8) & 0xFF;
- d[2] = (j >> 16);
+ d[0] = (uint8_t) j;
+ d[1] = (uint8_t) (j >> 8);
+ d[2] = (uint8_t) (j >> 16);
#elif defined(SA_BIG_ENDIAN)
- d[2] = j & 0xFF;
- d[1] = (j >> 8) & 0xFF;
- d[0] = (j >> 16);
+ d[2] = (uint8_t) j;
+ d[1] = (uint8_t) (j >> 8);
+ d[0] = (uint8_t) (j >> 16);
#else
#error "Unknown byte order"
#endif
@@ -269,11 +289,11 @@ static int format_s32_to_s24(sa_bbuffer_t *b, void *dst, size_t dstr, const void
}
static int format_s32_to_f32(sa_bbuffer_t *b, void *dst, size_t dstr, const void *src, size_t sstr, size_t bytes) {
- float f = 1.0/0x7fffffff;
- unsigned n = bytes/sizeof(int32_t);
+ float f = 1.0f/(float) 0x7fffffff;
+ size_t n = bytes/sizeof(int32_t);
- oil_conv_f32_s32(dst, dstr, src, sstr, n);
- oil_scalarmult_f32(dst, dstr, dst, dstr, &f, n);
+ oil_conv_f32_s32(dst, (int) dstr, src, (int) sstr, (int) n);
+ oil_scalarmult_f32(dst, (int) dstr, dst, (int) dstr, &f, (int) n);
return SA_SUCCESS;
}
@@ -285,14 +305,14 @@ static int format_f32_to_u8(sa_bbuffer_t *b, void *dst, size_t dstr, const void
const float *s = src;
float *buf;
float f = 0x7F, p = 0x80;
- unsigned n = bytes/sizeof(float);
+ size_t n = bytes/sizeof(float);
if (!(buf = sa_bbuffer_get(b, 0, bytes, 1)))
return SA_ERROR_OOM;
- oil_scalarmult_f32(buf, sizeof(float), s, sstr, &f, n);
- oil_scalaradd_f32(buf, sizeof(float), buf, sizeof(float), &p, n);
- oil_clipconv_u8_f32(d, dstr, buf, sizeof(float), n);
+ oil_scalarmult_f32(buf, sizeof(float), s, (int) sstr, &f, (int) n);
+ oil_scalaradd_f32(buf, sizeof(float), buf, sizeof(float), &p, (int) n);
+ oil_clipconv_u8_f32(d, (int) dstr, buf, sizeof(float), (int) n);
return SA_SUCCESS;
}
@@ -300,12 +320,11 @@ static int format_f32_to_u8(sa_bbuffer_t *b, void *dst, size_t dstr, const void
static int format_f32_to_ulaw(sa_bbuffer_t *b, void *dst, size_t dstr, const void *src, size_t sstr, size_t bytes) {
uint8_t *d = dst;
const float *s = src;
- unsigned n = bytes/sizeof(float);
+ size_t n = bytes/sizeof(float);
for (; n > 0; n --, d += dstr, s += sstr/sizeof(float)) {
float v = *s * 0x7FFF;
- if (v < -0x8000) v = -0x8000;
- if (v > -0x7FFF) v = -0x7FFF;
+ v = SA_CLAMP(v, (float) -0x8000, (float) 0x7FFF);
*d = sa_13linear2alaw((int16_t) v);
}
@@ -315,12 +334,11 @@ static int format_f32_to_ulaw(sa_bbuffer_t *b, void *dst, size_t dstr, const voi
static int format_f32_to_alaw(sa_bbuffer_t *b, void *dst, size_t dstr, const void *src, size_t sstr, size_t bytes) {
uint8_t *d = dst;
const float *s = src;
- unsigned n = bytes/sizeof(float);
+ size_t n = bytes/sizeof(float);
for (; n > 0; n --, d += dstr, s += sstr/sizeof(float)) {
float v = *s * 0x7FFF;
- if (v < -0x8000) v = -0x8000;
- if (v > -0x7FFF) v = -0x7FFF;
+ v = SA_CLAMP(v, (float) -0x8000, (float) 0x7FFF);
*d = sa_13linear2alaw((int16_t) v);
}
@@ -332,13 +350,13 @@ static int format_f32_to_s16(sa_bbuffer_t *b, void *dst, size_t dstr, const void
const float *s = src;
float *buf;
float f = 0x7FFF;
- unsigned n = bytes/sizeof(float);
+ size_t n = bytes/sizeof(float);
if (!(buf = sa_bbuffer_get(b, 0, bytes, 1)))
return SA_ERROR_OOM;
- oil_scalarmult_f32(buf, sizeof(float), s, sstr, &f, n);
- oil_clipconv_s16_f32(d, dstr, buf, sizeof(float), n);
+ oil_scalarmult_f32(buf, sizeof(float), s, (int) sstr, &f, (int) n);
+ oil_clipconv_s16_f32(d, (int) dstr, buf, sizeof(float), (int) n);
return SA_SUCCESS;
}
@@ -346,25 +364,24 @@ static int format_f32_to_s16(sa_bbuffer_t *b, void *dst, size_t dstr, const void
static int format_f32_to_s24(sa_bbuffer_t *b, void *dst, size_t dstr, const void *src, size_t sstr, size_t bytes) {
uint8_t *d = dst;
const float *s = src;
- unsigned n = bytes/sizeof(float);
+ size_t n = bytes/sizeof(float);
for (; n > 0; n--, d += dstr/3, s += sstr/sizeof(float)) {
float f = *s / 0x7fffff;
uint32_t j;
- if (f > 0x7fffff) f = 0x7fffff;
- if (f < -0x800000) f = -0x800000;
+ f = SA_CLAMP(f, (float) -0x800000, (float) 0x7FFFFF);
j = (uint32_t) ((int32_t) f);
#if defined(SA_LITTLE_ENDIAN)
- d[0] = j & 0xFF;
- d[1] = (j >> 8) & 0xFF;
- d[2] = (j >> 16);
+ d[0] = (uint8_t) j;
+ d[1] = (uint8_t) (j >> 8);
+ d[2] = (uint8_t) (j >> 16);
#elif defined(SA_BIG_ENDIAN)
- d[2] = j & 0xFF;
- d[1] = (j >> 8) & 0xFF;
- d[0] = (j >> 16);
+ d[2] = (uint8_t) j;
+ d[1] = (uint8_t) (j >> 8);
+ d[0] = (uint8_t) (j >> 16);
#else
#error "Unknown byte order"
#endif
@@ -377,14 +394,14 @@ static int format_f32_to_s32(sa_bbuffer_t *b, void *dst, size_t dstr, const void
int32_t *d = dst;
const float *s = src;
float *buf;
- float f = 0x7FFFFFFF;
- unsigned n = bytes/sizeof(float);
+ float f = (float) 0x7FFFFFFF;
+ size_t n = bytes/sizeof(float);
if (!(buf = sa_bbuffer_get(b, 0, bytes, 1)))
return SA_ERROR_OOM;
- oil_scalarmult_f32(buf, sizeof(float), s, sstr, &f, n);
- oil_clipconv_s32_f32(d, dstr, buf, sizeof(float), n);
+ oil_scalarmult_f32(buf, sizeof(float), s, (int) sstr, &f, (int) n);
+ oil_clipconv_s32_f32(d, (int) dstr, buf, sizeof(float), (int) n);
return SA_SUCCESS;
}
diff --git a/src/format.h b/src/format.h
index 91caf25..75ef6c5 100644
--- a/src/format.h
+++ b/src/format.h
@@ -1,6 +1,26 @@
#ifndef foosydneyformathfoo
#define foosydneyformathfoo
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
#include <sys/types.h>
#include "sydney.h"
diff --git a/src/interleave.c b/src/interleave.c
index 31d1a6b..d5d68d3 100644
--- a/src/interleave.c
+++ b/src/interleave.c
@@ -1,3 +1,23 @@
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@@ -18,7 +38,7 @@ static void interleave8(void *_dst, size_t dstr, const void *_src, size_t sstr,
static void interleave16(void *_dst, size_t dstr, const void *_src, size_t sstr, size_t bytes) {
uint16_t *dst = _dst;
const uint16_t *src = _src;
- unsigned n = bytes / sizeof(uint16_t);
+ size_t n = bytes / sizeof(uint16_t);
for (; n > 0; n--, src += sstr/sizeof(uint16_t), dst += dstr/sizeof(uint16_t))
*dst = *src;
@@ -27,7 +47,7 @@ static void interleave16(void *_dst, size_t dstr, const void *_src, size_t sstr,
static void interleave24(void *_dst, size_t dstr, const void *_src, size_t sstr, size_t bytes) {
uint8_t *dst = _dst;
const uint8_t *src = _src;
- unsigned n = bytes / 3;
+ size_t n = bytes / 3;
for (; n > 0; n--, src += sstr/3, dst += dstr/3) {
dst[0] = src[0];
@@ -39,7 +59,7 @@ static void interleave24(void *_dst, size_t dstr, const void *_src, size_t sstr,
static void interleave32(void *_dst, size_t dstr, const void *_src, size_t sstr, size_t bytes) {
uint32_t *dst = _dst;
const uint32_t *src = _src;
- unsigned n = bytes / sizeof(uint32_t);
+ size_t n = bytes / sizeof(uint32_t);
for (; n > 0; n--, src += sstr/sizeof(uint32_t), dst += dstr/sizeof(uint32_t))
*dst = *src;
diff --git a/src/interleave.h b/src/interleave.h
index add447f..7a297db 100644
--- a/src/interleave.h
+++ b/src/interleave.h
@@ -1,6 +1,26 @@
#ifndef foosydneyinterleavehfoo
#define foosydneyinterleavehfoo
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
#include <sys/types.h>
#include "sydney.h"
diff --git a/src/jack.c b/src/jack.c
new file mode 120000
index 0000000..cc3e685
--- /dev/null
+++ b/src/jack.c
@@ -0,0 +1 @@
+null.c \ No newline at end of file
diff --git a/src/llist.h b/src/llist.h
index f2a5e96..06f507e 100644
--- a/src/llist.h
+++ b/src/llist.h
@@ -1,6 +1,26 @@
#ifndef foosydneyllistfoo
#define foosydneyllistfoo
+/***
+ This file is part of libsydney.
+
+ Copyright 2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
#include "macro.h"
#define SA_LLIST_HEAD(t,head) \
diff --git a/src/macro.c b/src/macro.c
new file mode 100644
index 0000000..824fed1
--- /dev/null
+++ b/src/macro.c
@@ -0,0 +1,34 @@
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "macro.h"
+
+sa_bool_t sa_debug(void) {
+ const char *d;
+
+ if ((d = getenv("SYDNEY_DEBUG")))
+ return !!*d;
+
+ return FALSE;
+}
diff --git a/src/macro.h b/src/macro.h
index 30a7be4..5687dde 100644
--- a/src/macro.h
+++ b/src/macro.h
@@ -1,8 +1,40 @@
#ifndef foosydneymacrohfoo
#define foosydneymacrohfoo
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
#include <stdio.h>
-#include <assert.h>
+#include <stdlib.h>
+
+#ifndef PACKAGE
+#error "Please include config.h before including this file!"
+#endif
+
+#if defined (__GNUC__) && __GNUC__ >= 3
+#define SA_LIKELY(x) (__builtin_expect(!!(x),1))
+#define SA_UNLIKELY(x) (__builtin_expect((x),0))
+#else
+#define SA_LIKELY(x) (x)
+#define SA_UNLIKELY(x) (x)
+#endif
#ifdef __GNUC__
#define SA_PRETTY_FUNCTION __PRETTY_FUNCTION__
@@ -10,69 +42,102 @@
#define SA_PRETTY_FUNCTION ""
#endif
-#define sa_return_if_fail(expr) \
- do { \
- if (!(expr)) { \
- fprintf(stderr, "%s: Assertion <%s> failed.\n", SA_PRETTY_FUNCTION, #expr ); \
- return; \
- } \
- } while(0)
+#define sa_return_if_fail(expr) \
+ do { \
+ if (SA_UNLIKELY(!(expr))) { \
+ if (sa_debug()) \
+ fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n", #expr , __FILE__, __LINE__, SA_PRETTY_FUNCTION); \
+ return; \
+ } \
+ } while(FALSE)
#define sa_return_val_if_fail(expr, val) \
do { \
- if (!(expr)) { \
- fprintf(stderr, "%s: Assertion <%s> failed.\n", SA_PRETTY_FUNCTION, #expr ); \
- return (val); \
- } \
- } while(0)
-
-#define sa_return_if_fail_mutex(m, expr) \
- do { \
- if (!(expr)) { \
- fprintf(stderr, "%s: Assertion <%s> failed.\n", SA_PRETTY_FUNCTION, #expr ); \
- sa_mutex_unlock(m); \
- return; \
- } \
- } while(0)
-
-#define sa_return_val_if_fail_mutex(m, expr, val) \
- do { \
- if (!(expr)) { \
- \
- fprintf(stderr, "%s: Assertion <%s> failed.\n", SA_PRETTY_FUNCTION, #expr ); \
- sa_mutex_unlock(m); \
- return (val); \
- } \
- } while(0)
-
-#define sa_assert assert
-
-/* An assert which guarantees side effects of x */
+ if (SA_UNLIKELY(!(expr))) { \
+ if (sa_debug()) \
+ fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n", #expr , __FILE__, __LINE__, SA_PRETTY_FUNCTION); \
+ return (val); \
+ } \
+ } while(FALSE)
+
+#define sa_return_null_if_fail(expr) sa_return_val_if_fail(expr, NULL)
+
+#define sa_return_if_fail_unlock(expr, mutex) \
+ do { \
+ if (SA_UNLIKELY(!(expr))) { \
+ if (sa_debug()) \
+ fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n", #expr , __FILE__, __LINE__, SA_PRETTY_FUNCTION); \
+ sa_mutex_unlock(mutex); \
+ return; \
+ } \
+ } while(FALSE)
+
+#define sa_return_val_if_fail_unlock(expr, val, mutex) \
+ do { \
+ if (SA_UNLIKELY(!(expr))) { \
+ if (sa_debug()) \
+ fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s().\n", #expr , __FILE__, __LINE__, SA_PRETTY_FUNCTION); \
+ sa_mutex_unlock(mutex); \
+ return (val); \
+ } \
+ } while(FALSE)
+
+#define sa_return_null_if_fail_unlock(expr, mutex) sa_return_val_if_fail_unlock(expr, NULL, mutex)
+
+/* An assert which guarantees side effects of x, i.e. is never
+ * optimized away */
+#define sa_assert_se(expr) \
+ do { \
+ if (SA_UNLIKELY(!(expr))) { \
+ fprintf(stderr, "Assertion '%s' failed at %s:%u, function %s(). Aborting.\n", #expr , __FILE__, __LINE__, SA_PRETTY_FUNCTION); \
+ abort(); \
+ } \
+ } while (FALSE)
+
+/* An assert that may be optimized away by defining NDEBUG */
#ifdef NDEBUG
-#define sa_assert_se(x) x
+#define sa_assert(expr) do {} while (FALSE)
#else
-#define sa_assert_se(x) sa_assert(x)
+#define sa_assert(expr) sa_assert_se(expr)
#endif
-#define sa_assert_not_reached() sa_assert(!"Should not be reached.")
-
-#define sa_assert_success(x) do { \
- int _r = (x); \
- sa_assert(_r == 0); \
- } while(0)
+#define sa_assert_not_reached() \
+ do { \
+ fprintf(stderr, "Code should not be reached at %s:%u, function %s(). Aborting.\n", __FILE__, __LINE__, SA_PRETTY_FUNCTION); \
+ abort(); \
+ } while (FALSE)
#define SA_ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0]))
-#ifndef MAX
-#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#ifdef __GNUC__
+#define SA_MAX(a,b) \
+ __extension__ ({ typeof(a) _a = (a); \
+ typeof(b) _b = (b); \
+ _a > _b ? _a : _b; \
+ })
+#else
+#define SA_MAX(a, b) ((a) > (b) ? (a) : (b))
#endif
-#ifndef MIN
-#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#ifdef __GNUC__
+#define SA_MIN(a,b) \
+ __extension__ ({ typeof(a) _a = (a); \
+ typeof(b) _b = (b); \
+ _a < _b ? _a : _b; \
+ })
+#else
+#define SA_MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
-#ifndef CLAMP
-#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
+#ifdef __GNUC__
+#define SA_CLAMP(x, low, high) \
+ __extension__ ({ typeof(x) _x = (x); \
+ typeof(low) _low = (low); \
+ typeof(high) _high = (high); \
+ ((_x > _high) ? _high : ((_x < _low) ? _low : _x)); \
+ })
+#else
+#define SA_CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
#endif
#ifndef FALSE
@@ -95,6 +160,10 @@
#define SA_PTR_TO_INT32(p) ((int32_t) SA_PTR_TO_UINT(p))
#define SA_INT32_TO_PTR(u) SA_UINT_TO_PTR((int32_t) u)
+typedef int sa_bool_t;
+
+sa_bool_t sa_debug(void);
+
static inline size_t sa_align(size_t l) {
return (((l + sizeof(void*) - 1) / sizeof(void*)) * sizeof(void*));
}
@@ -103,16 +172,78 @@ static inline size_t sa_align(size_t l) {
typedef void (*sa_free_cb_t)(void *);
-typedef int sa_bool_t;
+#ifdef HAVE_BYTESWAP_H
+#include <byteswap.h>
+#endif
+
+#ifdef HAVE_BYTESWAP_H
+#define SA_INT16_SWAP(x) ((int16_t) bswap_16((uint16_t) x))
+#define SA_UINT16_SWAP(x) ((uint16_t) bswap_16((uint16_t) x))
+#define SA_INT32_SWAP(x) ((int32_t) bswap_32((uint32_t) x))
+#define SA_UINT32_SWAP(x) ((uint32_t) bswap_32((uint32_t) x))
+#else
+#define SA_INT16_SWAP(x) ( (int16_t) ( ((uint16_t) x >> 8) | ((uint16_t) x << 8) ) )
+#define SA_UINT16_SWAP(x) ( (uint16_t) ( ((uint16_t) x >> 8) | ((uint16_t) x << 8) ) )
+#define SA_INT32_SWAP(x) ( (int32_t) ( ((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 8) | ((((uint32_t) x) >> 8) & 0xFF00) ) )
+#define SA_UINT32_SWAP(x) ( (uint32_t) ( ((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 8) | ((((uint32_t) x) >> 8) & 0xFF00) ) )
+#endif
+
+#ifdef WORDS_BIGENDIAN
+ #define SA_INT16_FROM_LE(x) SA_INT16_SWAP(x)
+ #define SA_INT16_FROM_BE(x) ((int16_t)(x))
+
+ #define SA_INT16_TO_LE(x) SA_INT16_SWAP(x)
+ #define SA_INT16_TO_BE(x) ((int16_t)(x))
+
+ #define SA_UINT16_FROM_LE(x) SA_UINT16_SWAP(x)
+ #define SA_UINT16_FROM_BE(x) ((uint16_t)(x))
+
+ #define SA_UINT16_TO_LE(x) SA_UINT16_SWAP(x)
+ #define SA_UINT16_TO_BE(x) ((uint16_t)(x))
+
+ #define SA_INT32_FROM_LE(x) SA_INT32_SWAP(x)
+ #define SA_INT32_FROM_BE(x) ((int32_t)(x))
+
+ #define SA_INT32_TO_LE(x) SA_INT32_SWAP(x)
+ #define SA_INT32_TO_BE(x) ((int32_t)(x))
-/* Guard C code in headers, while including them from C++ */
-#ifdef __cplusplus
-# define SA_BEGIN_DECLS extern "C" {
-# define SA_END_DECLS }
+ #define SA_UINT32_FROM_LE(x) SA_UINT32_SWAP(x)
+ #define SA_UINT32_FROM_BE(x) ((uint32_t)(x))
+
+ #define SA_UINT32_TO_LE(x) SA_UINT32_SWAP(x)
+ #define SA_UINT32_TO_BE(x) ((uint32_t)(x))
#else
-# define SA_BEGIN_DECLS
-# define SA_END_DECLS
+ #define SA_INT16_FROM_LE(x) ((int16_t)(x))
+ #define SA_INT16_FROM_BE(x) SA_INT16_SWAP(x)
+
+ #define SA_INT16_TO_LE(x) ((int16_t)(x))
+ #define SA_INT16_TO_BE(x) SA_INT16_SWAP(x)
+
+ #define SA_UINT16_FROM_LE(x) ((uint16_t)(x))
+ #define SA_UINT16_FROM_BE(x) SA_UINT16_SWAP(x)
+
+ #define SA_UINT16_TO_LE(x) ((uint16_t)(x))
+ #define SA_UINT16_TO_BE(x) SA_UINT16_SWAP(x)
+
+ #define SA_INT32_FROM_LE(x) ((int32_t)(x))
+ #define SA_INT32_FROM_BE(x) SA_INT32_SWAP(x)
+
+ #define SA_INT32_TO_LE(x) ((int32_t)(x))
+ #define SA_INT32_TO_BE(x) SA_INT32_SWAP(x)
+
+ #define SA_UINT32_FROM_LE(x) ((uint32_t)(x))
+ #define SA_UINT32_FROM_BE(x) SA_UINT32_SWAP(x)
+
+ #define SA_UINT32_TO_LE(x) ((uint32_t)(x))
+ #define SA_UINT32_TO_BE(x) SA_UINT32_SWAP(x)
#endif
+#define sa_streq(a, b) (strcmp((a),(b)) == 0)
+
+#ifdef __GNUC__
+#define SA_GCC_DESTRUCTOR __attribute__ ((destructor))
+#else
+#undef SA_GCC_DESTRUCTOR
+#endif
#endif
diff --git a/src/malloc.c b/src/malloc.c
index a5171fa..e6a961b 100644
--- a/src/malloc.c
+++ b/src/malloc.c
@@ -1,12 +1,136 @@
+/***
+ This file is part of libsydney.
+
+ Copyright 2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <errno.h>
#include "macro.h"
#include "malloc.h"
+static sa_allocator allocator = {
+ .malloc = NULL,
+ .calloc = NULL,
+ .free = NULL,
+ .realloc = NULL
+};
+
+void* sa_malloc(size_t size) {
+ void *ptr;
+
+ if (size <= 0)
+ return NULL;
+
+ if (allocator.malloc)
+ ptr = allocator.malloc(size);
+ else
+ ptr = malloc(size);
+
+ if (!ptr)
+ errno = ENOMEM;
+
+ return ptr;
+}
+
+void sa_free(void *ptr) {
+ int saved_errno;
+
+ if (!ptr)
+ return;
+
+ saved_errno = errno;
+
+ if (allocator.free)
+ allocator.free(ptr);
+ else
+ free(ptr);
+
+ errno = saved_errno;
+}
+
+void* sa_malloc0(size_t size) {
+ void *ptr;
+
+ if (size <= 0)
+ return NULL;
+
+ if (allocator.calloc)
+ ptr = allocator.calloc(1, size);
+ else if (allocator.malloc) {
+ if ((ptr = allocator.malloc(size)))
+ memset(ptr, 0, size);
+ } else
+ ptr = calloc(1, size);
+
+ if (!ptr)
+ errno = ENOMEM;
+
+ return ptr;
+}
+
+char *sa_strdup(const char *s) {
+ char *p;
+ size_t n_avail;
+
+ if (!s)
+ return NULL;
+
+ n_avail = strlen(s);
+
+ if (!(p = sa_new(char, n_avail + 1)))
+ return NULL;
+
+ memcpy(p, s, n_avail);
+ p[n_avail] = 0;
+
+ return p;
+}
+
+char *sa_strndup(const char *s, size_t n) {
+ size_t n_avail;
+ char *p;
+
+ if (!s)
+ return NULL;
+
+ if (memchr(s, '\0', n)) {
+ n_avail = strlen(s);
+ if (n_avail > n)
+ n_avail = n;
+ } else
+ n_avail = n;
+
+ if (!(p = sa_new(char, n_avail + 1)))
+ return NULL;
+
+ memcpy(p, s, n_avail);
+ p[n_avail] = 0;
+
+ return p;
+}
+
void* sa_memdup(const void* p, size_t size) {
void *r;
@@ -18,3 +142,38 @@ void* sa_memdup(const void* p, size_t size) {
memcpy(r, p, size);
return r;
}
+
+char *sa_sprintf_malloc(const char *format, ...) {
+ size_t size = 100;
+ char *c = NULL;
+
+ sa_assert(format);
+
+ for(;;) {
+ int r;
+ va_list ap;
+
+ sa_free(c);
+
+ if (!(c = sa_new(char, size)))
+ return NULL;
+
+ va_start(ap, format);
+ r = vsnprintf(c, size, format, ap);
+ va_end(ap);
+
+ c[size-1] = 0;
+
+ if (r > -1 && (size_t) r < size)
+ return c;
+
+ if (r > -1) /* glibc 2.1 */
+ size = (size_t) r+1;
+ else /* glibc 2.0 */
+ size *= 2;
+ }
+}
+
+void sa_set_allocator(const sa_allocator *a) {
+ memcpy(&allocator, a, sizeof(allocator));
+}
diff --git a/src/malloc.h b/src/malloc.h
index b969988..9281ee4 100644
--- a/src/malloc.h
+++ b/src/malloc.h
@@ -1,19 +1,43 @@
#ifndef foosydneymallochfoo
#define foosydneymallochfoo
+/***
+ This file is part of libsydney.
+
+ Copyright 2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
#include <stdlib.h>
#include <string.h>
-#define sa_malloc malloc
-#define sa_free free
-#define sa_malloc0(size) calloc(1, (size))
-#define sa_strdup strdup
-#define sa_strndup strndup
+#include "sydney.h"
+#include "macro.h"
+void* sa_malloc(size_t size);
+void* sa_malloc0(size_t size);
+void sa_free(void *ptr);
+char *sa_strdup(const char *s);
+char *sa_strndup(const char *s, size_t n);
void* sa_memdup(const void* p, size_t size);
#define sa_new(t, n) ((t*) sa_malloc(sizeof(t)*(n)))
#define sa_new0(t, n) ((t*) sa_malloc0(sizeof(t)*(n)))
#define sa_newdup(t, p, n) ((t*) sa_memdup(p, sizeof(t)*(n)))
+char *sa_sprintf_malloc(const char *format, ...) __attribute__((format(printf, 1, 2)));
+
#endif
diff --git a/src/map-file b/src/map-file
new file mode 100644
index 0000000..46a5d6d
--- /dev/null
+++ b/src/map-file
@@ -0,0 +1,24 @@
+SYDNEY_0 {
+local:
+driver_change_device;
+driver_change_pcm_rate;
+driver_change_props;
+driver_change_read_latency;
+driver_change_read_volume;
+driver_change_write_latency;
+driver_change_write_volume;
+driver_destroy;
+driver_drain;
+driver_get_position;
+driver_get_read_size;
+driver_get_state;
+driver_get_write_size;
+driver_open;
+driver_pause;
+driver_pwrite;
+driver_pwrite_ni;
+driver_read;
+driver_read_ni;
+driver_resume;
+driver_wait;
+};
diff --git a/src/mutex-posix.c b/src/mutex-posix.c
index 436696c..65163a9 100644
--- a/src/mutex-posix.c
+++ b/src/mutex-posix.c
@@ -1,3 +1,23 @@
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
diff --git a/src/mutex.h b/src/mutex.h
index c24acb6..f0303ba 100644
--- a/src/mutex.h
+++ b/src/mutex.h
@@ -1,6 +1,26 @@
#ifndef foosydneymutexhfoo
#define foosydneymutexhfoo
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
#include "macro.h"
typedef struct sa_mutex sa_mutex;
diff --git a/src/null.c b/src/null.c
new file mode 100644
index 0000000..7948be6
--- /dev/null
+++ b/src/null.c
@@ -0,0 +1,111 @@
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "driver.h"
+#include "common.h"
+#include "malloc.h"
+
+int driver_open(sa_stream *s) {
+ return SA_ERROR_NOTAVAILABLE;
+}
+
+int driver_destroy(sa_stream *s) {
+ return SA_ERROR_INVALID;
+}
+
+int driver_change_write_latency(sa_stream *s, size_t *latency, size_t *process_time) {
+ return SA_ERROR_INVALID;
+}
+
+int driver_change_read_latency(sa_stream *s, size_t *latency, size_t *process_time) {
+ return SA_ERROR_INVALID;
+}
+
+int driver_change_device(sa_stream *s, const char *device_name) {
+ return SA_ERROR_INVALID;
+}
+
+int driver_change_read_volume(sa_stream *s, const int32_t vol[]) {
+ return SA_ERROR_INVALID;
+}
+
+int driver_change_write_volume(sa_stream *s, const int32_t vol[]) {
+ return SA_ERROR_INVALID;
+}
+
+int driver_change_pcm_rate(sa_stream *s, unsigned rate) {
+ return SA_ERROR_INVALID;
+}
+
+int driver_change_props(sa_stream *s, sa_proplist *changed, sa_proplist *merged) {
+ return SA_ERROR_INVALID;
+}
+
+int driver_get_state(sa_stream *s, sa_state_t *state) {
+ return SA_ERROR_INVALID;
+}
+
+int driver_get_position(sa_stream *s, sa_position_t position, int64_t *pos) {
+ return SA_ERROR_INVALID;
+}
+
+int driver_wait(sa_stream *s) {
+ return SA_ERROR_INVALID;
+}
+
+int driver_read(sa_stream *s, void *data, size_t nbytes) {
+ return SA_ERROR_INVALID;
+}
+
+int driver_read_ni(sa_stream *s, unsigned channel, void *data, size_t nbytes) {
+ return SA_ERROR_INVALID;
+}
+
+int driver_pwrite(sa_stream *s, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence) {
+ return SA_ERROR_INVALID;
+}
+
+int driver_pwrite_ni(sa_stream *s, unsigned channel, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence) {
+ return SA_ERROR_INVALID;
+}
+
+int driver_get_read_size(sa_stream *s, size_t *size) {
+ return SA_ERROR_INVALID;
+}
+
+int driver_get_write_size(sa_stream *s, size_t *size) {
+ return SA_ERROR_INVALID;
+}
+
+int driver_resume(sa_stream *s) {
+ return SA_ERROR_INVALID;
+}
+
+int driver_pause(sa_stream *s) {
+ return SA_ERROR_INVALID;
+}
+
+int driver_drain(sa_stream *s) {
+ return SA_ERROR_INVALID;
+}
diff --git a/src/oss.c b/src/oss.c
index 410fa45..a60412b 100644
--- a/src/oss.c
+++ b/src/oss.c
@@ -1,3 +1,23 @@
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@@ -13,6 +33,17 @@
#include <sys/types.h>
#include <sys/socket.h>
+#ifdef HAVE_MACHINE_SOUNDCARD_H
+# include <machine/soundcard.h>
+#else
+# ifdef HAVE_SOUNDCARD_H
+# include <soundcard.h>
+# else
+# include <sys/soundcard.h>
+# endif
+#endif
+
+
#include "sydney.h"
#include "common.h"
#include "macro.h"
@@ -23,13 +54,9 @@
#include "bufferq.h"
#define DEFAULT_DEVICE "/dev/dsp"
-#define DRIVER_NAME "oss"
-
-typedef struct oss_stream oss_stream_t;
-#define OSS_STREAM(x) ((oss_stream_t*) (x->private))
-struct oss_stream {
- sa_stream_t *parent;
+struct private {
+ sa_stream *parent;
int fd;
pcm_attrs_t real_pcm_attrs;
sa_converter_t converter_read, converter_write;
@@ -42,27 +69,37 @@ struct oss_stream {
void *cdata;
};
-static int simple_log2(int v) {
- int k = 0;
+#define PRIVATE(c) ((struct private *) ((c)->private))
+
+static inline unsigned ulog2(unsigned n) {
+
+ if (n <= 1)
+ return 0;
+
+#if __GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+ return 8U * (unsigned) sizeof(unsigned) - (unsigned) __builtin_clz(n) - 1;
+#else
+{
+ unsigned r = 0;
for (;;) {
- v >>= 1;
- if (!v) break;
- k++;
- }
+ n = n >> 1;
+
+ if (!n)
+ return r;
- return k;
+ r++;
+ }
}
-#ifdef HAVE_CONFIG_H
-#include <config.h>
#endif
+}
static size_t fixup_bps(size_t s, size_t bps1, size_t bps2) {
return (s*bps2)/bps1;
}
-int driver_open(sa_stream_t *s) {
- oss_stream_t *oss;
+int driver_open(sa_stream *s) {
+ struct private *p;
char *n;
int f, arg, bs, r, phase, i, found, suggested, fs, l, m;
unsigned c;
@@ -84,14 +121,14 @@ int driver_open(sa_stream_t *s) {
};
static const int try_rates[] = { 8000, 16000, 32000, 44100, 48000, 96000, 192000 };
- if (s->driver && strcmp(s->driver, DRIVER_NAME))
- return SA_ERROR_NO_DRIVER;
+ if (s->driver && !sa_streq(s->driver, "oss"))
+ return SA_ERROR_NODRIVER;
- if (!(s->private = oss = sa_new0(oss_stream_t, 1)))
+ if (!(s->private = p = sa_new0(struct private, 1)))
return SA_ERROR_OOM;
- oss->parent = s;
- oss->socket_fds[0] = oss->socket_fds[1] = -1;
+ p->parent = s;
+ p->socket_fds[0] = p->socket_fds[1] = -1;
n = s->device ? s->device : (char*) DEFAULT_DEVICE;
if (!s->codec)
@@ -106,17 +143,17 @@ int driver_open(sa_stream_t *s) {
* SETFRAGMENT again which can do only after reopening the
* device again. */
- if ((oss->fd = open(n, s->mode == SA_MODE_RDONLY ? O_RDONLY : (s->mode == SA_MODE_WRONLY ? O_WRONLY : O_RDWR) | O_NOCTTY | O_NONBLOCK)) < 0) {
+ if ((p->fd = open(n, s->mode == SA_MODE_RDONLY ? O_RDONLY : (s->mode == SA_MODE_WRONLY ? O_WRONLY : O_RDWR) | O_NOCTTY | O_NONBLOCK)) < 0) {
if (errno == ENODEV || errno == ENOENT)
- r = SA_ERROR_NO_DEVICE;
+ r = SA_ERROR_NODEVICE;
else
r = SA_ERROR_SYSTEM;
goto fail;
}
- fcntl(oss->fd, F_SETFL, fcntl(oss->fd, F_GETFL) & ~O_NONBLOCK); /* FIXME*/
+ fcntl(p->fd, F_SETFL, fcntl(p->fd, F_GETFL) & ~O_NONBLOCK); /* FIXME*/
if (!s->device) {
if (!(n = sa_strdup(n))) {
@@ -146,10 +183,10 @@ int driver_open(sa_stream_t *s) {
}
if (!s->codec && real_bps)
- bs = fixup_bps(bs, bps, real_bps);
+ bs = (int) fixup_bps((size_t) bs, bps, real_bps);
fs = bs/4;
- l = simple_log2(fs);
+ l = ulog2(fs);
if (l < 1) l = 1;
m = (bs+(1<<l)-1)/(1<<l);
if (m < 2) m = 2;
@@ -159,7 +196,7 @@ int driver_open(sa_stream_t *s) {
arg = (m << 16) | l;
- ioctl(oss->fd, SNDCTL_DSP_SETFRAGMENT, &arg);
+ ioctl(p->fd, SNDCTL_DSP_SETFRAGMENT, &arg);
/* We ignore errors on this call, since it's merely a hint anyway */
if (s->codec) {
@@ -169,7 +206,7 @@ int driver_open(sa_stream_t *s) {
else if (strcmp(s->codec, SA_CODEC_MPEG) == 0)
f = AFMT_MPEG;
else {
- r = SA_ERROR_NO_CODEC;
+ r = SA_ERROR_NOCODEC;
goto fail;
}
@@ -181,7 +218,7 @@ int driver_open(sa_stream_t *s) {
for (;;) {
arg = f;
- if (ioctl(oss->fd, SNDCTL_DSP_SETFMT, &arg) < 0) {
+ if (ioctl(p->fd, SNDCTL_DSP_SETFMT, &arg) < 0) {
r = SA_ERROR_SYSTEM;
goto fail;
}
@@ -210,10 +247,10 @@ int driver_open(sa_stream_t *s) {
} else if (f == AFMT_A_LAW || f == AFMT_MU_LAW) {
f = AFMT_U8;
} else if (f == AFMT_AC3 || f == AFMT_MPEG) {
- r = SA_ERROR_NO_CODEC;
+ r = SA_ERROR_NOCODEC;
goto fail;
} else {
- r = SA_ERROR_NO_PCM_FORMAT;
+ r = SA_ERROR_NOPCMFORMAT;
goto fail;
}
}
@@ -222,23 +259,23 @@ int driver_open(sa_stream_t *s) {
switch (f) {
case AFMT_MU_LAW:
- oss->real_pcm_attrs.format = SA_PCM_FORMAT_ULAW;
+ p->real_pcm_attrs.format = SA_PCM_FORMAT_ULAW;
break;
case AFMT_A_LAW:
- oss->real_pcm_attrs.format = SA_PCM_FORMAT_ALAW;
+ p->real_pcm_attrs.format = SA_PCM_FORMAT_ALAW;
break;
case AFMT_U8:
- oss->real_pcm_attrs.format = SA_PCM_FORMAT_U8;
+ p->real_pcm_attrs.format = SA_PCM_FORMAT_U8;
break;
case AFMT_S16_LE:
- oss->real_pcm_attrs.format = SA_PCM_FORMAT_S16_LE;
+ p->real_pcm_attrs.format = SA_PCM_FORMAT_S16_LE;
break;
case AFMT_S16_BE:
- oss->real_pcm_attrs.format = SA_PCM_FORMAT_S16_BE;
+ p->real_pcm_attrs.format = SA_PCM_FORMAT_S16_BE;
break;
default:
@@ -252,8 +289,8 @@ int driver_open(sa_stream_t *s) {
/* First try more channels ... */
for (c = s->pcm_attrs.nchannels; c < 8 || c == s->pcm_attrs.nchannels; c ++) {
- arg = c;
- if (ioctl(oss->fd, SNDCTL_DSP_CHANNELS, &arg) < 0) {
+ arg = (int) c;
+ if (ioctl(p->fd, SNDCTL_DSP_CHANNELS, &arg) < 0) {
r = SA_ERROR_SYSTEM;
goto fail;
}
@@ -267,8 +304,8 @@ int driver_open(sa_stream_t *s) {
/* ... then try less channels */
if (!found) {
for (c = s->pcm_attrs.nchannels - 1; c > 0; c --) {
- arg = c;
- if (ioctl(oss->fd, SNDCTL_DSP_CHANNELS, &arg) < 0) {
+ arg = (int) c;
+ if (ioctl(p->fd, SNDCTL_DSP_CHANNELS, &arg) < 0) {
r = SA_ERROR_SYSTEM;
goto fail;
}
@@ -283,8 +320,8 @@ int driver_open(sa_stream_t *s) {
/* First try less channels ... */
for (c = s->pcm_attrs.nchannels; c > 0; c --) {
- arg = c;
- if (ioctl(oss->fd, SNDCTL_DSP_CHANNELS, &arg) < 0) {
+ arg = (int) c;
+ if (ioctl(p->fd, SNDCTL_DSP_CHANNELS, &arg) < 0) {
r = SA_ERROR_SYSTEM;
goto fail;
}
@@ -299,7 +336,7 @@ int driver_open(sa_stream_t *s) {
if (!found) {
for (c = s->pcm_attrs.nchannels + 1; c < 8; c ++) {
arg = c;
- if (ioctl(oss->fd, SNDCTL_DSP_CHANNELS, &arg) < 0) {
+ if (ioctl(p->fd, SNDCTL_DSP_CHANNELS, &arg) < 0) {
r = SA_ERROR_SYSTEM;
goto fail;
}
@@ -318,32 +355,32 @@ int driver_open(sa_stream_t *s) {
goto fail;
}
- oss->real_pcm_attrs.nchannels = c;
+ p->real_pcm_attrs.nchannels = c;
- if (!(oss->real_pcm_attrs.channel_map = sa_new(sa_channel_t, c))) {
+ if (!(p->real_pcm_attrs.channel_map = sa_new(sa_channel_t, c))) {
r = SA_ERROR_OOM;
goto fail;
}
switch (c) {
case 8:
- oss->real_pcm_attrs.channel_map[7] = SA_CHANNEL_REAR_RIGHT;
+ p->real_pcm_attrs.channel_map[7] = SA_CHANNEL_REAR_RIGHT;
case 7:
- oss->real_pcm_attrs.channel_map[6] = SA_CHANNEL_REAR_LEFT;
+ p->real_pcm_attrs.channel_map[6] = SA_CHANNEL_REAR_LEFT;
case 6:
- oss->real_pcm_attrs.channel_map[5] = SA_CHANNEL_FRONT_LEFT;
+ p->real_pcm_attrs.channel_map[5] = SA_CHANNEL_FRONT_LEFT;
case 5:
- oss->real_pcm_attrs.channel_map[4] = SA_CHANNEL_FRONT_RIGHT;
+ p->real_pcm_attrs.channel_map[4] = SA_CHANNEL_FRONT_RIGHT;
case 4:
- oss->real_pcm_attrs.channel_map[3] = SA_CHANNEL_LFE;
+ p->real_pcm_attrs.channel_map[3] = SA_CHANNEL_LFE;
case 3:
- oss->real_pcm_attrs.channel_map[2] = SA_CHANNEL_CENTER;
+ p->real_pcm_attrs.channel_map[2] = SA_CHANNEL_CENTER;
case 2:
- oss->real_pcm_attrs.channel_map[1] = SA_CHANNEL_RIGHT;
- oss->real_pcm_attrs.channel_map[0] = SA_CHANNEL_LEFT;
+ p->real_pcm_attrs.channel_map[1] = SA_CHANNEL_RIGHT;
+ p->real_pcm_attrs.channel_map[0] = SA_CHANNEL_LEFT;
break;
case 1:
- oss->real_pcm_attrs.channel_map[0] = SA_CHANNEL_MONO;
+ p->real_pcm_attrs.channel_map[0] = SA_CHANNEL_MONO;
break;
}
@@ -358,7 +395,7 @@ int driver_open(sa_stream_t *s) {
for (;;) {
arg = r;
- if (ioctl(oss->fd, SNDCTL_DSP_SPEED, &arg) < 0) {
+ if (ioctl(p->fd, SNDCTL_DSP_SPEED, &arg) < 0) {
r = SA_ERROR_SYSTEM;
goto fail;
}
@@ -446,19 +483,19 @@ int driver_open(sa_stream_t *s) {
}
- oss->real_pcm_attrs.rate = r;
+ p->real_pcm_attrs.rate = r;
- printf("Chosen: %u channels, %uHz, format=%u\n", oss->real_pcm_attrs.nchannels, oss->real_pcm_attrs.rate, oss->real_pcm_attrs.format);
+ printf("Chosen: %u channels, %uHz, format=%u\n", p->real_pcm_attrs.nchannels, p->real_pcm_attrs.rate, p->real_pcm_attrs.format);
- real_bps = oss->real_pcm_attrs.nchannels * oss->real_pcm_attrs.rate * sa_get_pcm_sample_size(oss->real_pcm_attrs.format);
+ real_bps = p->real_pcm_attrs.nchannels * p->real_pcm_attrs.rate * sa_get_pcm_sample_size(p->real_pcm_attrs.format);
if (real_bps != bps && loops < 1) {
loops++;
- sa_free(oss->real_pcm_attrs.channel_map);
- oss->real_pcm_attrs.channel_map = NULL;
+ sa_free(p->real_pcm_attrs.channel_map);
+ p->real_pcm_attrs.channel_map = NULL;
- close(oss->fd);
+ close(p->fd);
printf("bps changed, retrying...\n");
continue;
@@ -469,15 +506,15 @@ int driver_open(sa_stream_t *s) {
}
/* First, let's try GETBLKSIZE */
- if (ioctl(oss->fd, SNDCTL_DSP_GETBLKSIZE, &arg) >= 0) {
+ if (ioctl(p->fd, SNDCTL_DSP_GETBLKSIZE, &arg) >= 0) {
if (s->mode & SA_MODE_RDONLY) {
- oss->read_fragment_size = arg;
- oss->read_nfragments = 2;
+ p->read_fragment_size = arg;
+ p->read_nfragments = 2;
}
if (s->mode & SA_MODE_WRONLY) {
- oss->write_fragment_size = arg;
- oss->write_nfragments = 2;
+ p->write_fragment_size = arg;
+ p->write_nfragments = 2;
}
}
@@ -485,28 +522,28 @@ int driver_open(sa_stream_t *s) {
if (s->mode & SA_MODE_RDONLY) {
audio_buf_info info;
- if (ioctl(oss->fd, SNDCTL_DSP_GETISPACE, &info) >= 0) {
- oss->read_fragment_size = info.fragsize;
- oss->read_nfragments = info.fragstotal;
+ if (ioctl(p->fd, SNDCTL_DSP_GETISPACE, &info) >= 0) {
+ p->read_fragment_size = info.fragsize;
+ p->read_nfragments = info.fragstotal;
}
}
if (s->mode & SA_MODE_WRONLY) {
audio_buf_info info;
- if (ioctl(oss->fd, SNDCTL_DSP_GETOSPACE, &info) >= 0) {
- oss->write_fragment_size = info.fragsize;
- oss->write_nfragments = info.fragstotal;
+ if (ioctl(p->fd, SNDCTL_DSP_GETOSPACE, &info) >= 0) {
+ p->write_fragment_size = info.fragsize;
+ p->write_nfragments = info.fragstotal;
}
}
- if (s->mode & SA_MODE_WRONLY && (oss->write_fragment_size <= 0 || oss->write_nfragments <= 1)) {
+ if (s->mode & SA_MODE_WRONLY && (p->write_fragment_size <= 0 || p->write_nfragments <= 1)) {
errno = EIO;
r = SA_ERROR_SYSTEM;
goto fail;
}
- if (s->mode & SA_MODE_RDONLY && (oss->read_fragment_size <= 0 || oss->read_nfragments <= 1)) {
+ if (s->mode & SA_MODE_RDONLY && (p->read_fragment_size <= 0 || p->read_nfragments <= 1)) {
errno = EIO;
r = SA_ERROR_SYSTEM;
goto fail;
@@ -517,7 +554,7 @@ int driver_open(sa_stream_t *s) {
if (s->adjust_nchannels != 0) {
sa_channel_t *cm;
- if (!(cm = sa_newdup(sa_channel_t, oss->real_pcm_attrs.channel_map, oss->real_pcm_attrs.nchannels))) {
+ if (!(cm = sa_newdup(sa_channel_t, p->real_pcm_attrs.channel_map, p->real_pcm_attrs.nchannels))) {
r = SA_ERROR_OOM;
goto fail;
}
@@ -525,45 +562,45 @@ int driver_open(sa_stream_t *s) {
sa_free(s->pcm_attrs.channel_map);
s->pcm_attrs.channel_map = cm;
- s->pcm_attrs.nchannels = oss->real_pcm_attrs.nchannels;
+ s->pcm_attrs.nchannels = p->real_pcm_attrs.nchannels;
}
if (s->adjust_rate != 0)
- s->pcm_attrs.rate = oss->real_pcm_attrs.rate;
+ s->pcm_attrs.rate = p->real_pcm_attrs.rate;
if (s->adjust_pcm_format != 0)
- s->pcm_attrs.format = oss->real_pcm_attrs.format;
+ s->pcm_attrs.format = p->real_pcm_attrs.format;
if (s->mode & SA_MODE_RDONLY)
- if ((r = sa_converter_init(&oss->converter_read, &oss->real_pcm_attrs, &s->pcm_attrs, s->dynamic_rate_enabled)) < 0)
+ if ((r = sa_converter_init(&p->converter_read, &p->real_pcm_attrs, &s->pcm_attrs, s->dynamic_rate_enabled)) < 0)
goto fail;
if (s->mode & SA_MODE_WRONLY)
- if ((r = sa_converter_init(&oss->converter_write, &s->pcm_attrs, &oss->real_pcm_attrs, s->dynamic_rate_enabled)) < 0)
+ if ((r = sa_converter_init(&p->converter_write, &s->pcm_attrs, &p->real_pcm_attrs, s->dynamic_rate_enabled)) < 0)
goto fail;
}
/* if (s->adjust_watermarks) { */
/* if (s->mode & SA_MODE_RDONLY) { */
-/* s->read_lower_watermark = oss->read_fragment_size; */
-/* s->read_upper_watermark = oss->read_fragment_size * oss->read_nfragments; */
+/* s->read_lower_watermark = p->read_fragment_size; */
+/* s->read_upper_watermark = p->read_fragment_size * p->read_nfragments; */
/* } */
/* if (s->mode & SA_MODE_WRONLY) { */
-/* s->write_lower_watermark = oss->write_fragment_size; */
-/* s->write_upper_watermark = oss->write_fragment_size * oss->write_nfragments; */
+/* s->write_lower_watermark = p->write_fragment_size; */
+/* s->write_upper_watermark = p->write_fragment_size * p->write_nfragments; */
/* } */
/* } */
if (s->mode & SA_MODE_RDONLY)
- printf("Chosen for read: %u fragments, %u fragsize\n", oss->read_nfragments, oss->read_fragment_size);
+ printf("Chosen for read: %u fragments, %lu fragsize\n", p->read_nfragments, (unsigned long) p->read_fragment_size);
if (s->mode & SA_MODE_WRONLY)
- printf("Chosen for write: %u fragments, %u fragsize\n", oss->write_nfragments, oss->write_fragment_size);
+ printf("Chosen for write: %u fragments, %lu fragsize\n", p->write_nfragments, (unsigned long) p->write_fragment_size);
- if (sa_bufferq_init(&oss->bufferq, s->ni_enabled ? s->pcm_attrs.nchannels : 1) < 0)
+ if (sa_bufferq_init(&p->bufferq, s->ni_enabled ? s->pcm_attrs.nchannels : 1) < 0)
goto fail;
- if ((oss->cdata = pa_new(void*, s->ni_enabled ? s->pcm_attrs.nchannels : 1) < 0)
+ if (!(p->cdata = sa_new(void*, s->ni_enabled ? s->pcm_attrs.nchannels : 1)))
goto fail;
return SA_SUCCESS;
@@ -573,33 +610,33 @@ fail:
return r;
}
-int driver_destroy(sa_stream_t *s) {
- oss_stream_t *oss = OSS_STREAM(s);
+int driver_destroy(sa_stream *s) {
+ struct private *p = PRIVATE(s);
- if (oss) {
+ if (p) {
- if (oss->thread)
- driver_stop_thread(s);
+ if (p->thread)
+ sa_thread_free(p->thread);
- if (oss->fd >= 0)
- close(oss->fd);
+ if (p->fd >= 0)
+ close(p->fd);
- sa_bufferq_done(&oss->bufferq);
+ sa_bufferq_done(&p->bufferq);
- sa_free(oss->real_pcm_attrs.channel_map);
- sa_converter_done(&oss->converter_read);
- sa_converter_done(&oss->converter_write);
+ sa_free(p->real_pcm_attrs.channel_map);
+ sa_converter_done(&p->converter_read);
+ sa_converter_done(&p->converter_write);
- sa_free(oss->cdata);
+ sa_free(p->cdata);
- sa_free(oss);
+ sa_free(p);
}
return SA_SUCCESS;
}
-static int feed(sa_stream_t *s) {
- oss_stream_t *oss = OSS_STREAM(s);
+static int feed(sa_stream *s) {
+ struct private *p = PRIVATE(s);
size_t w;
int ret;
@@ -613,8 +650,9 @@ static int feed(sa_stream_t *s) {
size_t nbytes;
uint8_t *d;
sa_bool_t drop;
+ void *cdata;
- sa_bufferq_get(&oss->bufferq, cdata, &nbytes);
+ sa_bufferq_get(&p->bufferq, cdata, &nbytes);
if (nbytes > 0) {
void **dst;
@@ -622,11 +660,11 @@ static int feed(sa_stream_t *s) {
if (s->ni_enabled) {
- if ((ret = sa_converter_go(&oss->converter_write, cdata, &dst, &stride,
+/* if ((ret = sa_converter_go(&p->converter_write, cdata, &dst, &stride, */
} else {
- if ((ret = sa_converter_go_interleaved(&oss->converter_write, cdata, &dst, &stride, 1, &nbytes)))
+ if ((ret = sa_converter_go_interleaved(&p->converter_write, cdata, &dst, &stride, 1, &nbytes)))
goto fail;
d = dst[0];
@@ -636,11 +674,12 @@ static int feed(sa_stream_t *s) {
s->state = SA_STATE_RUNNING;
} else {
- nbytes = w > oss->write_fragment_size ? oss->write_fragment_size : w;
+ nbytes = w > p->write_fragment_size ? p->write_fragment_size : w;
- if (!(d = sa_converter_get_zero_buffer(&oss->converter_write, nbytes))) {
+ if (!(d = sa_converter_get_zero_buffer(&p->converter_write, nbytes))) {
ret = SA_ERROR_OOM;
goto fail;
+ }
drop = s->xrun_mode == SA_XRUN_MODE_SPIN;
@@ -651,7 +690,7 @@ static int feed(sa_stream_t *s) {
while (nbytes > 0) {
ssize_t l;
- if ((l = write(oss->fd, d, nbytes)) < 0) {
+ if ((l = write(p->fd, d, nbytes)) < 0) {
ret = SA_ERROR_SYSTEM;
goto fail;
}
@@ -664,7 +703,7 @@ static int feed(sa_stream_t *s) {
w -= 1;
if (drop)
- sa_bufferq_drop(&oss->bufferq, l);
+ sa_bufferq_drop(&p->bufferq, l);
}
}
}
@@ -673,21 +712,21 @@ static int feed(sa_stream_t *s) {
fail:
- sa_free(i);
+/* sa_free(i); */
return ret;
}
enum {
POLLFD_OSS_FD,
- POLLFD_PIPE_FD,
+ POLLFD_SOCKET_FD,
POLLFD_MAX
};
static void thread_func(void *data) {
struct pollfd pollfds[POLLFD_MAX];
- sa_stream_t *s = data;
- oss_stream_t *oss = OSS_STREAM(s);
+ sa_stream *s = data;
+ struct private *p = PRIVATE(s);
sigset_t mask;
sa_assert_se(sigfillset(&mask) == 0);
@@ -701,10 +740,10 @@ static void thread_func(void *data) {
memset(pollfds, 0, sizeof(pollfds));
- pollfds[POLLFD_SOCKET_FD].fd = oss->socket_fds[0];
+ pollfds[POLLFD_SOCKET_FD].fd = p->socket_fds[0];
pollfds[POLLFD_SOCKET_FD].events = POLLIN;
- pollfds[POLLFD_OSS_FD].fd = oss->fd;
+ pollfds[POLLFD_OSS_FD].fd = p->fd;
pollfds[POLLFD_OSS_FD].events = ((s->mode & SA_MODE_RDONLY) ? POLLIN : 0) | ((s->mode & SA_MODE_WRONLY) ? POLLOUT : 0);
for (;;) {
@@ -753,127 +792,127 @@ static void thread_func(void *data) {
}
}
-int driver_start_thread(sa_stream_t *s, sa_event_callback_t callback) {
- oss_stream_t *oss = OSS_STREAM(s);
- sa_return_val_if_fail(!oss->thread, SA_ERROR_STATE);
+/* int driver_start_thread(sa_stream *s, sa_event_callback_t callback) { */
+/* struct private *p = PRIVATE(s); */
+/* sa_return_val_if_fail(!p->thread, SA_ERROR_STATE); */
- s->callback = callback;
+/* s->callback = callback; */
- if ((socketpair(AF_UNIX, SOCK_DGRAM, 0, oss->socket_fds)) < 0)
- return SA_ERROR_SYSTEM;
+/* if ((socketpair(AF_UNIX, SOCK_DGRAM, 0, p->socket_fds)) < 0) */
+/* return SA_ERROR_SYSTEM; */
- if (!(oss->thread = sa_thread_new(thread_func, s)))
- return SA_ERROR_OOM;
+/* if (!(p->thread = sa_thread_new(thread_func, s))) */
+/* return SA_ERROR_OOM; */
- return SA_SUCCESS;
-}
+/* return SA_SUCCESS; */
+/* } */
-int driver_stop_thread(sa_stream_t *s) {
- oss_stream_t *oss = OSS_STREAM(s);
- sa_return_val_if_fail(oss->thread, SA_ERROR_STATE);
- sa_return_val_if_fail(oss->thread != sa_thread_self(), SA_ERROR_STATE);
+/* int driver_stop_thread(sa_stream *s) { */
+/* struct private *p = PRIVATE(s); */
+/* sa_return_val_if_fail(p->thread, SA_ERROR_STATE); */
+/* sa_return_val_if_fail(p->thread != sa_thread_self(), SA_ERROR_STATE); */
- if (oss->socket_fds[0] >= 0)
- close(oss->socket_fds[0]);
+/* if (p->socket_fds[0] >= 0) */
+/* close(p->socket_fds[0]); */
- if (oss->socket_fds[1] >= 0)
- close(oss->socket_fds[1]);
+/* if (p->socket_fds[1] >= 0) */
+/* close(p->socket_fds[1]); */
- if (oss->thread)
- sa_thread_free(oss->thread);
+/* if (p->thread) */
+/* sa_thread_free(p->thread); */
- oss->thread = NULL;
- oss->socket_fds[0] = oss->socket_fds[1] = -1;
+/* p->thread = NULL; */
+/* p->socket_fds[0] = p->socket_fds[1] = -1; */
- return SA_SUCCESS;
-}
+/* return SA_SUCCESS; */
+/* } */
-int driver_change_read_volume(sa_stream_t *s, const int32_t vol[]) {
- oss_stream_t *oss = OSS_STREAM(s);
+int driver_change_read_volume(sa_stream *s, const int32_t vol[]) {
+ struct private *p = PRIVATE(s);
- sa_return_val_if_fail(!s->codec, SA_ERROR_NOT_SUPPORTED);
+ sa_return_val_if_fail(!s->codec, SA_ERROR_NOTSUPPORTED);
- sa_converter_set_volume(&oss->converter_read, vol);
+ sa_converter_set_volume(&p->converter_read, vol);
return SA_SUCCESS;
}
-int driver_change_write_volume(sa_stream_t *s, const int32_t vol[]) {
- oss_stream_t *oss = OSS_STREAM(s);
+int driver_change_write_volume(sa_stream *s, const int32_t vol[]) {
+ struct private *p = PRIVATE(s);
- sa_return_val_if_fail(!s->codec, SA_ERROR_NOT_SUPPORTED);
+ sa_return_val_if_fail(!s->codec, SA_ERROR_NOTSUPPORTED);
- sa_converter_set_volume(&oss->converter_write, vol);
+ sa_converter_set_volume(&p->converter_write, vol);
return SA_SUCCESS;
}
-int driver_change_rate(sa_stream_t *s, unsigned rate) {
- oss_stream_t *oss = OSS_STREAM(s);
+int driver_change_pcm_rate(sa_stream *s, unsigned rate) {
+ struct private *p = PRIVATE(s);
if (s->mode & SA_MODE_RDONLY)
- sa_converter_set_ratio(&oss->converter_read, oss->real_pcm_attrs.rate, s->pcm_attrs.rate);
+ sa_converter_set_ratio(&p->converter_read, p->real_pcm_attrs.rate, s->pcm_attrs.rate);
if (s->mode & SA_MODE_WRONLY)
- sa_converter_set_ratio(&oss->converter_write, s->pcm_attrs.rate, oss->real_pcm_attrs.rate);
+ sa_converter_set_ratio(&p->converter_write, s->pcm_attrs.rate, p->real_pcm_attrs.rate);
return SA_SUCCESS;
}
-int driver_get_state(sa_stream_t *s, sa_state_t *state) {
+int driver_get_state(sa_stream *s, sa_state_t *state) {
*state = s->state;
return SA_SUCCESS;
}
-int driver_get_position(sa_stream_t *s, sa_position_t position, int64_t *pos) {
- return SA_ERROR_NOT_SUPPORTED;
+int driver_get_position(sa_stream *s, sa_position_t position, int64_t *pos) {
+ return SA_ERROR_NOTSUPPORTED;
}
-int driver_read(sa_stream_t *s, void *data, size_t nbytes) {
- return SA_ERROR_NOT_SUPPORTED;
+int driver_read(sa_stream *s, void *data, size_t nbytes) {
+ return SA_ERROR_NOTSUPPORTED;
}
-int driver_pwrite(sa_stream_t *s, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence) {
- oss_stream_t *oss = OSS_STREAM(s);
+int driver_pwrite(sa_stream *s, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence) {
+ struct private *p = PRIVATE(s);
int ret, ret2;
- if ((ret = sa_bufferq_push(&oss->bufferq, 0, data, nbytes, offset, whence, SA_BUFFERQ_ITEM_STATIC)))
+ if ((ret = sa_bufferq_push(&p->bufferq, 0, data, nbytes, offset, whence, SA_BUFFERQ_ITEM_STATIC)))
return ret;
ret = feed(s);
- ret2 = sa_bufferq_realloc(&oss->bufferq);
+ ret2 = sa_bufferq_realloc(&p->bufferq);
return ret ? ret : ret2;
}
-int driver_read_ni(sa_stream_t *s, unsigned channel, void *data, size_t nbytes) {
- return SA_ERROR_NOT_SUPPORTED;
+int driver_read_ni(sa_stream *s, unsigned channel, void *data, size_t nbytes) {
+ return SA_ERROR_NOTSUPPORTED;
}
-int driver_pwrite_ni(sa_stream_t *s, unsigned channel, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence) {
- return SA_ERROR_NOT_SUPPORTED;
+int driver_pwrite_ni(sa_stream *s, unsigned channel, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence) {
+ return SA_ERROR_NOTSUPPORTED;
}
-int driver_get_read_size(sa_stream_t *s, size_t *size) {
- return SA_ERROR_NOT_SUPPORTED;
+int driver_get_read_size(sa_stream *s, size_t *size) {
+ return SA_ERROR_NOTSUPPORTED;
}
-int driver_get_write_size(sa_stream_t *s, size_t *size) {
- return SA_ERROR_NOT_SUPPORTED;
+int driver_get_write_size(sa_stream *s, size_t *size) {
+ return SA_ERROR_NOTSUPPORTED;
}
-int driver_resume(sa_stream_t *s) {
- return SA_ERROR_NOT_SUPPORTED;
+int driver_resume(sa_stream *s) {
+ return SA_ERROR_NOTSUPPORTED;
}
-int driver_pause(sa_stream_t *s) {
- return SA_ERROR_NOT_SUPPORTED;
+int driver_pause(sa_stream *s) {
+ return SA_ERROR_NOTSUPPORTED;
}
-int driver_drain(sa_stream_t *s) {
- oss_stream_t *oss = OSS_STREAM(s);
- sa_return_val_if_fail(!oss->thread, SA_ERROR_STATE);
+int driver_drain(sa_stream *s) {
+ struct private *p = PRIVATE(s);
+ sa_return_val_if_fail(!p->thread, SA_ERROR_STATE);
- if (ioctl(oss->fd, SNDCTL_DSP_SYNC, NULL) < 0)
+ if (ioctl(p->fd, SNDCTL_DSP_SYNC, NULL) < 0)
return SA_ERROR_SYSTEM;
return SA_SUCCESS;
@@ -881,10 +920,6 @@ int driver_drain(sa_stream_t *s) {
/* Unsupported operations */
-int driver_change_device(sa_stream_t *s, const char *device) {
- return SA_ERROR_NOT_SUPPORTED;
-}
-
-int driver_change_meta_data(sa_stream_t *s, const char *name, const void *data, size_t size) {
- return SA_ERROR_NOT_SUPPORTED;
+int driver_change_device(sa_stream *s, const char *device) {
+ return SA_ERROR_NOTSUPPORTED;
}
diff --git a/src/proplist.c b/src/proplist.c
new file mode 100644
index 0000000..ceab702
--- /dev/null
+++ b/src/proplist.c
@@ -0,0 +1,413 @@
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdarg.h>
+
+#include "sydney.h"
+#include "proplist.h"
+#include "macro.h"
+#include "malloc.h"
+
+static unsigned calc_hash(const char *c) {
+ unsigned hash = 0;
+
+ for (; *c; c++)
+ hash = 31 * hash + (unsigned) *c;
+
+ return hash;
+}
+
+/**
+ * sa_proplist_create:
+ * @p: A pointer where to fill in a pointer for the new property list.
+ *
+ * Allocate a new empty property list.
+ *
+ * Returns: 0 on success, negative error code on error.
+ */
+int sa_proplist_create(sa_proplist **_p) {
+ sa_proplist *p;
+ sa_return_val_if_fail(_p, SA_ERROR_INVALID);
+
+ if (!(p = sa_new0(sa_proplist, 1)))
+ return SA_ERROR_OOM;
+
+ if (!(p->mutex = sa_mutex_new(FALSE, FALSE))) {
+ sa_free(p);
+ return SA_ERROR_OOM;
+ }
+
+ *_p = p;
+
+ return SA_SUCCESS;
+}
+
+static int _unset(sa_proplist *p, const char *key) {
+ sa_prop *prop, *nprop;
+ unsigned i;
+
+ sa_return_val_if_fail(p, SA_ERROR_INVALID);
+ sa_return_val_if_fail(key, SA_ERROR_INVALID);
+
+ i = calc_hash(key) % N_HASHTABLE;
+
+ nprop = NULL;
+ for (prop = p->prop_hashtable[i]; prop; nprop = prop, prop = prop->next_in_slot)
+ if (strcmp(prop->key, key) == 0)
+ break;
+
+ if (prop) {
+ if (nprop)
+ nprop->next_in_slot = prop->next_in_slot;
+ else
+ p->prop_hashtable[i] = prop->next_in_slot;
+
+ if (prop->prev_item)
+ prop->prev_item->next_item = prop->next_item;
+ else
+ p->first_item = prop->next_item;
+
+ if (prop->next_item)
+ prop->next_item->prev_item = prop->prev_item;
+
+ sa_free(prop->key);
+ sa_free(prop);
+ }
+
+ return SA_SUCCESS;
+}
+
+/**
+ * sa_proplist_sets:
+ * @p: The property list to add this key/value pair to
+ * @key: The key for this key/value pair
+ * @value: The value for this key/value pair
+ *
+ * Add a new string key/value pair to the property list.
+ *
+ * Returns: 0 on success, negative error code on error.
+ */
+
+int sa_proplist_sets(sa_proplist *p, const char *key, const char *value) {
+ sa_return_val_if_fail(p, SA_ERROR_INVALID);
+ sa_return_val_if_fail(key, SA_ERROR_INVALID);
+ sa_return_val_if_fail(value, SA_ERROR_INVALID);
+
+ return sa_proplist_set(p, key, value, strlen(value)+1);
+}
+
+/**
+ * sa_proplist_setf:
+ * @p: The property list to add this key/value pair to
+ * @key: The key for this key/value pair
+ * @format: The format string for the value for this key/value pair
+ * @...: The parameters for the format string
+ *
+ * Much like sa_proplist_sets(): add a new string key/value pair to
+ * the property list. Takes a standard C format string plus arguments
+ * and formats a string of it.
+ *
+ * Returns: 0 on success, negative error code on error.
+ */
+
+int sa_proplist_setf(sa_proplist *p, const char *key, const char *format, ...) {
+ int ret;
+ char *k;
+ sa_prop *prop;
+ size_t size = 100;
+ unsigned h;
+
+ sa_return_val_if_fail(p, SA_ERROR_INVALID);
+ sa_return_val_if_fail(key, SA_ERROR_INVALID);
+ sa_return_val_if_fail(format, SA_ERROR_INVALID);
+
+ if (!(k = sa_strdup(key)))
+ return SA_ERROR_OOM;
+
+ for (;;) {
+ va_list ap;
+ int r;
+
+ if (!(prop = sa_malloc(SA_ALIGN(sizeof(sa_prop)) + size))) {
+ sa_free(k);
+ return SA_ERROR_OOM;
+ }
+
+ va_start(ap, format);
+ r = vsnprintf(SA_PROP_DATA(prop), size, format, ap);
+ va_end(ap);
+
+ ((char*) SA_PROP_DATA(prop))[size-1] = 0;
+
+ if (r > -1 && (size_t) r < size) {
+ prop->nbytes = (size_t) r+1;
+ break;
+ }
+
+ if (r > -1) /* glibc 2.1 */
+ size = (size_t) r+1;
+ else /* glibc 2.0 */
+ size *= 2;
+
+ sa_free(prop);
+ }
+
+ prop->key = k;
+
+ sa_mutex_lock(p->mutex);
+
+ if ((ret = _unset(p, key)) < 0) {
+ sa_free(prop);
+ sa_free(k);
+ goto finish;
+ }
+
+ h = calc_hash(key) % N_HASHTABLE;
+
+ prop->next_in_slot = p->prop_hashtable[h];
+ p->prop_hashtable[h] = prop;
+
+ prop->prev_item = NULL;
+ prop->next_item = p->first_item;
+ p->first_item = prop;
+
+finish:
+
+ sa_mutex_unlock(p->mutex);
+
+ return ret;
+}
+
+/**
+ * sa_proplist_set:
+ * @p: The property list to add this key/value pair to
+ * @key: The key for this key/value pair
+ * @data: The binary value for this key value pair
+ * @nbytes: The size of thebinary value for this key value pair.
+ *
+ * Add a new binary key/value pair to the property list.
+ *
+ * Returns: 0 on success, negative error code on error.
+ */
+
+int sa_proplist_set(sa_proplist *p, const char *key, const void *data, size_t nbytes) {
+ int ret;
+ char *k;
+ sa_prop *prop;
+ unsigned h;
+
+ sa_return_val_if_fail(p, SA_ERROR_INVALID);
+ sa_return_val_if_fail(key, SA_ERROR_INVALID);
+ sa_return_val_if_fail(!nbytes || data, SA_ERROR_INVALID);
+
+ if (!(k = sa_strdup(key)))
+ return SA_ERROR_OOM;
+
+ if (!(prop = sa_malloc(SA_ALIGN(sizeof(sa_prop)) + nbytes))) {
+ sa_free(k);
+ return SA_ERROR_OOM;
+ }
+
+ prop->key = k;
+ prop->nbytes = nbytes;
+ memcpy(SA_PROP_DATA(prop), data, nbytes);
+
+ sa_mutex_lock(p->mutex);
+
+ if ((ret = _unset(p, key)) < 0) {
+ sa_free(prop);
+ sa_free(k);
+ goto finish;
+ }
+
+ h = calc_hash(key) % N_HASHTABLE;
+
+ prop->next_in_slot = p->prop_hashtable[h];
+ p->prop_hashtable[h] = prop;
+
+ prop->prev_item = NULL;
+ prop->next_item = p->first_item;
+ p->first_item = prop;
+
+finish:
+
+ sa_mutex_unlock(p->mutex);
+
+ return ret;
+}
+
+/* Not exported, not self-locking */
+sa_prop* sa_proplist_get_unlocked(sa_proplist *p, const char *key) {
+ sa_prop *prop;
+ unsigned i;
+
+ sa_return_val_if_fail(p, NULL);
+ sa_return_val_if_fail(key, NULL);
+
+ i = calc_hash(key) % N_HASHTABLE;
+
+ for (prop = p->prop_hashtable[i]; prop; prop = prop->next_in_slot)
+ if (strcmp(prop->key, key) == 0)
+ return prop;
+
+ return NULL;
+}
+
+/* Not exported, not self-locking */
+const char* sa_proplist_gets_unlocked(sa_proplist *p, const char *key) {
+ sa_prop *prop;
+
+ sa_return_val_if_fail(p, NULL);
+ sa_return_val_if_fail(key, NULL);
+
+ if (!(prop = sa_proplist_get_unlocked(p, key)))
+ return NULL;
+
+ if (!memchr(SA_PROP_DATA(prop), 0, prop->nbytes))
+ return NULL;
+
+ return SA_PROP_DATA(prop);
+}
+
+/**
+ * sa_proplist_destroy:
+ * @p: The property list to destroy
+ *
+ * Destroys a property list that was created with sa_proplist_create() earlier.
+ *
+ * Returns: 0 on success, negative error code on error.
+ */
+
+int sa_proplist_destroy(sa_proplist *p) {
+ sa_prop *prop, *nprop;
+
+ sa_return_val_if_fail(p, SA_ERROR_INVALID);
+
+ for (prop = p->first_item; prop; prop = nprop) {
+ nprop = prop->next_item;
+ sa_free(prop->key);
+ sa_free(prop);
+ }
+
+ sa_mutex_free(p->mutex);
+
+ sa_free(p);
+
+ return SA_SUCCESS;
+}
+
+static int merge_into(sa_proplist *a, sa_proplist *b) {
+ int ret = SA_SUCCESS;
+ sa_prop *prop;
+
+ sa_return_val_if_fail(a, SA_ERROR_INVALID);
+ sa_return_val_if_fail(b, SA_ERROR_INVALID);
+
+ sa_mutex_lock(b->mutex);
+
+ for (prop = b->first_item; prop; prop = prop->next_item)
+ if ((ret = sa_proplist_set(a, prop->key, SA_PROP_DATA(prop), prop->nbytes)) < 0)
+ break;
+
+ sa_mutex_unlock(b->mutex);
+
+ return ret;
+}
+
+int sa_proplist_merge(sa_proplist **_a, sa_proplist *b, sa_proplist *c) {
+ sa_proplist *a;
+ int ret;
+
+ sa_return_val_if_fail(_a, SA_ERROR_INVALID);
+ sa_return_val_if_fail(b, SA_ERROR_INVALID);
+ sa_return_val_if_fail(c, SA_ERROR_INVALID);
+
+ if ((ret = sa_proplist_create(&a)) < 0)
+ return ret;
+
+ if ((ret = merge_into(a, b)) < 0 ||
+ (ret = merge_into(a, c)) < 0) {
+ sa_proplist_destroy(a);
+ return ret;
+ }
+
+ *_a = a;
+ return SA_SUCCESS;
+}
+
+sa_bool_t sa_proplist_contains(sa_proplist *p, const char *key) {
+ sa_bool_t b;
+
+ sa_return_val_if_fail(p, FALSE);
+ sa_return_val_if_fail(key, FALSE);
+
+ sa_mutex_lock(p->mutex);
+ b = !!sa_proplist_get_unlocked(p, key);
+ sa_mutex_unlock(p->mutex);
+
+ return b;
+}
+
+int sa_proplist_merge_ap(sa_proplist *p, va_list ap) {
+ int ret;
+
+ sa_return_val_if_fail(p, SA_ERROR_INVALID);
+
+ for (;;) {
+ const char *key, *value;
+
+ if (!(key = va_arg(ap, const char*)))
+ break;
+
+ if (!(value = va_arg(ap, const char*)))
+ return SA_ERROR_INVALID;
+
+ if ((ret = sa_proplist_sets(p, key, value)) < 0)
+ return ret;
+ }
+
+ return SA_SUCCESS;
+}
+
+int sa_proplist_from_ap(sa_proplist **_p, va_list ap) {
+ int ret;
+ sa_proplist *p;
+
+ sa_return_val_if_fail(_p, SA_ERROR_INVALID);
+
+ if ((ret = sa_proplist_create(&p)) < 0)
+ return ret;
+
+ if ((ret = sa_proplist_merge_ap(p, ap)) < 0)
+ goto fail;
+
+ *_p = p;
+
+ return SA_SUCCESS;
+
+fail:
+ sa_assert_se(sa_proplist_destroy(p) == SA_SUCCESS);
+
+ return ret;
+}
diff --git a/src/proplist.h b/src/proplist.h
new file mode 100644
index 0000000..f694de2
--- /dev/null
+++ b/src/proplist.h
@@ -0,0 +1,56 @@
+#ifndef foosydneyproplisthfoo
+#define foosydneyproplisthfoo
+
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdarg.h>
+
+#include "sydney.h"
+#include "mutex.h"
+
+#define N_HASHTABLE 31
+
+typedef struct sa_prop {
+ char *key;
+ size_t nbytes;
+ struct sa_prop *next_in_slot, *next_item, *prev_item;
+} sa_prop;
+
+#define SA_PROP_DATA(p) ((void*) ((char*) (p) + SA_ALIGN(sizeof(sa_prop))))
+
+struct sa_proplist {
+ sa_mutex *mutex;
+
+ sa_prop *prop_hashtable[N_HASHTABLE];
+ sa_prop *first_item;
+};
+
+int sa_proplist_merge(sa_proplist **_a, sa_proplist *b, sa_proplist *c);
+sa_bool_t sa_proplist_contains(sa_proplist *p, const char *key);
+
+/* Both of the following two functions are not locked! Need manual locking! */
+sa_prop* sa_proplist_get_unlocked(sa_proplist *p, const char *key);
+const char* sa_proplist_gets_unlocked(sa_proplist *p, const char *key);
+
+int sa_proplist_merge_ap(sa_proplist *p, va_list ap);
+int sa_proplist_from_ap(sa_proplist **_p, va_list ap);
+
+#endif
diff --git a/src/pulse.c b/src/pulse.c
new file mode 120000
index 0000000..cc3e685
--- /dev/null
+++ b/src/pulse.c
@@ -0,0 +1 @@
+null.c \ No newline at end of file
diff --git a/src/resample.c b/src/resample.c
index 7babe05..991c195 100644
--- a/src/resample.c
+++ b/src/resample.c
@@ -1,3 +1,23 @@
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@@ -7,10 +27,10 @@
static void resample_s16(SpeexResamplerState *speex, unsigned channel, void *dst, size_t dstr, const void *src, size_t sstr, size_t in_bytes, size_t *out_bytes) {
- spx_uint32_t in_samples = in_bytes/sizeof(int16_t), out_samples = *out_bytes/sizeof(int16_t);
+ spx_uint32_t in_samples = (uint32_t) (in_bytes/sizeof(int16_t)), out_samples = (uint32_t) (*out_bytes/sizeof(int16_t));
- speex_resampler_set_input_stride(speex, sstr/sizeof(int16_t));
- speex_resampler_set_input_stride(speex, dstr/sizeof(int16_t));
+ speex_resampler_set_input_stride(speex, (uint32_t) (sstr/sizeof(int16_t)));
+ speex_resampler_set_input_stride(speex, (uint32_t) (dstr/sizeof(int16_t)));
speex_resampler_process_int(speex, channel, src, &in_samples, dst, &out_samples);
@@ -21,10 +41,10 @@ static void resample_s16(SpeexResamplerState *speex, unsigned channel, void *dst
static void resample_f32(SpeexResamplerState *speex, unsigned channel, void *dst, size_t dstr, const void *src, size_t sstr, size_t in_bytes, size_t *out_bytes) {
- spx_uint32_t in_samples = in_bytes/sizeof(float), out_samples = *out_bytes/sizeof(float);
+ spx_uint32_t in_samples = (uint32_t) (in_bytes/sizeof(float)), out_samples = (uint32_t) (*out_bytes/sizeof(float));
- speex_resampler_set_input_stride(speex, sstr/sizeof(float));
- speex_resampler_set_input_stride(speex, dstr/sizeof(float));
+ speex_resampler_set_input_stride(speex, (uint32_t) (sstr/sizeof(float)));
+ speex_resampler_set_input_stride(speex, (uint32_t) (dstr/sizeof(float)));
speex_resampler_process_float(speex, channel, src, &in_samples, dst, &out_samples);
diff --git a/src/resample.h b/src/resample.h
index 7734f86..64557d8 100644
--- a/src/resample.h
+++ b/src/resample.h
@@ -1,11 +1,32 @@
#ifndef foosydneyresamplehfoo
#define foosydneyresamplehfoo
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
#include <sys/types.h>
#include <inttypes.h>
+#include <speex/speex_resampler.h>
+
#include "sydney.h"
-#include "speex/speex_resampler.h"
typedef void (*sa_resample_func_t) (SpeexResamplerState *speex, unsigned channel, void *dst, size_t dstr, const void *src, size_t sstr, size_t in_bytes, size_t *out_bytes);
diff --git a/src/sydney.h b/src/sydney.h
index 58324ca..cdc006c 100644
--- a/src/sydney.h
+++ b/src/sydney.h
@@ -1,33 +1,39 @@
#ifndef foosydneyhfoo
#define foosydneyhfoo
-#ifdef __cplusplus
-extern "C" {
-#endif
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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.
-/*
- Requirements & General observations
-
- - In sync mode, the device will automatically write data so that an
- initial read causes writes of zeros to be issued to that one can
- do "while (1); {read(); write()}
- - All functions are thread-safe and can be called in any thread
- context. None of the functions is async-signal safe.
- - It is assumed that duplex streams have a single clock (synchronised)
- - Property set extensible. To be kept in sync with PulseAudio and libsydney.
- - Property keys need to be valid UTF-8, text values, too.
- - Will warn if application.name or application.id not set.
- - Error codes are returned immediately, as negative integers
- - application.process.* will be filled in automatically but may be overwritten by the client.
- They thus should not be used for authentication purposes.
- - It is recommended to set most properties before the _open() call.
-
-*/
+ You should have received a copy of the GNU Lesser General Public
+ License along with libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
#include <sys/types.h>
#include <sys/param.h>
#include <inttypes.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef __GNUC__
+/* Make sure __attribute__ works on non-gcc systems. Yes, might be a bit ugly */
+#define __attribute__(x)
+#endif
+
/* Detect byte order, based on sys/param.h */
#if (defined(__BYTE_ORDER) && (__BYTE_ORDER == __LITTLE_ENDIAN)) || defined(WIN32)
#define SA_LITTLE_ENDIAN 1
@@ -39,8 +45,269 @@ extern "C" {
#error "Cannot determine byte order!"
#endif
+/**
+ * SA_PROP_MEDIA_NAME:
+ *
+ * A name describing the media being played. Localized if possible and applicable.
+ */
+#define SA_PROP_MEDIA_NAME "media.name"
+
+/**
+ * SA_PROP_MEDIA_TITLE:
+ *
+ * A (song) title describing the media being played. Localized if possible and applicable.
+ */
+#define SA_PROP_MEDIA_TITLE "media.title"
+
+/**
+ * SA_PROP_MEDIA_ARTIST:
+ *
+ * The artist of this media. Localized if possible and applicable.
+ */
+#define SA_PROP_MEDIA_ARTIST "media.artist"
+
+/**
+ * SA_PROP_MEDIA_LANGUAGE:
+ *
+ * The language this media is in, in some standard POSIX locale string, such as "de_DE".
+ */
+#define SA_PROP_MEDIA_LANGUAGE "media.language"
+
+/**
+ * SA_PROP_MEDIA_FILENAME:
+ *
+ * The file name this media was or can be loaded from.
+ */
+#define SA_PROP_MEDIA_FILENAME "media.filename"
+
+/**
+ * SA_PROP_MEDIA_ICON:
+ *
+ * An icon for this media in binary PNG format.
+ */
+#define SA_PROP_MEDIA_ICON "media.icon"
+
+/**
+ * SA_PROP_MEDIA_ICON_NAME:
+ *
+ * An icon name as defined in the XDG icon naming specifcation.
+ */
+#define SA_PROP_MEDIA_ICON_NAME "media.icon_name"
+
+/**
+ * SA_PROP_MEDIA_ROLE:
+ *
+ * The "role" this media is played in. For event sounds the string
+ * "event". For other cases strings like "music", "video", "game", ...
+ */
+#define SA_PROP_MEDIA_ROLE "media.role"
+
+/**
+ * SA_PROP_EVENT_ID:
+ *
+ * A textual id for an event sound, as mandated by the XDG sound naming specification.
+ */
+#define SA_PROP_EVENT_ID "event.id"
+
+/**
+ * SA_PROP_EVENT_DESCRIPTION:
+ *
+ * A descriptive string for the sound event. Localized if possible and applicable.
+ */
+#define SA_PROP_EVENT_DESCRIPTION "event.description"
+
+/**
+ * SA_PROP_EVENT_MOUSE_X:
+ *
+ * If this sound event was triggered by a mouse input event, the X
+ * position of the mouse cursor on the screen, formatted as string.
+ */
+#define SA_PROP_EVENT_MOUSE_X "event.mouse.x"
+
+/**
+ * SA_PROP_EVENT_MOUSE_Y:
+ *
+ * If this sound event was triggered by a mouse input event, the Y
+ * position of the mouse cursor on the screen, formatted as string.
+ */
+#define SA_PROP_EVENT_MOUSE_Y "event.mouse.y"
+
+/**
+ * SA_PROP_EVENT_MOUSE_HPOS:
+ *
+ * If this sound event was triggered by a mouse input event, the X
+ * position of the mouse cursor as fractional value between 0 and 1,
+ * formatted as string, 0 reflecting the left side of the screen, 1
+ * the right side.
+ */
+#define SA_PROP_EVENT_MOUSE_HPOS "event.mouse.hpos"
+
+/**
+ * SA_PROP_EVENT_MOUSE_VPOS:
+ *
+ * If this sound event was triggered by a mouse input event, the Y
+ * position of the mouse cursor as fractional value between 0 and 1,
+ * formatted as string, 0 reflecting the top end of the screen, 1
+ * the bottom end.
+ */
+#define SA_PROP_EVENT_MOUSE_VPOS "event.mouse.vpos"
+
+/**
+ * SA_PROP_EVENT_MOUSE_BUTTON:
+ *
+ * If this sound event was triggered by a mouse input event, the
+ * number of the mouse button that triggered it, formatted as string. 1
+ * for left mouse button, 3 for right, 2 for middle.
+ */
+#define SA_PROP_EVENT_MOUSE_BUTTON "event.mouse.button"
+
+/**
+ * SA_PROP_WINDOW_NAME:
+ *
+ * If this sound event was triggered by a window on the screen, the
+ * name of this window as human readable string.
+ */
+#define SA_PROP_WINDOW_NAME "window.name"
+
+/**
+ * SA_PROP_WINDOW_ID:
+ *
+ * If this sound event was triggered by a window on the screen, some
+ * identification string for this window, so that the sound system can
+ * recognize specific windows.
+ */
+#define SA_PROP_WINDOW_ID "window.id"
+
+/**
+ * SA_PROP_WINDOW_ICON:
+ *
+ * If this sound event was triggered by a window on the screen, binary
+ * icon data in PNG format for this window.
+ */
+#define SA_PROP_WINDOW_ICON "window.icon"
+
+/**
+ * SA_PROP_WINDOW_ICON_NAME:
+ *
+ * If this sound event was triggered by a window on the screen, an
+ * icon name for this window, as defined in the XDG icon naming
+ * specification.
+ */
+#define SA_PROP_WINDOW_ICON_NAME "window.icon_name"
+
+/**
+ * SA_PROP_WINDOW_X11_DISPLAY:
+ *
+ * If this sound event was triggered by a window on the screen and the
+ * windowing system is X11, the X display name of the window (e.g. ":0").
+ */
+#define SA_PROP_WINDOW_X11_DISPLAY "window.x11.display"
+
+/**
+ * SA_PROP_WINDOW_X11_SCREEN:
+ *
+ * If this sound event was triggered by a window on the screen and the
+ * windowing system is X11, the X screen id of the window formatted as
+ * string (e.g. "0").
+ */
+#define SA_PROP_WINDOW_X11_SCREEN "window.x11.screen"
+
+/**
+ * SA_PROP_WINDOW_X11_MONITOR:
+ *
+ * If this sound event was triggered by a window on the screen and the
+ * windowing system is X11, the X monitor id of the window formatted as
+ * string (e.g. "0").
+ */
+#define SA_PROP_WINDOW_X11_MONITOR "window.x11.monitor"
+
+/**
+ * SA_PROP_WINDOW_X11_XID:
+ *
+ * If this sound event was triggered by a window on the screen and the
+ * windowing system is X11, the XID of the window formatted as string.
+ */
+#define SA_PROP_WINDOW_X11_XID "window.x11.xid"
+
+/**
+ * SA_PROP_APPLICATION_NAME:
+ *
+ * The name of the application this sound event was triggered by as
+ * human readable string. (e.g. "GNU Emacs") Localized if possible and
+ * applicable.
+ */
+#define SA_PROP_APPLICATION_NAME "application.name"
+
+/**
+ * SA_PROP_APPLICATION_ID:
+ *
+ * An identifier for the program this sound event was triggered
+ * by. (e.g. "org.gnu.emacs").
+ */
+#define SA_PROP_APPLICATION_ID "application.id"
+
+/**
+ * SA_PROP_APPLICATION_VERSION:
+ *
+ * A version number for the program this sound event was triggered
+ * by. (e.g. "22.2")
+ */
+#define SA_PROP_APPLICATION_VERSION "application.version"
+
+/**
+ * SA_PROP_APPLICATION_ICON:
+ *
+ * Binary icon data in PNG format for the application this sound event
+ * is triggered by.
+ */
+#define SA_PROP_APPLICATION_ICON "application.icon"
+
+/**
+ * SA_PROP_APPLICATION_ICON_NAME:
+ *
+ * An icon name for the application this sound event is triggered by,
+ * as defined in the XDG icon naming specification.
+ */
+#define SA_PROP_APPLICATION_ICON_NAME "application.icon_name"
+
+/**
+ * SA_PROP_APPLICATION_LANGUAGE:
+ *
+ * The locale string the application that is triggering this sound
+ * event is running in. A POSIX locale string such as de_DE@euro.
+ */
+#define SA_PROP_APPLICATION_LANGUAGE "application.language"
+
+/**
+ * SA_PROP_APPLICATION_PROCESS_ID:
+ *
+ * The unix PID of the process that is triggering this sound event, formatted as string.
+ */
+#define SA_PROP_APPLICATION_PROCESS_ID "application.process.id"
+
+/**
+ * SA_PROP_APPLICATION_PROCESS_BINARY:
+ *
+ * The path to the process binary of the process that is triggering this sound event.
+ */
+#define SA_PROP_APPLICATION_PROCESS_BINARY "application.process.binary"
+
+/**
+ * SA_PROP_APPLICATION_PROCESS_USER:
+ *
+ * The user that owns the process that is triggering this sound event.
+ */
+#define SA_PROP_APPLICATION_PROCESS_USER "application.process.user"
+
+/**
+ * SA_PROP_APPLICATION_PROCESS_HOST:
+ *
+ * The host name of the host the process that is triggering this sound event runs on.
+ */
+#define SA_PROP_APPLICATION_PROCESS_HOST "application.process.host"
+
/** Stream object */
-typedef struct sa_stream sa_stream_t;
+typedef struct sa_stream sa_stream;
/** Volume that corresponds to muted in/out */
#define SA_VOLUME_MUTED ((int32_t) (-0x80000000))
@@ -104,23 +371,34 @@ typedef enum {
_SA_MODE_MAX = 4
} sa_mode_t;
-/** Error codes */
+/**
+ * Error codes:
+ * SCA_SUCCESS: Success
+ *
+ * Error codes
+ */
enum {
SA_SUCCESS = 0,
- SA_ERROR_NOT_SUPPORTED = -1,
+ SA_ERROR_NOTSUPPORTED = -1,
SA_ERROR_INVALID = -2,
SA_ERROR_STATE = -3,
SA_ERROR_OOM = -4,
- SA_ERROR_NO_DEVICE = -5,
- SA_ERROR_NO_DRIVER = -6,
- SA_ERROR_NO_CODEC = -7,
- SA_ERROR_NO_PCM_FORMAT = -7,
- SA_ERROR_SYSTEM = -8,
- SA_ERROR_NO_INIT = -9,
- SA_ERROR_NO_META = -10,
- SA_ERROR_NO_DATA = -11,
- SA_ERROR_NO_SPACE = -12,
- _SA_ERROR_MAX = -13
+ SA_ERROR_NODRIVER = -5,
+ SA_ERROR_SYSTEM = -6,
+ SA_ERROR_CORRUPT = -7,
+ SA_ERROR_TOOBIG = -8,
+ SA_ERROR_NOTFOUND = -9,
+ SA_ERROR_DESTROYED = -10,
+ SA_ERROR_CANCELED = -11,
+ SA_ERROR_NOTAVAILABLE = -12,
+ SA_ERROR_ACCESS = -13,
+ SA_ERROR_IO = -14,
+ SA_ERROR_INTERNAL = -15,
+ SA_ERROR_DISABLED = -16,
+ SA_ERROR_NODEVICE = -17,
+ SA_ERROR_NOCODEC = -18,
+ SA_ERROR_NOPCMFORMAT = -19,
+ _SA_ERROR_MAX = -20
};
/** Possible events for notifications */
@@ -219,6 +497,7 @@ typedef enum {
SA_STATE_RUNNING,
SA_STATE_STOPPED,
SA_STATE_DRAINING,
+ SA_STATE_DEAD,
/* put more stuff */
_SA_STATE_MAX
} sa_state_t;
@@ -236,185 +515,171 @@ typedef enum {
SA_ADJUST_NONE = 0
} sa_adjust_t;
-/** Stream properties */
-#define SA_PROP_MEDIA_NAME "media.name"
-#define SA_PROP_MEDIA_TITLE "media.title"
-#define SA_PROP_MEDIA_ARTIST "media.artist"
-#define SA_PROP_MEDIA_LANGUAGE "media.language"
-#define SA_PROP_MEDIA_FILENAME "media.filename"
-#define SA_PROP_MEDIA_ICON "media.icon"
-#define SA_PROP_MEDIA_ICON_NAME "media.icon_name"
-#define SA_PROP_MEDIA_ROLE "media.role"
-#define SA_PROP_EVENT_ID "event.id"
-#define SA_PROP_EVENT_X11_DISPLAY "event.x11.display"
-#define SA_PROP_EVENT_X11_XID "event.x11.xid"
-#define SA_PROP_EVENT_MOUSE_X "event.mouse.x"
-#define SA_PROP_EVENT_MOUSE_Y "event.mouse.y"
-#define SA_PROP_EVENT_MOUSE_BUTTON "event.mouse.button"
-#define SA_PROP_APPLICATION_NAME "application.name"
-#define SA_PROP_APPLICATION_ID "application.id"
-#define SA_PROP_APPLICATION_VERSION "application.version"
-#define SA_PROP_APPLICATION_ICON "application.icon"
-#define SA_PROP_APPLICATION_ICON_NAME "application.icon_name"
-#define SA_PROP_APPLICATION_LANGUAGE "application.language"
-#define SA_PROP_APPLICATION_PROCESS_ID "application.process.id"
-#define SA_PROP_APPLICATION_PROCESS_BINARY "application.process.binary"
-#define SA_PROP_APPLICATION_PROCESS_USER "application.process.user"
-#define SA_PROP_APPLICATION_PROCESS_HOST "application.process.host"
-
/** Main callback function */
-typedef int (*sa_event_callback_t)(sa_stream_t *s, sa_event_t event);
+typedef int (*sa_event_callback_t)(sa_stream *s, sa_event_t event);
+
+/**
+ * sa_proplist:
+ *
+ * A sydney property list object. Basically a hashtable.
+ */
+typedef struct sa_proplist sa_proplist;
+
+int sa_proplist_create(sa_proplist **p);
+int sa_proplist_destroy(sa_proplist *p);
+int sa_proplist_sets(sa_proplist *p, const char *key, const char *value);
+int sa_proplist_setf(sa_proplist *p, const char *key, const char *format, ...) __attribute__((format(printf, 3, 4)));
+int sa_proplist_set(sa_proplist *p, const char *key, const void *data, size_t nbytes);
/** Create an opaque (e.g. AC3) codec stream */
-int sa_stream_create_opaque(sa_stream_t **s, const char *client_name, sa_mode_t mode, const char *codec);
+int sa_stream_create_opaque(sa_stream **s, sa_mode_t mode, const char *codec);
/** Normal way to open a PCM device */
-int sa_stream_create_pcm(sa_stream_t **s, const char *client_name, sa_mode_t mode, sa_pcm_format_t format, unsigned rate, unsigned nchannels);
+int sa_stream_create_pcm(sa_stream **s, sa_mode_t mode, sa_pcm_format_t format, unsigned rate, unsigned nchannels);
/** Initialise the device */
-int sa_stream_open(sa_stream_t *s);
+int sa_stream_open(sa_stream *s);
/** Close/destroy everything */
-int sa_stream_destroy(sa_stream_t *s);
+int sa_stream_destroy(sa_stream *s);
/* Buffer params */
-int sa_stream_set_write_latency(sa_stream_t *s, size_t nbytes);
-int sa_stream_set_write_wakeup(sa_stream_t *s, size_t nbytes);
-int sa_stream_set_read_latency(sa_stream_t *s, size_t nbytes);
-int sa_stream_set_read_wakeup(sa_stream_t *s, size_t nbytes);
+int sa_stream_change_write_latency(sa_stream *s, size_t latency_nbytes, size_t process_time_nbytes);
+int sa_stream_change_read_latency(sa_stream *s, size_t latency_nbytes, size_t process_time_nbytes);
/** Set the mapping between channels and the loudspeakers */
-int sa_stream_set_channel_map(sa_stream_t *s, const sa_channel_t map[], unsigned n);
+int sa_stream_set_channel_map(sa_stream *s, const sa_channel_t map[], unsigned n);
/** Whether xruns cause the card to reset */
-int sa_stream_set_xrun_mode(sa_stream_t *s, sa_xrun_mode_t mode);
+int sa_stream_set_xrun_mode(sa_stream *s, sa_xrun_mode_t mode);
/** Set the device to non-interleaved mode */
-int sa_stream_set_non_interleaved(sa_stream_t *s, int enable);
+int sa_stream_set_non_interleaved(sa_stream *s, int enable);
/** Allow that the sample rate may be changed during runtime */
-int sa_stream_set_dynamic_rate(sa_stream_t *s, int enabled);
-
-/** Set the number of PCM channels for input */
-int sa_stream_set_read_pcm_nchannels(sa_stream *s, unsigned nchannels);
-
-/** Set the number of PCM channels for output */
-int sa_stream_set_write_pcm_nchannels(sa_stream *s, unsigned nchannels);
+int sa_stream_set_dynamic_pcm_rate(sa_stream *s, int enabled);
/** Select driver */
-int sa_stream_set_driver(sa_stream_t *s, const char *driver);
-
-/** Start callback thread */
-int sa_stream_start_thread(sa_stream_t *s, sa_event_callback_t callback);
+int sa_stream_set_driver(sa_stream *s, const char *driver);
-/** Start callback thread */
-int sa_stream_stop_thread(sa_stream_t *s);
+/** Enable asynchronous mode and set event callback*/
+int sa_stream_set_event_callback(sa_stream *s, sa_event_callback_t callback);
/** Change the device connected to the stream */
-int sa_stream_change_device(sa_stream_t *s, const char *device_name);
+int sa_stream_change_device(sa_stream *s, const char *device_name);
/** volume in hundreths of dB*/
-int sa_stream_change_read_volume(sa_stream_t *s, const int32_t vol[], unsigned n);
+int sa_stream_change_read_volume(sa_stream *s, const int32_t vol[], unsigned n);
/** volume in hundreths of dB*/
-int sa_stream_change_write_volume(sa_stream_t *s, const int32_t vol[], unsigned n);
+int sa_stream_change_write_volume(sa_stream *s, const int32_t vol[], unsigned n);
/** Change the sampling rate */
-int sa_stream_change_rate(sa_stream_t *s, unsigned rate);
+int sa_stream_change_pcm_rate(sa_stream *s, unsigned rate);
+
+int sa_stream_change_props(sa_stream *c, ...) __attribute__((sentinel));
+int sa_stream_change_props_full(sa_stream *c, sa_proplist *p);
/** Associate opaque user data */
-int sa_stream_change_user_data(sa_stream_t *s, const void *value);
+int sa_stream_change_user_data(sa_stream *s, const void *value);
/* Hardware-related. This is implementation-specific and hardware specific. */
-int sa_stream_set_adjust_rate(sa_stream_t *s, sa_adjust_t direction);
-int sa_stream_set_adjust_nchannels(sa_stream_t *s, sa_adjust_t direction);
-int sa_stream_set_adjust_pcm_format(sa_stream_t *s, sa_adjust_t direction);
+int sa_stream_set_adjust_rate(sa_stream *s, sa_adjust_t direction);
+int sa_stream_set_adjust_nchannels(sa_stream *s, sa_adjust_t direction);
+int sa_stream_set_adjust_pcm_format(sa_stream *s, sa_adjust_t direction);
/* Query functions */
-int sa_stream_get_mode(sa_stream_t *s, sa_mode_t *access_mode);
-int sa_stream_get_codec(sa_stream_t *s, char *codec, size_t *size);
-int sa_stream_get_pcm_format(sa_stream_t *s, sa_pcm_format_t *format);
-int sa_stream_get_pcm_rate(sa_stream_t *s, unsigned *rate);
-int sa_stream_get_pcm_nchannels(sa_stream_t *s, int *nchannels);
-int sa_stream_get_user_data(sa_stream_t *s, void **value);
-int sa_stream_get_write_latency(sa_stream_t *s, size_t *nbytes);
-int sa_stream_get_write_wakeup(sa_stream_t *s, size_t *nbytes);
-int sa_stream_get_read_latency(sa_stream_t *s, size_t *nbytes);
-int sa_stream_get_read_wakeup(sa_stream_t *s, size_t *nbytes);
-int sa_stream_get_pcm_channel_map(sa_stream_t *s, sa_channel_t map[], unsigned *n);
-int sa_stream_get_xrun_mode(sa_stream_t *s, sa_xrun_mode_t *mode);
-int sa_stream_get_non_interleaved(sa_stream_t *s, int *enabled);
-int sa_stream_get_pcm_dynamic_rate(sa_stream_t *s, int *enabled);
-int sa_stream_get_driver(sa_stream_t *s, char *driver_name, size_t *size);
-int sa_stream_get_device(sa_stream_t *s, char *device_name, size_t *size);
-int sa_stream_get_read_volume(sa_stream_t *s, int32_t vol[], unsigned *n);
-int sa_stream_get_write_volume(sa_stream_t *s, int32_t vol[], unsigned *n);
-int sa_stream_get_meta_data(sa_stream_t *s, const char *name, void*data, size_t *size);
-int sa_stream_get_adjust_pcm_rate(sa_stream_t *s, sa_adjust_t *direction);
-int sa_stream_get_adjust_pcm_nchannels(sa_stream_t *s, sa_adjust_t *direction);
-int sa_stream_get_adjust_pcm_format(sa_stream_t *s, sa_adjust_t *direction);
+int sa_stream_get_mode(sa_stream *s, sa_mode_t *access_mode);
+int sa_stream_get_codec(sa_stream *s, char **codec);
+int sa_stream_get_pcm_format(sa_stream *s, sa_pcm_format_t *format);
+int sa_stream_get_pcm_rate(sa_stream *s, unsigned *rate);
+int sa_stream_get_pcm_nchannels(sa_stream *s, unsigned *nchannels);
+int sa_stream_get_user_data(sa_stream *s, void **value);
+int sa_stream_get_write_latency(sa_stream *s, size_t *nbytes);
+int sa_stream_get_write_process_time(sa_stream *s, size_t *nbytes);
+int sa_stream_get_read_latency(sa_stream *s, size_t *nbytes);
+int sa_stream_get_read_process_time(sa_stream *s, size_t *nbytes);
+int sa_stream_get_pcm_channel_map(sa_stream *s, sa_channel_t **map, unsigned *n);
+int sa_stream_get_xrun_mode(sa_stream *s, sa_xrun_mode_t *mode);
+int sa_stream_get_non_interleaved(sa_stream *s, int *enabled);
+int sa_stream_get_dynamic_pcm_rate(sa_stream *s, int *enabled);
+int sa_stream_get_driver(sa_stream *s, char **driver_name);
+int sa_stream_get_device(sa_stream *s, char **device_name);
+int sa_stream_get_read_volume(sa_stream *s, int32_t **vol, unsigned *n);
+int sa_stream_get_write_volume(sa_stream *s, int32_t **vol, unsigned *n);
+int sa_stream_get_adjust_pcm_rate(sa_stream *s, sa_adjust_t *direction);
+int sa_stream_get_adjust_pcm_nchannels(sa_stream *s, sa_adjust_t *direction);
+int sa_stream_get_adjust_pcm_format(sa_stream *s, sa_adjust_t *direction);
/** Get current state of the audio device */
-int sa_stream_get_state(sa_stream_t *s, sa_state_t *state);
+int sa_stream_get_state(sa_stream *s, sa_state_t *state);
/** Obtain the error code */
-int sa_stream_get_event_error(sa_stream_t *s, int *error);
+int sa_stream_get_event_error(sa_stream *s, int *error);
/** Obtain the notification code */
-int sa_stream_get_event_notify(sa_stream_t *s, sa_notify_t *notify);
+int sa_stream_get_event_notify(sa_stream *s, sa_notify_t *notify, void **data, size_t *data_nbytes);
/** sync/timing */
-int sa_stream_get_position(sa_stream_t *s, sa_position_t position, int64_t *pos);
+int sa_stream_get_position(sa_stream *s, sa_position_t position, int64_t *pos);
-/* Blocking IO calls */
+/* IO calls */
+int sa_stream_wait(sa_stream *s, sa_event_t *event);
/** Interleaved capture function */
-int sa_stream_read(sa_stream_t *s, void *data, size_t nbytes);
+int sa_stream_read(sa_stream *s, void *data, size_t nbytes);
/** Non-interleaved capture function */
-int sa_stream_read_ni(sa_stream_t *s, unsigned channel, void *data, size_t nbytes);
+int sa_stream_read_ni(sa_stream *s, unsigned channel, void *data, size_t nbytes);
/** Interleaved playback function */
-int sa_stream_write(sa_stream_t *s, const void *data, size_t nbytes);
+int sa_stream_write(sa_stream *s, const void *data, size_t nbytes);
/** Non-interleaved playback function */
-int sa_stream_write_ni(sa_stream_t *s, unsigned channel, const void *data, size_t nbytes);
+int sa_stream_write_ni(sa_stream *s, unsigned channel, const void *data, size_t nbytes);
/** Interleaved playback function with seek offset */
-int sa_stream_pwrite(sa_stream_t *s, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence);
+int sa_stream_pwrite(sa_stream *s, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence);
/** Non-interleaved playback function with seek offset */
-int sa_stream_pwrite_ni(sa_stream_t *s, unsigned channel, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence);
+int sa_stream_pwrite_ni(sa_stream *s, unsigned channel, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence);
/** Query how much can be read without blocking */
-int sa_stream_get_read_size(sa_stream_t *s, size_t *nbytes);
+int sa_stream_get_read_size(sa_stream *s, size_t *nbytes);
/** Query how much can be written without blocking */
-int sa_stream_get_write_size(sa_stream_t *s, size_t *nbytes);
+int sa_stream_get_write_size(sa_stream *s, size_t *nbytes);
/* Control/xrun */
/** Resume playing after a pause */
-int sa_stream_start(sa_stream_t *s);
+int sa_stream_start(sa_stream *s);
/** Pause audio playback (do not empty the buffer) */
-int sa_stream_stop(sa_stream_t *s);
+int sa_stream_stop(sa_stream *s);
/** Block until all audio has been played */
-int sa_stream_drain(sa_stream_t *s);
+int sa_stream_drain(sa_stream *s);
/** Return a human readable error */
const char *sa_strerror(int code);
-/* Stream properties */
+unsigned sa_stream_bytes_to_frames(sa_stream *s, size_t nbytes, int round_up);
+size_t sa_stream_frames_to_bytes(sa_stream *s, unsigned nframes);
+
+uint64_t sa_stream_bytes_to_usec(sa_stream *s, size_t nbytes, int round_up);
+size_t sa_stream_usec_to_bytes(sa_stream *s, uint64_t usec, int round_up);
-/** Update meta data string properties that are attached to this stream. Takes a NULL terminated list of string key/value pairs. */
-int sa_stream_change_props(sa_stream_t *s, ...) SA_GCC_SENTINEL;
+uint64_t sa_stream_frames_to_usec(sa_stream *s, unsigned nframes, int round_up);
+unsigned sa_stream_usec_to_frames(sa_stream *s, uint64_t usec, int round_up);
-/** Update abritrary meta data properties that are attached to this stream */
-int sa_stream_change_prop(sa_stream_t *s, const char *key, const void *data, size_t nbytes);
+typedef struct sa_allocator {
+ void* (*malloc)(size_t size);
+ void* (*calloc)(size_t nmemb, size_t size);
+ void (*free)(void *ptr);
+ void* (*realloc)(void *ptr, size_t size);
+} sa_allocator;
-/** Remove abritrary meta data properties that are attached to this stream */
-int sa_stream_remove_prop(sa_stream_t *s, ...) SA_GCC_SENTINEL;
+void sa_set_allocator(const sa_allocator *a);
#ifdef __cplusplus
}
diff --git a/src/test-bufferq.c b/src/test-bufferq.c
index 79cd618..b99474d 100644
--- a/src/test-bufferq.c
+++ b/src/test-bufferq.c
@@ -1,3 +1,23 @@
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@@ -9,7 +29,7 @@ int main(int argc, char *argv[]) {
sa_bufferq_t q;
- sa_bufferq_init(&q, 1, 1);
+ sa_bufferq_init(&q, 1);
sa_bufferq_push(&q, 0, "{AAAAAAAA}", 10, 0, SA_SEEK_RELATIVE, SA_BUFFERQ_ITEM_STATIC);
sa_bufferq_push(&q, 0, "<BBBBBBBB>", 10, 5, SA_SEEK_RELATIVE, SA_BUFFERQ_ITEM_STATIC);
@@ -29,7 +49,7 @@ int main(int argc, char *argv[]) {
if (size == 0)
break;
- printf("Got %u bytes: ", size);
+ printf("Got %lu bytes: ", (unsigned long) size);
if (b[0])
fwrite(b[0], size, 1, stdout);
else
@@ -37,7 +57,7 @@ int main(int argc, char *argv[]) {
printf("\n");
- sa_bufferq_drop(&q, size);
+ sa_bufferq_drop(&q, (int64_t) size);
}
sa_bufferq_done(&q);
diff --git a/src/test-pull.c b/src/test-pull.c
index 993b7a3..281b8c4 100644
--- a/src/test-pull.c
+++ b/src/test-pull.c
@@ -1,3 +1,23 @@
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@@ -11,22 +31,11 @@
#include "sydney.h"
#include "macro.h"
-#define ASSERT_SUCCESS(x) do { \
- int _r; \
- if ((_r = x)) { \
- fprintf(stderr, "Operation <%s> failed: %s%s%s\n", \
- #x, \
- sa_strerror(_r), \
- _r == SA_ERROR_SYSTEM ? "; " : "", _r == SA_ERROR_SYSTEM ? strerror(errno) : ""); \
- } \
- assert(_r == SA_SUCCESS); \
-} while(0)
-
#define FREQ 440
static const float data[4] = { 0.0, 1.0, 0.0, -1.0 };
-static int callback(sa_stream_t *s, sa_event_t e) {
+static int callback(sa_stream *s, sa_event_t e) {
switch (e) {
case SA_EVENT_INIT_THREAD:
printf("Thread initialized.\n");
@@ -34,7 +43,7 @@ static int callback(sa_stream_t *s, sa_event_t e) {
case SA_EVENT_ERROR: {
int err;
- ASSERT_SUCCESS(sa_stream_get_event_error(s, &err));
+ sa_assert_se(sa_stream_get_event_error(s, &err) == 0);
printf("Error: %s\n", sa_strerror(err));
return -1;
}
@@ -45,9 +54,10 @@ static int callback(sa_stream_t *s, sa_event_t e) {
case SA_EVENT_REQUEST_IO:
- ASSERT_SUCCESS(sa_stream_write(s, data, sizeof(data)));
+ sa_assert_se(sa_stream_write(s, data, sizeof(data)) == 0);
return 0;
+ case SA_EVENT_XRUN:
case _SA_EVENT_MAX:
;
}
@@ -57,21 +67,21 @@ static int callback(sa_stream_t *s, sa_event_t e) {
int main(int argc, char *argv[]) {
- sa_stream_t *s;
+ sa_stream *s;
- ASSERT_SUCCESS(sa_stream_create_pcm(&s, "Sine Test (pull)", SA_MODE_WRONLY, SA_PCM_FORMAT_FLOAT32_NE, FREQ * 4, 1));
- ASSERT_SUCCESS(sa_stream_change_device(s, "/dev/dsp1"));
- ASSERT_SUCCESS(sa_stream_open(s));
+ sa_assert_se(sa_stream_create_pcm(&s, SA_MODE_WRONLY, SA_PCM_FORMAT_FLOAT32_NE, FREQ * 4, 1) == 0);
+ sa_assert_se(sa_stream_change_device(s, "/dev/dsp1") == 0);
+ sa_assert_se(sa_stream_open(s) == 0);
- ASSERT_SUCCESS(sa_stream_start_thread(s, callback));
+/* sa_assert_se(sa_stream_start_thread(s, callback)); */
sleep(20);
- ASSERT_SUCCESS(sa_stream_stop_thread(s));
+/* sa_assert_se(sa_stream_stop_thread(s)); */
- ASSERT_SUCCESS(sa_stream_drain(s));
+ sa_assert_se(sa_stream_drain(s) == 0);
- ASSERT_SUCCESS(sa_stream_destroy(s));
+ sa_assert_se(sa_stream_destroy(s) == 0);
return 0;
}
diff --git a/src/test-sine.c b/src/test-sine.c
index 633fabb..9ea6b32 100644
--- a/src/test-sine.c
+++ b/src/test-sine.c
@@ -1,3 +1,23 @@
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@@ -8,47 +28,36 @@
#include <string.h>
#include "sydney.h"
-
-#define ASSERT_SUCCESS(x) do { \
- int _r; \
- if ((_r = x)) { \
- fprintf(stderr, "Operation <%s> failed: %s%s%s\n", \
- #x, \
- sa_strerror(_r), \
- _r == SA_ERROR_SYSTEM ? "; " : "", _r == SA_ERROR_SYSTEM ? strerror(errno) : ""); \
- } \
- assert(_r == SA_SUCCESS); \
-} while(0)
+#include "macro.h"
#define FREQ 440
int main(int argc, char *argv[]) {
- sa_stream_t *s;
+ sa_stream *s;
float data[4] = { 0.0, 1.0, 0.0, -1.0 };
int i, j;
- ASSERT_SUCCESS(sa_stream_create_pcm(&s, "Sine Test", SA_MODE_WRONLY, SA_PCM_FORMAT_FLOAT32_NE, FREQ * 4, 1));
- ASSERT_SUCCESS(sa_stream_change_device(s, "/dev/dsp1"));
- sa_stream_change_meta_data(s, SA_META_CLIENT_NAME, argv[0], strlen(argv[0]));
- ASSERT_SUCCESS(sa_stream_open(s));
+ sa_assert_se(sa_stream_create_pcm(&s, SA_MODE_WRONLY, SA_PCM_FORMAT_FLOAT32_NE, FREQ * 4, 1) == 0);
+ sa_assert_se(sa_stream_change_device(s, "/dev/dsp1") == 0);
+ sa_assert_se(sa_stream_open(s) == 0);
for (j = 0; j < 10; j++) {
int v;
v = -j*500;
-/* ASSERT_SUCCESS(sa_stream_change_rate(dev, FREQ*4+100*j)); */
- ASSERT_SUCCESS(sa_stream_change_write_volume(s, &v, 1));
+/* sa_assert_se(sa_stream_change_rate(dev, FREQ*4+100*j)); */
+ sa_assert_se(sa_stream_change_write_volume(s, &v, 1));
for (i = 0; i < FREQ; i++)
- ASSERT_SUCCESS(sa_stream_write(s, data, sizeof(data)));
+ sa_assert_se(sa_stream_write(s, data, sizeof(data)));
}
- ASSERT_SUCCESS(sa_stream_drain(s));
+ sa_assert_se(sa_stream_drain(s));
- ASSERT_SUCCESS(sa_stream_destroy(s));
+ sa_assert_se(sa_stream_destroy(s) == 0);
return 0;
}
diff --git a/src/thread-posix.c b/src/thread-posix.c
index d76e8d5..33efe41 100644
--- a/src/thread-posix.c
+++ b/src/thread-posix.c
@@ -1,3 +1,23 @@
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@@ -17,6 +37,7 @@ struct sa_thread {
void *userdata;
int running;
sa_mutex *mutex;
+ sa_bool_t joined;
};
struct sa_tls {
@@ -78,6 +99,7 @@ sa_thread* sa_thread_new(sa_thread_func_t thread_func, void *userdata) {
t->thread_func = thread_func;
t->userdata = userdata;
t->running = 1;
+ t->joined = FALSE;
if (!(t->mutex = sa_mutex_new(FALSE, FALSE))) {
sa_free(t);
@@ -127,6 +149,10 @@ int sa_thread_join(sa_thread *t) {
/* Only allowed when this is not a foreign thread */
sa_assert(t->thread_func);
+ if (t->joined)
+ return -1;
+
+ t->joined = TRUE;
return pthread_join(t->id, NULL);
}
@@ -151,6 +177,7 @@ sa_thread* sa_thread_self(void) {
t->thread_func = NULL;
t->userdata = NULL;
t->running = 2;
+ t->joined = TRUE;
t->mutex = sa_mutex_new(FALSE, FALSE);
sa_tls_set(tid_tls, t);
diff --git a/src/thread.h b/src/thread.h
index 66071e1..947c614 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -1,6 +1,26 @@
#ifndef foosydneythreadhfoo
#define foosydneythreadhfoo
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
#include "macro.h"
typedef struct sa_thread sa_thread;
diff --git a/src/volscale.c b/src/volscale.c
index f29cb0e..86b187b 100644
--- a/src/volscale.c
+++ b/src/volscale.c
@@ -1,3 +1,23 @@
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@@ -13,8 +33,8 @@ static void volscale_u8(void *_dst, size_t dstr, const void *_src, size_t sstr,
for (; bytes > 0; bytes --) {
int32_t t = (((int32_t) *src - 0x80) * factor) / divisor;
- t = CLAMP(t, -0x80, 0x7F);
- *dst = (int8_t) (t+0x80);
+ t = SA_CLAMP(t, -0x80, 0x7F);
+ *dst = (uint8_t) (t+0x80);
src += sstr;
dst += dstr;
@@ -24,11 +44,11 @@ static void volscale_u8(void *_dst, size_t dstr, const void *_src, size_t sstr,
static void volscale_s16(void *_dst, size_t dstr, const void *_src, size_t sstr, int32_t factor, int32_t divisor, size_t bytes) {
int16_t *dst = _dst;
const int16_t *src = _src;
- unsigned n = bytes / sizeof(int16_t);
+ size_t n = bytes / sizeof(int16_t);
for (; n > 0; n--) {
int32_t t = ((int32_t) *src * factor) / divisor;
- t = CLAMP(t, -0x8000, 0x7FFF);
+ t = SA_CLAMP(t, -0x8000, 0x7FFF);
*dst = (int16_t) t;
src += sstr / sizeof(int16_t);
@@ -39,11 +59,11 @@ static void volscale_s16(void *_dst, size_t dstr, const void *_src, size_t sstr,
static void volscale_s32(void *_dst, size_t dstr, const void *_src, size_t sstr, int32_t factor, int32_t divisor, size_t bytes) {
int32_t *dst = _dst;
const int32_t *src = _src;
- unsigned n = bytes / sizeof(int32_t);
+ size_t n = bytes / sizeof(int32_t);
for (; n > 0; n--) {
int64_t t = ((int64_t) *src * factor) / divisor;
- t = CLAMP(t, -0x80000000L, 0x7FFFFFFFL);
+ t = SA_CLAMP(t, -0x80000000LL, 0x7FFFFFFFLL);
*dst = (int32_t) t;
src += sstr / sizeof(int32_t);
@@ -56,7 +76,7 @@ static void volscale_f32(void *_dst, size_t dstr, const void *_src, size_t sstr,
const float *src = _src;
float f = (float) factor / (float) divisor;
- oil_scalarmult_f32(dst, dstr, src, sstr, &f, size / sizeof(float));
+ oil_scalarmult_f32(dst, (int) dstr, src, (int) sstr, &f, (int) (size / sizeof(float)));
}
sa_volscale_func_t sa_get_volscale_func(sa_pcm_format_t f) {
diff --git a/src/volscale.h b/src/volscale.h
index fe6e037..745ab9b 100644
--- a/src/volscale.h
+++ b/src/volscale.h
@@ -1,6 +1,26 @@
#ifndef foosydneyvolscalehfoo
#define foosydneyvolscalehfoo
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
#include <sys/types.h>
#include <inttypes.h>
diff --git a/src/zero.c b/src/zero.c
index 9d4c054..0cceb23 100644
--- a/src/zero.c
+++ b/src/zero.c
@@ -1,3 +1,23 @@
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@@ -18,9 +38,31 @@ static void zero_u8(void *dst, size_t dstr, size_t bytes) {
}
}
+static void zero_ulaw(void *dst, size_t dstr, size_t bytes) {
+ uint8_t *d = dst;
+
+ if (dstr == 1)
+ memset(dst, 0xff, bytes);
+ else {
+ for (; bytes > 0; bytes --, d += dstr)
+ *d = 0xff;
+ }
+}
+
+static void zero_alaw(void *dst, size_t dstr, size_t bytes) {
+ uint8_t *d = dst;
+
+ if (dstr == 1)
+ memset(dst, 0xd5, bytes);
+ else {
+ for (; bytes > 0; bytes --, d += dstr)
+ *d = 0xd5;
+ }
+}
+
static void zero_16(void *dst, size_t dstr, size_t bytes) {
uint16_t *d = dst;
- unsigned n = bytes/sizeof(uint16_t);
+ size_t n = bytes/sizeof(uint16_t);
if (dstr == sizeof(uint16_t))
memset(dst, 0, bytes);
@@ -30,9 +72,21 @@ static void zero_16(void *dst, size_t dstr, size_t bytes) {
}
}
+static void zero_24(void *dst, size_t dstr, size_t bytes) {
+ uint8_t *d = dst;
+ size_t n = bytes/3;
+
+ if (dstr == 3)
+ memset(dst, 0, bytes);
+ else {
+ for (; n > 0; n --, d += dstr/3)
+ d[0] = d[1] = d[2] = 0;
+ }
+}
+
static void zero_32(void *dst, size_t dstr, size_t bytes) {
uint32_t *d = dst;
- unsigned n = bytes/sizeof(float);
+ size_t n = bytes/sizeof(float);
if (dstr == sizeof(uint32_t))
memset(dst, 0, bytes);
@@ -46,9 +100,16 @@ sa_zero_func_t sa_get_zero_func(sa_pcm_format_t f) {
static const sa_zero_func_t funcs[_SA_PCM_FORMAT_MAX] = {
[SA_PCM_FORMAT_U8] = zero_u8,
- [SA_PCM_FORMAT_S16_NE] = zero_16,
- [SA_PCM_FORMAT_S32_NE] = zero_32,
- [SA_PCM_FORMAT_FLOAT32_NE] = zero_32
+ [SA_PCM_FORMAT_ULAW] = zero_ulaw,
+ [SA_PCM_FORMAT_ALAW] = zero_alaw,
+ [SA_PCM_FORMAT_S16_LE] = zero_16,
+ [SA_PCM_FORMAT_S16_BE] = zero_16,
+ [SA_PCM_FORMAT_S24_LE] = zero_24,
+ [SA_PCM_FORMAT_S24_BE] = zero_24,
+ [SA_PCM_FORMAT_S32_LE] = zero_32,
+ [SA_PCM_FORMAT_S32_BE] = zero_32,
+ [SA_PCM_FORMAT_FLOAT32_LE] = zero_32,
+ [SA_PCM_FORMAT_FLOAT32_BE] = zero_32
};
sa_assert(f < _SA_PCM_FORMAT_MAX);
diff --git a/src/zero.h b/src/zero.h
index 6f59bdb..1abba0f 100644
--- a/src/zero.h
+++ b/src/zero.h
@@ -1,6 +1,26 @@
#ifndef foosydneyzerohfoo
#define foosydneyzerohfoo
+/***
+ This file is part of libsydney.
+
+ Copyright 2007-2008 Lennart Poettering
+
+ libsydney 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.
+
+ libsydney 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 libsydney. If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
#include <sys/types.h>
#include <inttypes.h>