From 181e9c6d5d11cb1e5d36a2777eeb233ad8ed00e5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 9 Oct 2008 18:15:23 +0200 Subject: big pile of updates to match more what happened with libcanberra --- .gitignore | 6 + configure.ac | 214 ++++++- src/.gitignore | 4 + src/Makefile.am | 280 ++++++++- src/add.c | 32 +- src/add.h | 20 + src/alsa.c | 1 + src/bbuffer.c | 20 + src/bbuffer.h | 20 + src/bswap.c | 44 +- src/bswap.h | 20 + src/bufferq.c | 46 +- src/bufferq.h | 20 + src/common.c | 1406 ++++++++++++++++++++++++++++------------------ src/common.h | 80 ++- src/continued-fraction.h | 20 + src/converter.c | 46 +- src/converter.h | 26 +- src/driver-order.c | 42 ++ src/driver-order.h | 26 + src/driver.h | 62 +- src/dso.c | 565 +++++++++++++++++++ src/format.c | 161 +++--- src/format.h | 20 + src/interleave.c | 26 +- src/interleave.h | 20 + src/jack.c | 1 + src/llist.h | 20 + src/macro.c | 34 ++ src/macro.h | 245 ++++++-- src/malloc.c | 159 ++++++ src/malloc.h | 34 +- src/map-file | 24 + src/mutex-posix.c | 20 + src/mutex.h | 20 + src/null.c | 111 ++++ src/oss.c | 403 +++++++------ src/proplist.c | 413 ++++++++++++++ src/proplist.h | 56 ++ src/pulse.c | 1 + src/resample.c | 32 +- src/resample.h | 23 +- src/sydney.h | 541 +++++++++++++----- src/test-bufferq.c | 26 +- src/test-pull.c | 54 +- src/test-sine.c | 51 +- src/thread-posix.c | 27 + src/thread.h | 20 + src/volscale.c | 34 +- src/volscale.h | 20 + src/zero.c | 71 ++- src/zero.h | 20 + 52 files changed, 4476 insertions(+), 1211 deletions(-) create mode 100644 src/.gitignore create mode 120000 src/alsa.c create mode 100644 src/driver-order.c create mode 100644 src/driver-order.h create mode 100644 src/dso.c create mode 120000 src/jack.c create mode 100644 src/macro.c create mode 100644 src/map-file create mode 100644 src/null.c create mode 100644 src/proplist.c create mode 100644 src/proplist.h create mode 120000 src/pulse.c 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 # . -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 + . +***/ + #ifdef HAVE_CONFIG_H #include #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 + . +***/ + #include #include 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 + . +***/ + #ifdef HAVE_CONFIG_H #include #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 + . +***/ + #include #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 + . +***/ + #ifdef HAVE_CONFIG_H #include #endif -#ifdef HAVE_BYTESWAP_H -#include -#endif - #include #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 + . +***/ + #include #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 + . +***/ + #ifdef HAVE_CONFIG_H #include #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 + . +***/ + #include #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 + . +***/ + #ifdef HAVE_CONFIG_H #include #endif #include #include +#include #include #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 + . +***/ + +#include + #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 + . +***/ + 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 + . +***/ + #ifdef HAVE_CONFIG_H #include #endif @@ -5,7 +25,7 @@ #include #include -#include "speex/speex_resampler.h" +#include #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 + . +***/ + #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 + . +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#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 + . +***/ + +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 + . +***/ + #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 + . +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#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 + . +***/ + #ifdef HAVE_CONFIG_H #include #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 + . +***/ + #include #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 + . +***/ + #ifdef HAVE_CONFIG_H #include #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 + . +***/ + #include #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 + . +***/ + #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 + . +***/ + +#ifdef HAVE_CONFIG_H +#include +#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 + . +***/ + #include -#include +#include + +#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 +#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 + . +***/ + #ifdef HAVE_CONFIG_H #include #endif #include +#include +#include +#include #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 + . +***/ + #include #include -#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 + . +***/ + #ifdef HAVE_CONFIG_H #include #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 + . +***/ + #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 + . +***/ + +#ifdef HAVE_CONFIG_H +#include +#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 + . +***/ + #ifdef HAVE_CONFIG_H #include #endif @@ -13,6 +33,17 @@ #include #include +#ifdef HAVE_MACHINE_SOUNDCARD_H +# include +#else +# ifdef HAVE_SOUNDCARD_H +# include +# else +# include +# 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 #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<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 + . +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#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 + . +***/ + +#include + +#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 + . +***/ + #ifdef HAVE_CONFIG_H #include #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 + . +***/ + #include #include +#include + #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 + . +***/ #include #include #include +#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 + . +***/ + #ifdef HAVE_CONFIG_H #include #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, "", 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 + . +***/ + #ifdef HAVE_CONFIG_H #include #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 + . +***/ + #ifdef HAVE_CONFIG_H #include #endif @@ -8,47 +28,36 @@ #include #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 + . +***/ + #ifdef HAVE_CONFIG_H #include #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 + . +***/ + #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 + . +***/ + #ifdef HAVE_CONFIG_H #include #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 + . +***/ + #include #include 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 + . +***/ + #ifdef HAVE_CONFIG_H #include #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 + . +***/ + #include #include -- cgit