diff --git a/configure.ac b/configure.ac index 0e53752..da9ab4e 100644 --- a/configure.ac +++ b/configure.ac @@ -32,13 +32,15 @@ dnl Check for programs dnl ==================================== cflags_save="$CFLAGS" +cppflags_save="$CPPFLAGS" AC_PROG_CC +AC_PROG_CXX AC_LIBTOOL_WIN32_DLL AC_LIBTOOL_DLOPEN AM_PROG_LIBTOOL dnl ==================================== -dnl Check dlopen +dnl Check dlopen dnl ==================================== dnl Currently use this to disable plugin support dlfcn.h @@ -70,6 +72,7 @@ if test -z "$GCC"; then PLUGIN_LDFLAGS="-export-dynamic -avoid-version" DEBUG="-g" CFLAGS="-O" + CPPFLAGS="-O" PROFILE="-g -p" ;; esac else @@ -94,10 +97,12 @@ else PLUGIN_LDFLAGS="-export-dynamic -avoid-version" DEBUG="-g -Wall -D__NO_MATH_INLINES -fsigned-char" CFLAGS="-O20 -D__NO_MATH_INLINES -fsigned-char" + CPPFLAGS="-O20 -D__NO_MATH_INLINES -fsigned-char" PROFILE="-O20 -g -pg -D__NO_MATH_INLINES -fsigned-char" ;; esac fi CFLAGS="$CFLAGS $cflags_save -DAO_BUILDING_LIBAO" +CPPFLAGS="$CPPFLAGS $cppflags_save -DAO_BUILDING_LIBAO" DEBUG="$DEBUG $cflags_save -DAO_BUILDING_LIBAO" PROFILE="$PROFILE $cflags_save -DAO_BUILDING_LIBAO" @@ -113,7 +118,7 @@ case $host in *-mingw*|*-cygwin*) LIBAO_LA_LDFLAGS="-no-undefined" ;; - *) + *) LIBAO_LA_LDFLAGS="" ;; esac @@ -153,7 +158,7 @@ case $host in *hpux*) DLOPEN_FLAG='(RTLD_LAZY)' SHARED_LIB_EXT='.sl' - ;; + ;; *openbsd* | *netbsd* | *solaris2.7 | *darwin*) DLOPEN_FLAG='(RTLD_LAZY)' SHARED_LIB_EXT='.so' @@ -196,7 +201,7 @@ AC_SUBST(SIZE16) AC_SUBST(SIZE32) dnl ====================================== -dnl Disable default use of SLP in roar +dnl Disable default use of SLP in roar dnl until such time as SLP doesn't block dnl indefinitely dnl ====================================== @@ -214,7 +219,7 @@ fi AC_SUBST([SLP_DEF]) dnl ====================================== -dnl Detect possible output devices +dnl Detect possible output devices dnl ====================================== dnl Check for WMM @@ -311,7 +316,7 @@ if test "x$enable_broken_oss" = "xyes"; then AC_DEFINE(BROKEN_OSS) AC_MSG_WARN(Broken OSS API workaround enabled. See README for details.) fi - + dnl Check for Sun audio have_sun="no"; @@ -426,7 +431,7 @@ if test "$BUILD_NAS" = "yes"; then AC_PATH_XTRA AC_CHECK_LIB(Xau, XauFileName, have_nas=yes, have_nas=no, $X_LIBS) AC_CHECK_LIB(audio, AuOpenServer, dummy="no-op", have_nas=no, -lXau $X_LIBS) - + ac_save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $X_CFLAGS" AC_CHECK_HEADER(audio/audiolib.h, dummy="no-op", have_nas=no) @@ -459,6 +464,12 @@ AC_SUBST(PULSE_LIBS) AM_CONDITIONAL(HAVE_PULSE,test "x$have_pulse" = xyes) +dnl Check for Haiku audio + +have_haiku="no"; +AC_CHECK_HEADERS(MediaDefs.h, have_haiku=yes) +AM_CONDITIONAL(HAVE_HAIKU,test "${have_haiku}" = yes) + dnl Orphaned driver. We'll probably dump it soon. AM_CONDITIONAL(HAVE_SOLARIS,test "x$have_solaris" = xyes) @@ -466,7 +477,7 @@ dnl Plugins get special LDFLAGS AC_SUBST(PLUGIN_LDFLAGS) -AC_OUTPUT([Makefile src/Makefile doc/Makefile include/Makefile include/ao/Makefile include/ao/os_types.h src/plugins/Makefile src/plugins/esd/Makefile src/plugins/oss/Makefile src/plugins/alsa/Makefile src/plugins/sun/Makefile src/plugins/irix/Makefile src/plugins/arts/Makefile src/plugins/macosx/Makefile src/plugins/nas/Makefile src/plugins/pulse/Makefile src/plugins/sndio/Makefile src/plugins/roar/Makefile ao.pc]) +AC_OUTPUT([Makefile src/Makefile doc/Makefile include/Makefile include/ao/Makefile include/ao/os_types.h src/plugins/Makefile src/plugins/esd/Makefile src/plugins/oss/Makefile src/plugins/alsa/Makefile src/plugins/sun/Makefile src/plugins/irix/Makefile src/plugins/arts/Makefile src/plugins/macosx/Makefile src/plugins/nas/Makefile src/plugins/pulse/Makefile src/plugins/sndio/Makefile src/plugins/roar/Makefile src/plugins/haiku/Makefile ao.pc]) AS_AC_EXPAND(LIBDIR, ${libdir}) AS_AC_EXPAND(INCLUDEDIR, ${includedir}) @@ -487,6 +498,7 @@ AC_MSG_RESULT([ ALSA live output: ............ ${have_alsa} ARTS live output: ............ ${have_arts} ESD live output: ............. ${have_esd} + HAIKU live output: ........... ${have_haiku} IRIX live output: ............ ${have_irix} MACOSX live output: .......... ${have_macosx} NAS live output: ............. ${have_nas} diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am index 1af2303..1b417d4 100644 --- a/src/plugins/Makefile.am +++ b/src/plugins/Makefile.am @@ -1,4 +1,4 @@ ## Process this file with automake to produce Makefile.in AUTOMAKE_OPTIONS = foreign -SUBDIRS = oss esd arts alsa sun irix macosx nas pulse sndio roar +SUBDIRS = oss esd arts alsa sun irix macosx nas pulse sndio roar haiku diff --git a/src/plugins/haiku/Makefile.am b/src/plugins/haiku/Makefile.am new file mode 100644 index 0000000..596c664 --- /dev/null +++ b/src/plugins/haiku/Makefile.am @@ -0,0 +1,25 @@ +## Process this file with automake to produce Makefile.in + +AUTOMAKE_OPTIONS = foreign + +if HAVE_HAIKU + +haikultlibs = libhaiku.la +haikusources = ao_haiku.cpp + +else + +haikultlibs = +haikusources = + +endif + +INCLUDES = -I$(top_builddir)/include/ao -I$(top_srcdir)/include + +libdir = $(plugindir) +lib_LTLIBRARIES = $(haikultlibs) + +libhaiku_la_LDFLAGS = @PLUGIN_LDFLAGS@ -lbe -lmedia +libhaiku_la_SOURCES = $(haikusources) + +EXTRA_DIST = ao_haiku.cpp diff --git a/src/plugins/haiku/ao_haiku.cpp b/src/plugins/haiku/ao_haiku.cpp new file mode 100644 index 0000000..58d9dcb --- /dev/null +++ b/src/plugins/haiku/ao_haiku.cpp @@ -0,0 +1,254 @@ +/* + * ao_haiku.cpp + * + * Copyright (C) Julian Harnath - March 2014 + * + * This file is part of libao, a cross-platform audio output library. See + * README for a history of this source code. + * + * libao is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * libao is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + ********************************************************************/ + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + + +static char* ao_haiku_options[] = { + "matrix" +}; + + +struct ao_info ao_haiku_info = { + AO_TYPE_LIVE, + "Haiku Media Kit Output", + "haiku", + "Julian Harnath ", + "Outputs to the Haiku Media Kit", + AO_FMT_NATIVE, + 30, + ao_haiku_options, + sizeof(ao_haiku_options) / sizeof(*ao_haiku_options) +}; + + +typedef struct ao_haiku_internal { + media_raw_audio_format* format; + BSoundPlayer* sound_player; + + sem_id new_buffer; + sem_id buffer_done; + + uint8* buffer; + size_t buffer_size; + size_t buffer_filled; +} ao_haiku_internal; + + +int +ao_plugin_test() +{ + BSoundPlayer testPlayer; + return testPlayer.InitCheck() == B_OK ? 1 :0; +} + + +ao_info* +ao_plugin_driver_info() +{ + return &ao_haiku_info; +} + + +int +ao_plugin_device_init(ao_device* device) +{ + ao_haiku_internal* const internal = (ao_haiku_internal*)calloc(1, + sizeof(ao_haiku_internal)); + if (internal == NULL) + return 0; + + internal->format = (media_raw_audio_format*)malloc( + sizeof(media_raw_audio_format)); + if (internal->format == NULL) { + free(internal); + return 0; + } + + internal->new_buffer = create_sem(0, "New buffer request"); + internal->buffer_done = create_sem(1, "Buffer done"); + + device->output_matrix_order = AO_OUTPUT_MATRIX_FIXED; + device->internal = internal; + + return 1; +} + + +int +ao_plugin_set_option(ao_device* device, const char* key, const char* value) +{ + return 1; +} + + +static void +fill_buffer(void* cookie, void* buffer, size_t size, + const media_raw_audio_format& format) +{ + ao_haiku_internal* const internal = (ao_haiku_internal*)cookie; + + internal->buffer = (uint8*)buffer; + internal->buffer_size = size; + internal->buffer_filled = 0; + release_sem(internal->new_buffer); + acquire_sem(internal->buffer_done); +} + + +int +ao_plugin_open(ao_device* device, ao_sample_format* format) +{ + ao_haiku_internal* const internal = (ao_haiku_internal*)device->internal; + media_raw_audio_format* const mediaRawFormat = internal->format; + + mediaRawFormat->frame_rate = format->rate; + mediaRawFormat->channel_count = device->output_channels; + + switch (format->bits) { + case 8: + mediaRawFormat->format = media_raw_audio_format::B_AUDIO_CHAR; + break; + case 16: + mediaRawFormat->format = media_raw_audio_format::B_AUDIO_SHORT; + break; + case 32: + mediaRawFormat->format = media_raw_audio_format::B_AUDIO_INT; + break; + default: + aerror("Unsupported sample bit depth"); + return 0; + } + + device->driver_byte_format = AO_FMT_NATIVE; + if (B_HOST_IS_LENDIAN) + mediaRawFormat->byte_order = B_MEDIA_LITTLE_ENDIAN; + else + mediaRawFormat->byte_order = B_MEDIA_BIG_ENDIAN; + + mediaRawFormat->buffer_size = BMediaRoster::Roster()->AudioBufferSizeFor( + mediaRawFormat->channel_count, mediaRawFormat->format, + mediaRawFormat->frame_rate, B_UNKNOWN_BUS) * 2; + + internal->sound_player = new BSoundPlayer(mediaRawFormat, "ao player", + fill_buffer, NULL, internal); + + if (internal->sound_player->InitCheck() != B_OK) { + delete internal->sound_player; + internal->sound_player = NULL; + return 0; + } + + internal->sound_player->SetVolume(1.0); + internal->sound_player->Start(); + internal->sound_player->SetHasData(false); + + if (device->inter_matrix == NULL) { + if (device->output_channels <= 2) + device->inter_matrix = strdup("L,R"); + } + + return 1; +} + + +int +ao_plugin_play(ao_device* device, const char* output_samples, + uint_32 num_bytes) +{ + ao_haiku_internal* const internal = (ao_haiku_internal*)device->internal; + BSoundPlayer* const soundPlayer = internal->sound_player; + + if (num_bytes == 0) { + soundPlayer->SetHasData(false); + return 1; + } + + soundPlayer->SetHasData(true); + acquire_sem(internal->new_buffer); + + size_t bytesLeft = num_bytes; + while (bytesLeft > 0) { + if (internal->buffer_filled == internal->buffer_size) { + // Request another buffer from BSoundPlayer + release_sem(internal->buffer_done); + acquire_sem(internal->new_buffer); + } + + const size_t copyBytes = std::min(bytesLeft, internal->buffer_size + - internal->buffer_filled); + memcpy(internal->buffer + internal->buffer_filled, output_samples, + copyBytes); + internal->buffer_filled += copyBytes; + output_samples += copyBytes; + bytesLeft -= copyBytes; + } + + if (internal->buffer_filled < internal->buffer_size) { + // Continue filling this buffer the next time this function is called + release_sem(internal->new_buffer); + } else { + // Buffer is full + release_sem(internal->buffer_done); + soundPlayer->SetHasData(false); + } + + return 1; +} + + +int +ao_plugin_close(ao_device* device) +{ + ao_haiku_internal* const internal = (ao_haiku_internal*)device->internal; + + release_sem(internal->buffer_done); + internal->sound_player->SetHasData(false); + internal->sound_player->Stop(); + delete internal->sound_player; + + return 1; +} + + +void +ao_plugin_device_clear(ao_device* device) +{ + ao_haiku_internal* const internal = (ao_haiku_internal*)device->internal; + + free(internal->format); + delete_sem(internal->new_buffer); + delete_sem(internal->buffer_done); + free(internal); +}