diff options
Diffstat (limited to 'sys/osxaudio')
-rwxr-xr-x | sys/osxaudio/Makefile.am | 37 | ||||
-rwxr-xr-x | sys/osxaudio/Makefile.in | 971 | ||||
-rwxr-xr-x | sys/osxaudio/gstosxaudio.c | 53 | ||||
-rwxr-xr-x | sys/osxaudio/gstosxaudioelement.c | 92 | ||||
-rwxr-xr-x | sys/osxaudio/gstosxaudioelement.h | 92 | ||||
-rwxr-xr-x | sys/osxaudio/gstosxaudioringbuffer.c | 313 | ||||
-rwxr-xr-x | sys/osxaudio/gstosxaudioringbuffer.h | 98 | ||||
-rwxr-xr-x | sys/osxaudio/gstosxaudiosink.c | 656 | ||||
-rwxr-xr-x | sys/osxaudio/gstosxaudiosink.h | 98 | ||||
-rwxr-xr-x | sys/osxaudio/gstosxaudiosrc.c | 334 | ||||
-rwxr-xr-x | sys/osxaudio/gstosxaudiosrc.h | 83 | ||||
-rwxr-xr-x | sys/osxaudio/gstosxcoreaudio.c | 221 | ||||
-rwxr-xr-x | sys/osxaudio/gstosxcoreaudio.h | 151 | ||||
-rwxr-xr-x | sys/osxaudio/gstosxcoreaudiocommon.c | 430 | ||||
-rwxr-xr-x | sys/osxaudio/gstosxcoreaudiocommon.h | 65 | ||||
-rwxr-xr-x | sys/osxaudio/gstosxcoreaudiohal.c | 1254 | ||||
-rwxr-xr-x | sys/osxaudio/gstosxcoreaudioremoteio.c | 126 |
17 files changed, 5074 insertions, 0 deletions
diff --git a/sys/osxaudio/Makefile.am b/sys/osxaudio/Makefile.am new file mode 100755 index 0000000..12b7d03 --- /dev/null +++ b/sys/osxaudio/Makefile.am @@ -0,0 +1,37 @@ +plugin_LTLIBRARIES = libgstosxaudio.la + +libgstosxaudio_la_SOURCES = gstosxaudioringbuffer.c \ + gstosxaudioelement.c \ + gstosxaudiosink.c \ + gstosxaudiosrc.c \ + gstosxcoreaudiocommon.c \ + gstosxcoreaudio.c \ + gstosxaudio.c + +libgstosxaudio_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) \ + -Wno-deprecated-declarations +libgstosxaudio_la_LIBADD = \ + -lgstaudio-@GST_API_VERSION@ \ + $(GST_PLUGINS_BASE_LIBS) \ + $(GST_BASE_LIBS) \ + $(GST_LIBS) + +libgstosxaudio_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -Wl,-framework,CoreAudio -Wl,-framework,AudioToolbox + +if !HAVE_IOS +libgstosxaudio_la_LDFLAGS += -Wl,-framework,AudioUnit -Wl,-framework,CoreServices +endif + +libgstosxaudio_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS) --tag=CC + +noinst_HEADERS = gstosxaudiosink.h \ + gstosxaudioelement.h \ + gstosxaudioringbuffer.h \ + gstosxaudiosrc.h \ + gstosxcoreaudiocommon.h \ + gstosxcoreaudio.h \ + gstosxcoreaudiohal.c \ + gstosxcoreaudioremoteio.c + + + diff --git a/sys/osxaudio/Makefile.in b/sys/osxaudio/Makefile.in new file mode 100755 index 0000000..25d02ac --- /dev/null +++ b/sys/osxaudio/Makefile.in @@ -0,0 +1,971 @@ +# Makefile.in generated by automake 1.14.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +@HAVE_IOS_FALSE@am__append_1 = -Wl,-framework,AudioUnit -Wl,-framework,CoreServices +subdir = sys/osxaudio +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ + $(top_srcdir)/depcomp $(noinst_HEADERS) +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \ + $(top_srcdir)/common/m4/as-auto-alt.m4 \ + $(top_srcdir)/common/m4/as-compiler-flag.m4 \ + $(top_srcdir)/common/m4/as-gcc-inline-assembly.m4 \ + $(top_srcdir)/common/m4/as-libtool.m4 \ + $(top_srcdir)/common/m4/as-version.m4 \ + $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \ + $(top_srcdir)/common/m4/gst-arch.m4 \ + $(top_srcdir)/common/m4/gst-args.m4 \ + $(top_srcdir)/common/m4/gst-check.m4 \ + $(top_srcdir)/common/m4/gst-default.m4 \ + $(top_srcdir)/common/m4/gst-dowhile.m4 \ + $(top_srcdir)/common/m4/gst-error.m4 \ + $(top_srcdir)/common/m4/gst-feature.m4 \ + $(top_srcdir)/common/m4/gst-gettext.m4 \ + $(top_srcdir)/common/m4/gst-glib2.m4 \ + $(top_srcdir)/common/m4/gst-package-release-datetime.m4 \ + $(top_srcdir)/common/m4/gst-platform.m4 \ + $(top_srcdir)/common/m4/gst-plugin-docs.m4 \ + $(top_srcdir)/common/m4/gst-plugindir.m4 \ + $(top_srcdir)/common/m4/gst-x11.m4 \ + $(top_srcdir)/common/m4/gst.m4 \ + $(top_srcdir)/common/m4/gtk-doc.m4 \ + $(top_srcdir)/common/m4/orc.m4 $(top_srcdir)/common/m4/pkg.m4 \ + $(top_srcdir)/m4/aalib.m4 $(top_srcdir)/m4/gettext.m4 \ + $(top_srcdir)/m4/gst-fionread.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \ + $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ + $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(plugindir)" +LTLIBRARIES = $(plugin_LTLIBRARIES) +am__DEPENDENCIES_1 = +libgstosxaudio_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +am_libgstosxaudio_la_OBJECTS = \ + libgstosxaudio_la-gstosxaudioringbuffer.lo \ + libgstosxaudio_la-gstosxaudioelement.lo \ + libgstosxaudio_la-gstosxaudiosink.lo \ + libgstosxaudio_la-gstosxaudiosrc.lo \ + libgstosxaudio_la-gstosxcoreaudiocommon.lo \ + libgstosxaudio_la-gstosxcoreaudio.lo \ + libgstosxaudio_la-gstosxaudio.lo +libgstosxaudio_la_OBJECTS = $(am_libgstosxaudio_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +libgstosxaudio_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(libgstosxaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ + $(CCLD) $(libgstosxaudio_la_CFLAGS) $(CFLAGS) \ + $(libgstosxaudio_la_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(libgstosxaudio_la_SOURCES) +DIST_SOURCES = $(libgstosxaudio_la_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +HEADERS = $(noinst_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +AALIB_CFLAGS = @AALIB_CFLAGS@ +AALIB_CONFIG = @AALIB_CONFIG@ +AALIB_LIBS = @AALIB_LIBS@ +ACLOCAL = @ACLOCAL@ +ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BZ2_LIBS = @BZ2_LIBS@ +CAIRO_CFLAGS = @CAIRO_CFLAGS@ +CAIRO_LIBS = @CAIRO_LIBS@ +CC = @CC@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_AUDIOSINK = @DEFAULT_AUDIOSINK@ +DEFAULT_AUDIOSRC = @DEFAULT_AUDIOSRC@ +DEFAULT_VIDEOSINK = @DEFAULT_VIDEOSINK@ +DEFAULT_VIDEOSRC = @DEFAULT_VIDEOSRC@ +DEFAULT_VISUALIZER = @DEFAULT_VISUALIZER@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DEPRECATED_CFLAGS = @DEPRECATED_CFLAGS@ +DIRECTSOUND_CFLAGS = @DIRECTSOUND_CFLAGS@ +DIRECTSOUND_LDFLAGS = @DIRECTSOUND_LDFLAGS@ +DIRECTSOUND_LIBS = @DIRECTSOUND_LIBS@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +DV1394_CFLAGS = @DV1394_CFLAGS@ +DV1394_LIBS = @DV1394_LIBS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ERROR_CFLAGS = @ERROR_CFLAGS@ +ERROR_CXXFLAGS = @ERROR_CXXFLAGS@ +ERROR_OBJCFLAGS = @ERROR_OBJCFLAGS@ +EXEEXT = @EXEEXT@ +FFLAGS = @FFLAGS@ +FGREP = @FGREP@ +FLAC_CFLAGS = @FLAC_CFLAGS@ +FLAC_LIBS = @FLAC_LIBS@ +GCOV = @GCOV@ +GCOV_CFLAGS = @GCOV_CFLAGS@ +GCOV_LIBS = @GCOV_LIBS@ +GDK_PIXBUF_CFLAGS = @GDK_PIXBUF_CFLAGS@ +GDK_PIXBUF_LIBS = @GDK_PIXBUF_LIBS@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ +GIO_CFLAGS = @GIO_CFLAGS@ +GIO_LDFLAGS = @GIO_LDFLAGS@ +GIO_LIBS = @GIO_LIBS@ +GLIB_CFLAGS = @GLIB_CFLAGS@ +GLIB_EXTRA_CFLAGS = @GLIB_EXTRA_CFLAGS@ +GLIB_GENMARSHAL = @GLIB_GENMARSHAL@ +GLIB_LIBS = @GLIB_LIBS@ +GLIB_MKENUMS = @GLIB_MKENUMS@ +GLIB_PREFIX = @GLIB_PREFIX@ +GLIB_REQ = @GLIB_REQ@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GREP = @GREP@ +GSTPB_PLUGINS_DIR = @GSTPB_PLUGINS_DIR@ +GSTPB_PREFIX = @GSTPB_PREFIX@ +GST_AGE = @GST_AGE@ +GST_ALL_LDFLAGS = @GST_ALL_LDFLAGS@ +GST_API_VERSION = @GST_API_VERSION@ +GST_BASE_CFLAGS = @GST_BASE_CFLAGS@ +GST_BASE_LIBS = @GST_BASE_LIBS@ +GST_CFLAGS = @GST_CFLAGS@ +GST_CHECK_CFLAGS = @GST_CHECK_CFLAGS@ +GST_CHECK_LIBS = @GST_CHECK_LIBS@ +GST_CONTROLLER_CFLAGS = @GST_CONTROLLER_CFLAGS@ +GST_CONTROLLER_LIBS = @GST_CONTROLLER_LIBS@ +GST_CURRENT = @GST_CURRENT@ +GST_CXXFLAGS = @GST_CXXFLAGS@ +GST_LEVEL_DEFAULT = @GST_LEVEL_DEFAULT@ +GST_LIBS = @GST_LIBS@ +GST_LIBVERSION = @GST_LIBVERSION@ +GST_LICENSE = @GST_LICENSE@ +GST_LT_LDFLAGS = @GST_LT_LDFLAGS@ +GST_NET_CFLAGS = @GST_NET_CFLAGS@ +GST_NET_LIBS = @GST_NET_LIBS@ +GST_OBJCFLAGS = @GST_OBJCFLAGS@ +GST_OPTION_CFLAGS = @GST_OPTION_CFLAGS@ +GST_OPTION_CXXFLAGS = @GST_OPTION_CXXFLAGS@ +GST_OPTION_OBJCFLAGS = @GST_OPTION_OBJCFLAGS@ +GST_PACKAGE_NAME = @GST_PACKAGE_NAME@ +GST_PACKAGE_ORIGIN = @GST_PACKAGE_ORIGIN@ +GST_PLUGINS_ALL = @GST_PLUGINS_ALL@ +GST_PLUGINS_BASE_CFLAGS = @GST_PLUGINS_BASE_CFLAGS@ +GST_PLUGINS_BASE_DIR = @GST_PLUGINS_BASE_DIR@ +GST_PLUGINS_BASE_LIBS = @GST_PLUGINS_BASE_LIBS@ +GST_PLUGINS_DIR = @GST_PLUGINS_DIR@ +GST_PLUGINS_NONPORTED = @GST_PLUGINS_NONPORTED@ +GST_PLUGINS_SELECTED = @GST_PLUGINS_SELECTED@ +GST_PLUGIN_LDFLAGS = @GST_PLUGIN_LDFLAGS@ +GST_PLUGIN_LIBTOOLFLAGS = @GST_PLUGIN_LIBTOOLFLAGS@ +GST_PREFIX = @GST_PREFIX@ +GST_REVISION = @GST_REVISION@ +GST_TOOLS_DIR = @GST_TOOLS_DIR@ +GTKDOC_CHECK = @GTKDOC_CHECK@ +GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@ +GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@ +GTKDOC_MKPDF = @GTKDOC_MKPDF@ +GTKDOC_REBASE = @GTKDOC_REBASE@ +GTK_CFLAGS = @GTK_CFLAGS@ +GTK_LIBS = @GTK_LIBS@ +GTK_X11_CFLAGS = @GTK_X11_CFLAGS@ +GTK_X11_LIBS = @GTK_X11_LIBS@ +GUDEV_CFLAGS = @GUDEV_CFLAGS@ +GUDEV_LIBS = @GUDEV_LIBS@ +HAVE_AVC1394 = @HAVE_AVC1394@ +HAVE_CXX = @HAVE_CXX@ +HAVE_DIRECTSOUND = @HAVE_DIRECTSOUND@ +HAVE_ROM1394 = @HAVE_ROM1394@ +HAVE_SPEEX = @HAVE_SPEEX@ +HAVE_X = @HAVE_X@ +HAVE_XSHM = @HAVE_XSHM@ +HAVE_ZLIB = @HAVE_ZLIB@ +HTML_DIR = @HTML_DIR@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +JACK_0_120_1_CFLAGS = @JACK_0_120_1_CFLAGS@ +JACK_0_120_1_LIBS = @JACK_0_120_1_LIBS@ +JACK_1_9_7_CFLAGS = @JACK_1_9_7_CFLAGS@ +JACK_1_9_7_LIBS = @JACK_1_9_7_LIBS@ +JACK_CFLAGS = @JACK_CFLAGS@ +JACK_LIBS = @JACK_LIBS@ +JPEG_LIBS = @JPEG_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBCACA_CFLAGS = @LIBCACA_CFLAGS@ +LIBCACA_LIBS = @LIBCACA_LIBS@ +LIBDV_CFLAGS = @LIBDV_CFLAGS@ +LIBDV_LIBS = @LIBDV_LIBS@ +LIBICONV = @LIBICONV@ +LIBIEC61883_CFLAGS = @LIBIEC61883_CFLAGS@ +LIBIEC61883_LIBS = @LIBIEC61883_LIBS@ +LIBINTL = @LIBINTL@ +LIBM = @LIBM@ +LIBOBJS = @LIBOBJS@ +LIBPNG_CFLAGS = @LIBPNG_CFLAGS@ +LIBPNG_LIBS = @LIBPNG_LIBS@ +LIBRT = @LIBRT@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBV4L2_CFLAGS = @LIBV4L2_CFLAGS@ +LIBV4L2_LIBS = @LIBV4L2_LIBS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LOCALEDIR = @LOCALEDIR@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJC = @OBJC@ +OBJCDEPMODE = @OBJCDEPMODE@ +OBJCFLAGS = @OBJCFLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +ORCC = @ORCC@ +ORCC_FLAGS = @ORCC_FLAGS@ +ORC_CFLAGS = @ORC_CFLAGS@ +ORC_LIBS = @ORC_LIBS@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@ +PACKAGE_VERSION_MICRO = @PACKAGE_VERSION_MICRO@ +PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@ +PACKAGE_VERSION_NANO = @PACKAGE_VERSION_NANO@ +PACKAGE_VERSION_RELEASE = @PACKAGE_VERSION_RELEASE@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PLUGINDIR = @PLUGINDIR@ +POSUB = @POSUB@ +PROFILE_CFLAGS = @PROFILE_CFLAGS@ +PULSE_CFLAGS = @PULSE_CFLAGS@ +PULSE_LIBS = @PULSE_LIBS@ +PYTHON = @PYTHON@ +PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ +PYTHON_PLATFORM = @PYTHON_PLATFORM@ +PYTHON_PREFIX = @PYTHON_PREFIX@ +PYTHON_VERSION = @PYTHON_VERSION@ +RANLIB = @RANLIB@ +RAW1394_CFLAGS = @RAW1394_CFLAGS@ +RAW1394_LIBS = @RAW1394_LIBS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SHOUT2_CFLAGS = @SHOUT2_CFLAGS@ +SHOUT2_LIBS = @SHOUT2_LIBS@ +SOUP_CFLAGS = @SOUP_CFLAGS@ +SOUP_LIBS = @SOUP_LIBS@ +SPEEX_CFLAGS = @SPEEX_CFLAGS@ +SPEEX_LIBS = @SPEEX_LIBS@ +STRIP = @STRIP@ +TAGLIB_CFLAGS = @TAGLIB_CFLAGS@ +TAGLIB_CXXFLAGS = @TAGLIB_CXXFLAGS@ +TAGLIB_LIBS = @TAGLIB_LIBS@ +USE_NLS = @USE_NLS@ +VALGRIND_CFLAGS = @VALGRIND_CFLAGS@ +VALGRIND_LIBS = @VALGRIND_LIBS@ +VALGRIND_PATH = @VALGRIND_PATH@ +VERSION = @VERSION@ +VPX_130_CFLAGS = @VPX_130_CFLAGS@ +VPX_130_LIBS = @VPX_130_LIBS@ +VPX_CFLAGS = @VPX_CFLAGS@ +VPX_LIBS = @VPX_LIBS@ +WARNING_CFLAGS = @WARNING_CFLAGS@ +WARNING_CXXFLAGS = @WARNING_CXXFLAGS@ +WARNING_OBJCFLAGS = @WARNING_OBJCFLAGS@ +WAVPACK_CFLAGS = @WAVPACK_CFLAGS@ +WAVPACK_LIBS = @WAVPACK_LIBS@ +XDAMAGE_CFLAGS = @XDAMAGE_CFLAGS@ +XDAMAGE_LIBS = @XDAMAGE_LIBS@ +XFIXES_CFLAGS = @XFIXES_CFLAGS@ +XFIXES_LIBS = @XFIXES_LIBS@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ +XMKMF = @XMKMF@ +XSHM_LIBS = @XSHM_LIBS@ +X_CFLAGS = @X_CFLAGS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_LIBS = @X_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +ZLIB_LIBS = @ZLIB_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +ac_ct_OBJC = @ac_ct_OBJC@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgpyexecdir = @pkgpyexecdir@ +pkgpythondir = @pkgpythondir@ +plugindir = @plugindir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +pyexecdir = @pyexecdir@ +pythondir = @pythondir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +plugin_LTLIBRARIES = libgstosxaudio.la +libgstosxaudio_la_SOURCES = gstosxaudioringbuffer.c \ + gstosxaudioelement.c \ + gstosxaudiosink.c \ + gstosxaudiosrc.c \ + gstosxcoreaudiocommon.c \ + gstosxcoreaudio.c \ + gstosxaudio.c + +libgstosxaudio_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) \ + -Wno-deprecated-declarations + +libgstosxaudio_la_LIBADD = \ + -lgstaudio-@GST_API_VERSION@ \ + $(GST_PLUGINS_BASE_LIBS) \ + $(GST_BASE_LIBS) \ + $(GST_LIBS) + +libgstosxaudio_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) \ + -Wl,-framework,CoreAudio -Wl,-framework,AudioToolbox \ + $(am__append_1) +libgstosxaudio_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS) --tag=CC +noinst_HEADERS = gstosxaudiosink.h \ + gstosxaudioelement.h \ + gstosxaudioringbuffer.h \ + gstosxaudiosrc.h \ + gstosxcoreaudiocommon.h \ + gstosxcoreaudio.h \ + gstosxcoreaudiohal.c \ + gstosxcoreaudioremoteio.c + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu sys/osxaudio/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu sys/osxaudio/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(plugindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(plugindir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ + } + +uninstall-pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ + done + +clean-pluginLTLIBRARIES: + -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) + @list='$(plugin_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +libgstosxaudio.la: $(libgstosxaudio_la_OBJECTS) $(libgstosxaudio_la_DEPENDENCIES) $(EXTRA_libgstosxaudio_la_DEPENDENCIES) + $(AM_V_CCLD)$(libgstosxaudio_la_LINK) -rpath $(plugindir) $(libgstosxaudio_la_OBJECTS) $(libgstosxaudio_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstosxaudio_la-gstosxaudio.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstosxaudio_la-gstosxaudioelement.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstosxaudio_la-gstosxaudioringbuffer.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstosxaudio_la-gstosxaudiosink.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstosxaudio_la-gstosxaudiosrc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstosxaudio_la-gstosxcoreaudio.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstosxaudio_la-gstosxcoreaudiocommon.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +libgstosxaudio_la-gstosxaudioringbuffer.lo: gstosxaudioringbuffer.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstosxaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstosxaudio_la_CFLAGS) $(CFLAGS) -MT libgstosxaudio_la-gstosxaudioringbuffer.lo -MD -MP -MF $(DEPDIR)/libgstosxaudio_la-gstosxaudioringbuffer.Tpo -c -o libgstosxaudio_la-gstosxaudioringbuffer.lo `test -f 'gstosxaudioringbuffer.c' || echo '$(srcdir)/'`gstosxaudioringbuffer.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstosxaudio_la-gstosxaudioringbuffer.Tpo $(DEPDIR)/libgstosxaudio_la-gstosxaudioringbuffer.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstosxaudioringbuffer.c' object='libgstosxaudio_la-gstosxaudioringbuffer.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstosxaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstosxaudio_la_CFLAGS) $(CFLAGS) -c -o libgstosxaudio_la-gstosxaudioringbuffer.lo `test -f 'gstosxaudioringbuffer.c' || echo '$(srcdir)/'`gstosxaudioringbuffer.c + +libgstosxaudio_la-gstosxaudioelement.lo: gstosxaudioelement.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstosxaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstosxaudio_la_CFLAGS) $(CFLAGS) -MT libgstosxaudio_la-gstosxaudioelement.lo -MD -MP -MF $(DEPDIR)/libgstosxaudio_la-gstosxaudioelement.Tpo -c -o libgstosxaudio_la-gstosxaudioelement.lo `test -f 'gstosxaudioelement.c' || echo '$(srcdir)/'`gstosxaudioelement.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstosxaudio_la-gstosxaudioelement.Tpo $(DEPDIR)/libgstosxaudio_la-gstosxaudioelement.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstosxaudioelement.c' object='libgstosxaudio_la-gstosxaudioelement.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstosxaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstosxaudio_la_CFLAGS) $(CFLAGS) -c -o libgstosxaudio_la-gstosxaudioelement.lo `test -f 'gstosxaudioelement.c' || echo '$(srcdir)/'`gstosxaudioelement.c + +libgstosxaudio_la-gstosxaudiosink.lo: gstosxaudiosink.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstosxaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstosxaudio_la_CFLAGS) $(CFLAGS) -MT libgstosxaudio_la-gstosxaudiosink.lo -MD -MP -MF $(DEPDIR)/libgstosxaudio_la-gstosxaudiosink.Tpo -c -o libgstosxaudio_la-gstosxaudiosink.lo `test -f 'gstosxaudiosink.c' || echo '$(srcdir)/'`gstosxaudiosink.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstosxaudio_la-gstosxaudiosink.Tpo $(DEPDIR)/libgstosxaudio_la-gstosxaudiosink.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstosxaudiosink.c' object='libgstosxaudio_la-gstosxaudiosink.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstosxaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstosxaudio_la_CFLAGS) $(CFLAGS) -c -o libgstosxaudio_la-gstosxaudiosink.lo `test -f 'gstosxaudiosink.c' || echo '$(srcdir)/'`gstosxaudiosink.c + +libgstosxaudio_la-gstosxaudiosrc.lo: gstosxaudiosrc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstosxaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstosxaudio_la_CFLAGS) $(CFLAGS) -MT libgstosxaudio_la-gstosxaudiosrc.lo -MD -MP -MF $(DEPDIR)/libgstosxaudio_la-gstosxaudiosrc.Tpo -c -o libgstosxaudio_la-gstosxaudiosrc.lo `test -f 'gstosxaudiosrc.c' || echo '$(srcdir)/'`gstosxaudiosrc.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstosxaudio_la-gstosxaudiosrc.Tpo $(DEPDIR)/libgstosxaudio_la-gstosxaudiosrc.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstosxaudiosrc.c' object='libgstosxaudio_la-gstosxaudiosrc.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstosxaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstosxaudio_la_CFLAGS) $(CFLAGS) -c -o libgstosxaudio_la-gstosxaudiosrc.lo `test -f 'gstosxaudiosrc.c' || echo '$(srcdir)/'`gstosxaudiosrc.c + +libgstosxaudio_la-gstosxcoreaudiocommon.lo: gstosxcoreaudiocommon.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstosxaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstosxaudio_la_CFLAGS) $(CFLAGS) -MT libgstosxaudio_la-gstosxcoreaudiocommon.lo -MD -MP -MF $(DEPDIR)/libgstosxaudio_la-gstosxcoreaudiocommon.Tpo -c -o libgstosxaudio_la-gstosxcoreaudiocommon.lo `test -f 'gstosxcoreaudiocommon.c' || echo '$(srcdir)/'`gstosxcoreaudiocommon.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstosxaudio_la-gstosxcoreaudiocommon.Tpo $(DEPDIR)/libgstosxaudio_la-gstosxcoreaudiocommon.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstosxcoreaudiocommon.c' object='libgstosxaudio_la-gstosxcoreaudiocommon.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstosxaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstosxaudio_la_CFLAGS) $(CFLAGS) -c -o libgstosxaudio_la-gstosxcoreaudiocommon.lo `test -f 'gstosxcoreaudiocommon.c' || echo '$(srcdir)/'`gstosxcoreaudiocommon.c + +libgstosxaudio_la-gstosxcoreaudio.lo: gstosxcoreaudio.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstosxaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstosxaudio_la_CFLAGS) $(CFLAGS) -MT libgstosxaudio_la-gstosxcoreaudio.lo -MD -MP -MF $(DEPDIR)/libgstosxaudio_la-gstosxcoreaudio.Tpo -c -o libgstosxaudio_la-gstosxcoreaudio.lo `test -f 'gstosxcoreaudio.c' || echo '$(srcdir)/'`gstosxcoreaudio.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstosxaudio_la-gstosxcoreaudio.Tpo $(DEPDIR)/libgstosxaudio_la-gstosxcoreaudio.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstosxcoreaudio.c' object='libgstosxaudio_la-gstosxcoreaudio.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstosxaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstosxaudio_la_CFLAGS) $(CFLAGS) -c -o libgstosxaudio_la-gstosxcoreaudio.lo `test -f 'gstosxcoreaudio.c' || echo '$(srcdir)/'`gstosxcoreaudio.c + +libgstosxaudio_la-gstosxaudio.lo: gstosxaudio.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstosxaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstosxaudio_la_CFLAGS) $(CFLAGS) -MT libgstosxaudio_la-gstosxaudio.lo -MD -MP -MF $(DEPDIR)/libgstosxaudio_la-gstosxaudio.Tpo -c -o libgstosxaudio_la-gstosxaudio.lo `test -f 'gstosxaudio.c' || echo '$(srcdir)/'`gstosxaudio.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstosxaudio_la-gstosxaudio.Tpo $(DEPDIR)/libgstosxaudio_la-gstosxaudio.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstosxaudio.c' object='libgstosxaudio_la-gstosxaudio.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(libgstosxaudio_la_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstosxaudio_la_CFLAGS) $(CFLAGS) -c -o libgstosxaudio_la-gstosxaudio.lo `test -f 'gstosxaudio.c' || echo '$(srcdir)/'`gstosxaudio.c + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(plugindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-pluginLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-pluginLTLIBRARIES + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pluginLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-pluginLTLIBRARIES cscopelist-am ctags \ + ctags-am distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-pluginLTLIBRARIES install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \ + uninstall-pluginLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/sys/osxaudio/gstosxaudio.c b/sys/osxaudio/gstosxaudio.c new file mode 100755 index 0000000..c48b03f --- /dev/null +++ b/sys/osxaudio/gstosxaudio.c @@ -0,0 +1,53 @@ +/* + * GStreamer + * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu> + * Copyright (C) 2007,2008 Pioneers of the Inevitable <songbird@songbirdnest.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * The development of this code was made possible due to the involvement of + * Pioneers of the Inevitable, the creators of the Songbird Music player + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstosxaudioelement.h" +#include "gstosxaudiosink.h" +#include "gstosxaudiosrc.h" + +static gboolean +plugin_init (GstPlugin * plugin) +{ + if (!gst_element_register (plugin, "osxaudiosink", GST_RANK_PRIMARY, + GST_TYPE_OSX_AUDIO_SINK)) { + return FALSE; + } + if (!gst_element_register (plugin, "osxaudiosrc", GST_RANK_PRIMARY, + GST_TYPE_OSX_AUDIO_SRC)) { + return FALSE; + } + + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + osxaudio, + "OSX (Mac OS X) audio support for GStreamer", + plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/sys/osxaudio/gstosxaudioelement.c b/sys/osxaudio/gstosxaudioelement.c new file mode 100755 index 0000000..bec24d1 --- /dev/null +++ b/sys/osxaudio/gstosxaudioelement.c @@ -0,0 +1,92 @@ +/* + * GStreamer + * Copyright (C) 2006 Zaheer Abbas Merali <zaheerabbas at merali dot org> + * Copyright (C) 2007 Pioneers of the Inevitable <songbird@songbirdnest.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * The development of this code was made possible due to the involvement of + * Pioneers of the Inevitable, the creators of the Songbird Music player + * + */ + +#include "gstosxaudioelement.h" +#include <gst/gst.h> + +static void +gst_osx_audio_element_interface_init (GstOsxAudioElementInterface * iface); + +GType +gst_osx_audio_element_get_type (void) +{ + static GType gst_osxaudioelement_type = 0; + + if (!gst_osxaudioelement_type) { + static const GTypeInfo gst_osxaudioelement_info = { + sizeof (GstOsxAudioElementInterface), + (GBaseInitFunc) gst_osx_audio_element_interface_init, + NULL, + NULL, + NULL, + NULL, + 0, + 0, + NULL, + NULL + }; + + gst_osxaudioelement_type = g_type_register_static (G_TYPE_INTERFACE, + "GstOsxAudioElement", &gst_osxaudioelement_info, 0); + } + + return gst_osxaudioelement_type; +} + +static void +gst_osx_audio_element_interface_init (GstOsxAudioElementInterface * iface) +{ + static gboolean initialized = FALSE; + + if (!initialized) { + initialized = TRUE; + } + + /* default virtual functions */ + iface->io_proc = NULL; +} diff --git a/sys/osxaudio/gstosxaudioelement.h b/sys/osxaudio/gstosxaudioelement.h new file mode 100755 index 0000000..3e09dc1 --- /dev/null +++ b/sys/osxaudio/gstosxaudioelement.h @@ -0,0 +1,92 @@ +/* + * GStreamer + * Copyright (C) 2006 Zaheer Abbas Merali <zaheerabbas at merali dot org> + * Copyright (C) 2007 Pioneers of the Inevitable <songbird@songbirdnest.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * The development of this code was made possible due to the involvement of + * Pioneers of the Inevitable, the creators of the Songbird Music player + * + */ + +#ifndef __GST_OSX_AUDIO_ELEMENT_H__ +#define __GST_OSX_AUDIO_ELEMENT_H__ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gst/gst.h> +#ifdef HAVE_IOS +#include <CoreAudio/CoreAudioTypes.h> +#else +#include <CoreAudio/CoreAudio.h> +#endif +#include <AudioUnit/AudioUnit.h> + +G_BEGIN_DECLS + +#define GST_OSX_AUDIO_ELEMENT_TYPE \ + (gst_osx_audio_element_get_type()) +#define GST_OSX_AUDIO_ELEMENT(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_OSX_AUDIO_ELEMENT_TYPE,GstOsxAudioElementInterface)) +#define GST_IS_OSX_AUDIO_ELEMENT(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_OSX_AUDIO_ELEMENT_TYPE)) +#define GST_OSX_AUDIO_ELEMENT_GET_INTERFACE(inst) \ + (G_TYPE_INSTANCE_GET_INTERFACE((inst),GST_OSX_AUDIO_ELEMENT_TYPE,GstOsxAudioElementInterface)) + +typedef struct _GstOsxAudioElementInterface GstOsxAudioElementInterface; + +struct _GstOsxAudioElementInterface +{ + GTypeInterface parent; + + OSStatus (*io_proc) (void * userdata, + AudioUnitRenderActionFlags * ioActionFlags, + const AudioTimeStamp * inTimeStamp, + UInt32 inBusNumber, UInt32 inNumberFrames, + AudioBufferList * bufferList); +}; + +GType gst_osx_audio_element_get_type (void); + +G_END_DECLS + +#endif /* __GST_OSX_AUDIO_ELEMENT_H__ */ diff --git a/sys/osxaudio/gstosxaudioringbuffer.c b/sys/osxaudio/gstosxaudioringbuffer.c new file mode 100755 index 0000000..14faa78 --- /dev/null +++ b/sys/osxaudio/gstosxaudioringbuffer.c @@ -0,0 +1,313 @@ +/* + * GStreamer + * Copyright (C) 2006 Zaheer Abbas Merali <zaheerabbas at merali dot org> + * Copyright (C) 2008 Pioneers of the Inevitable <songbird@songbirdnest.com> + * Copyright (C) 2012 Fluendo S.A. <support@fluendo.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gst/gst.h> +#include <gst/audio/audio-channels.h> +#include "gstosxaudioringbuffer.h" +#include "gstosxaudiosink.h" +#include "gstosxaudiosrc.h" + +#include <unistd.h> /* for getpid() */ + +GST_DEBUG_CATEGORY_STATIC (osx_audio_debug); +#define GST_CAT_DEFAULT osx_audio_debug + +#include "gstosxcoreaudio.h" + +static void gst_osx_audio_ring_buffer_dispose (GObject * object); +static void gst_osx_audio_ring_buffer_finalize (GObject * object); +static gboolean gst_osx_audio_ring_buffer_open_device (GstAudioRingBuffer * + buf); +static gboolean gst_osx_audio_ring_buffer_close_device (GstAudioRingBuffer * + buf); + +static gboolean gst_osx_audio_ring_buffer_acquire (GstAudioRingBuffer * buf, + GstAudioRingBufferSpec * spec); +static gboolean gst_osx_audio_ring_buffer_release (GstAudioRingBuffer * buf); + +static gboolean gst_osx_audio_ring_buffer_start (GstAudioRingBuffer * buf); +static gboolean gst_osx_audio_ring_buffer_pause (GstAudioRingBuffer * buf); +static gboolean gst_osx_audio_ring_buffer_stop (GstAudioRingBuffer * buf); +static guint gst_osx_audio_ring_buffer_delay (GstAudioRingBuffer * buf); +static GstAudioRingBufferClass *ring_parent_class = NULL; + +#define gst_osx_audio_ring_buffer_do_init \ + GST_DEBUG_CATEGORY_INIT (osx_audio_debug, "osxaudio", 0, "OSX Audio Elements"); + +G_DEFINE_TYPE_WITH_CODE (GstOsxAudioRingBuffer, gst_osx_audio_ring_buffer, + GST_TYPE_AUDIO_RING_BUFFER, gst_osx_audio_ring_buffer_do_init); + +static void +gst_osx_audio_ring_buffer_class_init (GstOsxAudioRingBufferClass * klass) +{ + GObjectClass *gobject_class; + GstAudioRingBufferClass *gstringbuffer_class; + + gobject_class = (GObjectClass *) klass; + gstringbuffer_class = (GstAudioRingBufferClass *) klass; + + ring_parent_class = g_type_class_peek_parent (klass); + + gobject_class->dispose = gst_osx_audio_ring_buffer_dispose; + gobject_class->finalize = gst_osx_audio_ring_buffer_finalize; + + gstringbuffer_class->open_device = + GST_DEBUG_FUNCPTR (gst_osx_audio_ring_buffer_open_device); + gstringbuffer_class->close_device = + GST_DEBUG_FUNCPTR (gst_osx_audio_ring_buffer_close_device); + gstringbuffer_class->acquire = + GST_DEBUG_FUNCPTR (gst_osx_audio_ring_buffer_acquire); + gstringbuffer_class->release = + GST_DEBUG_FUNCPTR (gst_osx_audio_ring_buffer_release); + gstringbuffer_class->start = + GST_DEBUG_FUNCPTR (gst_osx_audio_ring_buffer_start); + gstringbuffer_class->pause = + GST_DEBUG_FUNCPTR (gst_osx_audio_ring_buffer_pause); + gstringbuffer_class->resume = + GST_DEBUG_FUNCPTR (gst_osx_audio_ring_buffer_start); + gstringbuffer_class->stop = + GST_DEBUG_FUNCPTR (gst_osx_audio_ring_buffer_stop); + gstringbuffer_class->delay = + GST_DEBUG_FUNCPTR (gst_osx_audio_ring_buffer_delay); + + GST_DEBUG ("osx audio ring buffer class init"); +} + +static void +gst_osx_audio_ring_buffer_init (GstOsxAudioRingBuffer * ringbuffer) +{ + ringbuffer->core_audio = gst_core_audio_new (GST_OBJECT (ringbuffer)); +} + +static void +gst_osx_audio_ring_buffer_dispose (GObject * object) +{ + GstOsxAudioRingBuffer *osxbuf; + + osxbuf = GST_OSX_AUDIO_RING_BUFFER (object); + + if (osxbuf->core_audio) { + g_object_unref (osxbuf->core_audio); + osxbuf->core_audio = NULL; + } + G_OBJECT_CLASS (ring_parent_class)->dispose (object); +} + +static void +gst_osx_audio_ring_buffer_finalize (GObject * object) +{ + G_OBJECT_CLASS (ring_parent_class)->finalize (object); +} + +static gboolean +gst_osx_audio_ring_buffer_open_device (GstAudioRingBuffer * buf) +{ + GstOsxAudioRingBuffer *osxbuf; + + osxbuf = GST_OSX_AUDIO_RING_BUFFER (buf); + + return gst_core_audio_open (osxbuf->core_audio); +} + +static gboolean +gst_osx_audio_ring_buffer_close_device (GstAudioRingBuffer * buf) +{ + GstOsxAudioRingBuffer *osxbuf; + osxbuf = GST_OSX_AUDIO_RING_BUFFER (buf); + + return gst_core_audio_close (osxbuf->core_audio); +} + +static gboolean +gst_osx_audio_ring_buffer_acquire (GstAudioRingBuffer * buf, + GstAudioRingBufferSpec * spec) +{ + gboolean ret = FALSE, is_passthrough = FALSE; + GstOsxAudioRingBuffer *osxbuf; + AudioStreamBasicDescription format; + + osxbuf = GST_OSX_AUDIO_RING_BUFFER (buf); + + if (RINGBUFFER_IS_SPDIF (spec->type)) { + format.mFormatID = kAudioFormat60958AC3; + format.mSampleRate = (double) GST_AUDIO_INFO_RATE (&spec->info); + format.mChannelsPerFrame = 2; + format.mFormatFlags = kAudioFormatFlagIsSignedInteger | + kAudioFormatFlagIsPacked | kAudioFormatFlagIsNonMixable; + format.mBytesPerFrame = 0; + format.mBitsPerChannel = 16; + format.mBytesPerPacket = 6144; + format.mFramesPerPacket = 1536; + format.mReserved = 0; + spec->segsize = 6144; + spec->segtotal = 10; + is_passthrough = TRUE; + } else { + int width, depth; + /* Fill out the audio description we're going to be using */ + format.mFormatID = kAudioFormatLinearPCM; + format.mSampleRate = (double) GST_AUDIO_INFO_RATE (&spec->info); + format.mChannelsPerFrame = GST_AUDIO_INFO_CHANNELS (&spec->info); + if (GST_AUDIO_INFO_IS_FLOAT (&spec->info)) { + format.mFormatFlags = kAudioFormatFlagsNativeFloatPacked; + width = depth = GST_AUDIO_INFO_WIDTH (&spec->info); + } else { + format.mFormatFlags = kAudioFormatFlagIsSignedInteger; + width = GST_AUDIO_INFO_WIDTH (&spec->info); + depth = GST_AUDIO_INFO_DEPTH (&spec->info); + if (width == depth) { + format.mFormatFlags |= kAudioFormatFlagIsPacked; + } else { + format.mFormatFlags |= kAudioFormatFlagIsAlignedHigh; + } + if (GST_AUDIO_INFO_IS_BIG_ENDIAN (&spec->info)) { + format.mFormatFlags |= kAudioFormatFlagIsBigEndian; + } + } + format.mBytesPerFrame = GST_AUDIO_INFO_BPF (&spec->info); + format.mBitsPerChannel = depth; + format.mBytesPerPacket = GST_AUDIO_INFO_BPF (&spec->info); + format.mFramesPerPacket = 1; + format.mReserved = 0; + spec->segsize = + (spec->latency_time * GST_AUDIO_INFO_RATE (&spec->info) / + G_USEC_PER_SEC) * GST_AUDIO_INFO_BPF (&spec->info); + spec->segtotal = spec->buffer_time / spec->latency_time; + is_passthrough = FALSE; + } + + GST_DEBUG_OBJECT (osxbuf, "Format: " CORE_AUDIO_FORMAT, + CORE_AUDIO_FORMAT_ARGS (format)); + + if (GST_IS_OSX_AUDIO_SINK (GST_OBJECT_PARENT (buf))) { + gst_audio_ring_buffer_set_channel_positions (buf, + GST_OSX_AUDIO_SINK (GST_OBJECT_PARENT (buf))->channel_positions); + } + + buf->size = spec->segtotal * spec->segsize; + buf->memory = g_malloc0 (buf->size); + + ret = gst_core_audio_initialize (osxbuf->core_audio, format, spec->caps, + is_passthrough); + + if (!ret) { + g_free (buf->memory); + buf->memory = NULL; + buf->size = 0; + } + + osxbuf->segoffset = 0; + + return ret; +} + +static gboolean +gst_osx_audio_ring_buffer_release (GstAudioRingBuffer * buf) +{ + GstOsxAudioRingBuffer *osxbuf; + + osxbuf = GST_OSX_AUDIO_RING_BUFFER (buf); + + gst_core_audio_unitialize (osxbuf->core_audio); + + g_free (buf->memory); + buf->memory = NULL; + buf->size = 0; + + return TRUE; +} + +static gboolean +gst_osx_audio_ring_buffer_start (GstAudioRingBuffer * buf) +{ + GstOsxAudioRingBuffer *osxbuf; + + osxbuf = GST_OSX_AUDIO_RING_BUFFER (buf); + + return gst_core_audio_start_processing (osxbuf->core_audio); +} + +static gboolean +gst_osx_audio_ring_buffer_pause (GstAudioRingBuffer * buf) +{ + GstOsxAudioRingBuffer *osxbuf = GST_OSX_AUDIO_RING_BUFFER (buf); + + return gst_core_audio_pause_processing (osxbuf->core_audio); +} + + +static gboolean +gst_osx_audio_ring_buffer_stop (GstAudioRingBuffer * buf) +{ + GstOsxAudioRingBuffer *osxbuf; + + osxbuf = GST_OSX_AUDIO_RING_BUFFER (buf); + + gst_core_audio_stop_processing (osxbuf->core_audio); + + return TRUE; +} + +static guint +gst_osx_audio_ring_buffer_delay (GstAudioRingBuffer * buf) +{ + GstOsxAudioRingBuffer *osxbuf; + double latency; + guint samples; + + osxbuf = GST_OSX_AUDIO_RING_BUFFER (buf); + + if (!gst_core_audio_get_samples_and_latency (osxbuf->core_audio, + GST_AUDIO_INFO_RATE (&buf->spec.info), &samples, &latency)) { + return 0; + } + GST_DEBUG_OBJECT (buf, "Got latency: %f seconds -> %d samples", + latency, samples); + return samples; +} diff --git a/sys/osxaudio/gstosxaudioringbuffer.h b/sys/osxaudio/gstosxaudioringbuffer.h new file mode 100755 index 0000000..5054fd3 --- /dev/null +++ b/sys/osxaudio/gstosxaudioringbuffer.h @@ -0,0 +1,98 @@ +/* + * GStreamer + * Copyright (C) 2006 Zaheer Abbas Merali <zaheerabbas at merali dot org> + * Copyright (C) 2012 Fluendo S.A. <support@fluendo.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_OSX_RING_BUFFER_H__ +#define __GST_OSX_RING_BUFFER_H__ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gst/gst.h> +#include <gst/audio/audio.h> +#include <gst/audio/gstaudioringbuffer.h> +#include <gstosxcoreaudio.h> + + +G_BEGIN_DECLS + +#define GST_TYPE_OSX_AUDIO_RING_BUFFER \ + (gst_osx_audio_ring_buffer_get_type()) +#define GST_OSX_AUDIO_RING_BUFFER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSX_AUDIO_RING_BUFFER,GstOsxAudioRingBuffer)) +#define GST_OSX_AUDIO_RING_BUFFER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSX_AUDIO_RING_BUFFER,GstOsxAudioRingBufferClass)) +#define GST_OSX_AUDIO_RING_BUFFER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_OSX_AUDIO_RING_BUFFER,GstOsxAudioRingBufferClass)) +#define GST_IS_OSX_AUDIO_RING_BUFFER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OSX_AUDIO_RING_BUFFER)) +#define GST_IS_OSX_AUDIO_RING_BUFFER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OSX_AUDIO_RING_BUFFER)) + +#define RINGBUFFER_IS_SPDIF(t) ((t) == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_AC3 || (t) == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_DTS) + +typedef struct _GstOsxAudioRingBuffer GstOsxAudioRingBuffer; +typedef struct _GstOsxAudioRingBufferClass GstOsxAudioRingBufferClass; + +struct _GstOsxAudioRingBuffer +{ + GstAudioRingBuffer object; + + GstCoreAudio *core_audio; + + guint buffer_len; + guint segoffset; +}; + +struct _GstOsxAudioRingBufferClass +{ + GstAudioRingBufferClass parent_class; +}; + +GType gst_osx_audio_ring_buffer_get_type (void); + +G_END_DECLS + +#endif /* __GST_OSX_AUDIO_RING_BUFFER_H__ */ + diff --git a/sys/osxaudio/gstosxaudiosink.c b/sys/osxaudio/gstosxaudiosink.c new file mode 100755 index 0000000..0479ce1 --- /dev/null +++ b/sys/osxaudio/gstosxaudiosink.c @@ -0,0 +1,656 @@ +/* + * GStreamer + * Copyright (C) 2005,2006 Zaheer Abbas Merali <zaheerabbas at merali dot org> + * Copyright (C) 2007,2008 Pioneers of the Inevitable <songbird@songbirdnest.com> + * Copyright (C) 2012 Fluendo S.A. <support@fluendo.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * The development of this code was made possible due to the involvement of + * Pioneers of the Inevitable, the creators of the Songbird Music player + * + */ + +/** + * SECTION:element-osxaudiosink + * + * This element renders raw audio samples using the CoreAudio api. + * + * <refsect2> + * <title>Example pipelines</title> + * |[ + * gst-launch-1.0 filesrc location=sine.ogg ! oggdemux ! vorbisdec ! audioconvert ! audioresample ! osxaudiosink + * ]| Play an Ogg/Vorbis file. + * </refsect2> + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gst/gst.h> +#include <gst/audio/audio.h> +#include <gst/audio/audio-channels.h> +#include <gst/audio/gstaudioiec61937.h> + +#include "gstosxaudiosink.h" +#include "gstosxaudioelement.h" + +GST_DEBUG_CATEGORY_STATIC (osx_audiosink_debug); +#define GST_CAT_DEFAULT osx_audiosink_debug + +#include "gstosxcoreaudio.h" + +/* Filter signals and args */ +enum +{ + /* FILL ME */ + LAST_SIGNAL +}; + +enum +{ + ARG_0, + ARG_DEVICE, + ARG_VOLUME +}; + +#define DEFAULT_VOLUME 1.0 + +#if (G_BYTE_ORDER == G_LITTLE_ENDIAN) +# define FORMATS "{ S32LE, S24LE, S16LE, U8 }" +#else +# define FORMATS "{ S32BE, S24BE, S16BE, U8 }" +#endif + +static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("audio/x-raw, " + "format = (string) " FORMATS ", " + "layout = (string) interleaved, " + "rate = (int) [1, MAX], " + "channels = (int) [1, 9];" + "audio/x-ac3, framed = (boolean) true;" + "audio/x-dts, framed = (boolean) true") + ); + +static void gst_osx_audio_sink_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_osx_audio_sink_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static gboolean gst_osx_audio_sink_query (GstBaseSink * base, GstQuery * query); + +static gboolean gst_osx_audio_sink_stop (GstBaseSink * base); +static GstCaps *gst_osx_audio_sink_getcaps (GstBaseSink * base, + GstCaps * filter); +static gboolean gst_osx_audio_sink_acceptcaps (GstOsxAudioSink * sink, + GstCaps * caps); + +static GstBuffer *gst_osx_audio_sink_sink_payload (GstAudioBaseSink * sink, + GstBuffer * buf); +static GstAudioRingBuffer + * gst_osx_audio_sink_create_ringbuffer (GstAudioBaseSink * sink); +static void gst_osx_audio_sink_osxelement_init (gpointer g_iface, + gpointer iface_data); +static gboolean gst_osx_audio_sink_select_device (GstOsxAudioSink * osxsink); +static void gst_osx_audio_sink_set_volume (GstOsxAudioSink * sink); + +static OSStatus gst_osx_audio_sink_io_proc (GstOsxAudioRingBuffer * buf, + AudioUnitRenderActionFlags * ioActionFlags, + const AudioTimeStamp * inTimeStamp, + UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList * bufferList); + +static void +gst_osx_audio_sink_do_init (GType type) +{ + static const GInterfaceInfo osxelement_info = { + gst_osx_audio_sink_osxelement_init, + NULL, + NULL + }; + + GST_DEBUG_CATEGORY_INIT (osx_audiosink_debug, "osxaudiosink", 0, + "OSX Audio Sink"); + gst_core_audio_init_debug (); + GST_DEBUG ("Adding static interface"); + g_type_add_interface_static (type, GST_OSX_AUDIO_ELEMENT_TYPE, + &osxelement_info); +} + +#define gst_osx_audio_sink_parent_class parent_class +G_DEFINE_TYPE_WITH_CODE (GstOsxAudioSink, gst_osx_audio_sink, + GST_TYPE_AUDIO_BASE_SINK, gst_osx_audio_sink_do_init (g_define_type_id)); + +static void +gst_osx_audio_sink_class_init (GstOsxAudioSinkClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + GstBaseSinkClass *gstbasesink_class; + GstAudioBaseSinkClass *gstaudiobasesink_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + gstbasesink_class = (GstBaseSinkClass *) klass; + gstaudiobasesink_class = (GstAudioBaseSinkClass *) klass; + + parent_class = g_type_class_peek_parent (klass); + + gobject_class->set_property = gst_osx_audio_sink_set_property; + gobject_class->get_property = gst_osx_audio_sink_get_property; + +#ifndef HAVE_IOS + g_object_class_install_property (gobject_class, ARG_DEVICE, + g_param_spec_int ("device", "Device ID", "Device ID of output device", + 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); +#endif + + gstbasesink_class->query = GST_DEBUG_FUNCPTR (gst_osx_audio_sink_query); + + g_object_class_install_property (gobject_class, ARG_VOLUME, + g_param_spec_double ("volume", "Volume", "Volume of this stream", + 0, 1.0, 1.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_osx_audio_sink_getcaps); + gstbasesink_class->stop = GST_DEBUG_FUNCPTR (gst_osx_audio_sink_stop); + + gstaudiobasesink_class->create_ringbuffer = + GST_DEBUG_FUNCPTR (gst_osx_audio_sink_create_ringbuffer); + gstaudiobasesink_class->payload = + GST_DEBUG_FUNCPTR (gst_osx_audio_sink_sink_payload); + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&sink_factory)); + + gst_element_class_set_static_metadata (gstelement_class, "Audio Sink (OSX)", + "Sink/Audio", + "Output to a sound card in OS X", + "Zaheer Abbas Merali <zaheerabbas at merali dot org>"); +} + +static void +gst_osx_audio_sink_init (GstOsxAudioSink * sink) +{ + gint i; + + GST_DEBUG ("Initialising object"); + + sink->device_id = kAudioDeviceUnknown; + sink->cached_caps = NULL; + + sink->volume = DEFAULT_VOLUME; + + sink->channels = 0; + for (i = 0; i < GST_OSX_AUDIO_MAX_CHANNEL; i++) { + sink->channel_positions[i] = GST_AUDIO_CHANNEL_POSITION_INVALID; + } +} + +static void +gst_osx_audio_sink_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstOsxAudioSink *sink = GST_OSX_AUDIO_SINK (object); + + switch (prop_id) { +#ifndef HAVE_IOS + case ARG_DEVICE: + sink->device_id = g_value_get_int (value); + break; +#endif + case ARG_VOLUME: + sink->volume = g_value_get_double (value); + gst_osx_audio_sink_set_volume (sink); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_osx_audio_sink_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstOsxAudioSink *sink = GST_OSX_AUDIO_SINK (object); + switch (prop_id) { +#ifndef HAVE_IOS + case ARG_DEVICE: + g_value_set_int (value, sink->device_id); + break; +#endif + case ARG_VOLUME: + g_value_set_double (value, sink->volume); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static gboolean +gst_osx_audio_sink_query (GstBaseSink * base, GstQuery * query) +{ + GstOsxAudioSink *sink = GST_OSX_AUDIO_SINK (base); + gboolean ret = FALSE; + + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_ACCEPT_CAPS: + { + GstCaps *caps = NULL; + + gst_query_parse_accept_caps (query, &caps); + ret = gst_osx_audio_sink_acceptcaps (sink, caps); + gst_query_set_accept_caps_result (query, ret); + ret = TRUE; + break; + } + default: + ret = GST_BASE_SINK_CLASS (parent_class)->query (base, query); + break; + } + return ret; +} + +static gboolean +gst_osx_audio_sink_stop (GstBaseSink * base) +{ + GstOsxAudioSink *sink = GST_OSX_AUDIO_SINK (base); + + if (sink->cached_caps) { + gst_caps_unref (sink->cached_caps); + sink->cached_caps = NULL; + } + + return GST_CALL_PARENT_WITH_DEFAULT (GST_BASE_SINK_CLASS, stop, (base), TRUE); +} + +static GstCaps * +gst_osx_audio_sink_getcaps (GstBaseSink * base, GstCaps * filter) +{ + GstOsxAudioSink *sink = GST_OSX_AUDIO_SINK (base); + gchar *caps_string = NULL; + + if (sink->cached_caps) { + caps_string = gst_caps_to_string (sink->cached_caps); + GST_DEBUG_OBJECT (sink, "using cached caps: %s", caps_string); + g_free (caps_string); + if (filter) + return gst_caps_intersect_full (sink->cached_caps, filter, + GST_CAPS_INTERSECT_FIRST); + return gst_caps_ref (sink->cached_caps); + } + + GST_DEBUG_OBJECT (sink, "using template caps"); + return NULL; +} + +static gboolean +gst_osx_audio_sink_acceptcaps (GstOsxAudioSink * sink, GstCaps * caps) +{ + GstCaps *pad_caps; + GstStructure *st; + gboolean ret = FALSE; + GstAudioRingBufferSpec spec = { 0 }; + gchar *caps_string = NULL; + + caps_string = gst_caps_to_string (caps); + GST_DEBUG_OBJECT (sink, "acceptcaps called with %s", caps_string); + g_free (caps_string); + + pad_caps = gst_pad_query_caps (GST_BASE_SINK_PAD (sink), caps); + if (pad_caps) { + gboolean cret = gst_caps_can_intersect (pad_caps, caps); + gst_caps_unref (pad_caps); + if (!cret) + goto done; + } + + /* If we've not got fixed caps, creating a stream might fail, + * so let's just return from here with default acceptcaps + * behaviour */ + if (!gst_caps_is_fixed (caps)) + goto done; + + /* parse helper expects this set, so avoid nasty warning + * will be set properly later on anyway */ + spec.latency_time = GST_SECOND; + if (!gst_audio_ring_buffer_parse_caps (&spec, caps)) + goto done; + + /* Make sure input is framed and can be payloaded */ + switch (spec.type) { + case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_AC3: + { + gboolean framed = FALSE; + + st = gst_caps_get_structure (caps, 0); + + gst_structure_get_boolean (st, "framed", &framed); + if (!framed || gst_audio_iec61937_frame_size (&spec) <= 0) + goto done; + break; + } + case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_DTS: + { + gboolean parsed = FALSE; + + st = gst_caps_get_structure (caps, 0); + + gst_structure_get_boolean (st, "parsed", &parsed); + if (!parsed || gst_audio_iec61937_frame_size (&spec) <= 0) + goto done; + break; + } + default: + break; + } + ret = TRUE; + +done: + return ret; +} + +static GstBuffer * +gst_osx_audio_sink_sink_payload (GstAudioBaseSink * sink, GstBuffer * buf) +{ + if (RINGBUFFER_IS_SPDIF (sink->ringbuffer->spec.type)) { + gint framesize = gst_audio_iec61937_frame_size (&sink->ringbuffer->spec); + GstBuffer *out; + GstMapInfo inmap, outmap; + gboolean res; + + if (framesize <= 0) + return NULL; + + out = gst_buffer_new_and_alloc (framesize); + + gst_buffer_map (buf, &inmap, GST_MAP_READ); + gst_buffer_map (out, &outmap, GST_MAP_WRITE); + + /* FIXME: the endianness needs to be queried and then set */ + res = gst_audio_iec61937_payload (inmap.data, inmap.size, + outmap.data, outmap.size, &sink->ringbuffer->spec, G_BIG_ENDIAN); + + gst_buffer_unmap (buf, &inmap); + gst_buffer_unmap (out, &outmap); + + if (!res) { + gst_buffer_unref (out); + return NULL; + } + + gst_buffer_copy_into (out, buf, GST_BUFFER_COPY_METADATA, 0, -1); + return out; + + } else { + return gst_buffer_ref (buf); + } +} + +static GstAudioRingBuffer * +gst_osx_audio_sink_create_ringbuffer (GstAudioBaseSink * sink) +{ + GstOsxAudioSink *osxsink; + GstOsxAudioRingBuffer *ringbuffer; + + osxsink = GST_OSX_AUDIO_SINK (sink); + + if (!gst_osx_audio_sink_select_device (osxsink)) { + GST_ERROR_OBJECT (sink, "Could not select device"); + return NULL; + } + + GST_DEBUG_OBJECT (sink, "Creating ringbuffer"); + ringbuffer = g_object_new (GST_TYPE_OSX_AUDIO_RING_BUFFER, NULL); + GST_DEBUG_OBJECT (sink, "osx sink %p element %p ioproc %p", osxsink, + GST_OSX_AUDIO_ELEMENT_GET_INTERFACE (osxsink), + (void *) gst_osx_audio_sink_io_proc); + + gst_osx_audio_sink_set_volume (osxsink); + + ringbuffer->core_audio->element = + GST_OSX_AUDIO_ELEMENT_GET_INTERFACE (osxsink); + ringbuffer->core_audio->device_id = osxsink->device_id; + ringbuffer->core_audio->is_src = FALSE; + + return GST_AUDIO_RING_BUFFER (ringbuffer); +} + +/* HALOutput AudioUnit will request fairly arbitrarily-sized chunks + * of data, not of a fixed size. So, we keep track of where in + * the current ringbuffer segment we are, and only advance the segment + * once we've read the whole thing */ +static OSStatus +gst_osx_audio_sink_io_proc (GstOsxAudioRingBuffer * buf, + AudioUnitRenderActionFlags * ioActionFlags, + const AudioTimeStamp * inTimeStamp, + UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList * bufferList) +{ + guint8 *readptr; + gint readseg; + gint len; + gint stream_idx = buf->core_audio->stream_idx; + gint remaining = bufferList->mBuffers[stream_idx].mDataByteSize; + gint offset = 0; + + while (remaining) { + if (!gst_audio_ring_buffer_prepare_read (GST_AUDIO_RING_BUFFER (buf), + &readseg, &readptr, &len)) + return 0; + + len -= buf->segoffset; + + if (len > remaining) + len = remaining; + + memcpy ((char *) bufferList->mBuffers[stream_idx].mData + offset, + readptr + buf->segoffset, len); + + buf->segoffset += len; + offset += len; + remaining -= len; + + if ((gint) buf->segoffset == GST_AUDIO_RING_BUFFER (buf)->spec.segsize) { + /* clear written samples */ + gst_audio_ring_buffer_clear (GST_AUDIO_RING_BUFFER (buf), readseg); + + /* we wrote one segment */ + gst_audio_ring_buffer_advance (GST_AUDIO_RING_BUFFER (buf), 1); + + buf->segoffset = 0; + } + } + return 0; +} + +static void +gst_osx_audio_sink_osxelement_init (gpointer g_iface, gpointer iface_data) +{ + GstOsxAudioElementInterface *iface = (GstOsxAudioElementInterface *) g_iface; + + iface->io_proc = (AURenderCallback) gst_osx_audio_sink_io_proc; +} + +static void +gst_osx_audio_sink_set_volume (GstOsxAudioSink * sink) +{ + GstOsxAudioRingBuffer *osxbuf; + + osxbuf = GST_OSX_AUDIO_RING_BUFFER (GST_AUDIO_BASE_SINK (sink)->ringbuffer); + if (!osxbuf) + return; + + gst_core_audio_set_volume (osxbuf->core_audio, sink->volume); +} + +static gboolean +gst_osx_audio_sink_allowed_caps (GstOsxAudioSink * osxsink) +{ + gint i, channels; + gboolean spdif_allowed; + AudioChannelLayout *layout; + GstElementClass *element_class; + GstPadTemplate *pad_template; + GstCaps *caps, *in_caps; + guint64 channel_mask = 0; + GstAudioChannelPosition *pos = osxsink->channel_positions; + + /* First collect info about the HW capabilites and preferences */ + spdif_allowed = + gst_core_audio_audio_device_is_spdif_avail (osxsink->device_id); + layout = gst_core_audio_audio_device_get_channel_layout (osxsink->device_id); + + GST_DEBUG_OBJECT (osxsink, "Selected device ID: %u SPDIF allowed: %d", + (unsigned) osxsink->device_id, spdif_allowed); + + if (layout) { + channels = MIN (layout->mNumberChannelDescriptions, + GST_OSX_AUDIO_MAX_CHANNEL); + } else { + GST_WARNING_OBJECT (osxsink, "This driver does not support " + "kAudioDevicePropertyPreferredChannelLayout."); + channels = 2; + } + + switch (channels) { + case 0: + pos[0] = GST_AUDIO_CHANNEL_POSITION_NONE; + break; + case 1: + pos[0] = GST_AUDIO_CHANNEL_POSITION_MONO; + break; + case 2: + pos[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT; + pos[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT; + channel_mask |= GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_LEFT); + channel_mask |= GST_AUDIO_CHANNEL_POSITION_MASK (FRONT_RIGHT); + break; + default: + channels = MIN (layout->mNumberChannelDescriptions, + GST_OSX_AUDIO_MAX_CHANNEL); + for (i = 0; i < channels; i++) { + switch (layout->mChannelDescriptions[i].mChannelLabel) { + case kAudioChannelLabel_Left: + pos[i] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT; + break; + case kAudioChannelLabel_Right: + pos[i] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT; + break; + case kAudioChannelLabel_Center: + pos[i] = GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER; + break; + case kAudioChannelLabel_LFEScreen: + pos[i] = GST_AUDIO_CHANNEL_POSITION_LFE1; + break; + case kAudioChannelLabel_LeftSurround: + pos[i] = GST_AUDIO_CHANNEL_POSITION_REAR_LEFT; + break; + case kAudioChannelLabel_RightSurround: + pos[i] = GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT; + break; + case kAudioChannelLabel_RearSurroundLeft: + pos[i] = GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT; + break; + case kAudioChannelLabel_RearSurroundRight: + pos[i] = GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT; + break; + case kAudioChannelLabel_CenterSurround: + pos[i] = GST_AUDIO_CHANNEL_POSITION_REAR_CENTER; + break; + default: + GST_WARNING_OBJECT (osxsink, "unrecognized channel: %d", + (int) layout->mChannelDescriptions[i].mChannelLabel); + channel_mask = 0; + channels = 2; + break; + } + } + } + g_free (layout); + + /* Recover the template caps */ + element_class = GST_ELEMENT_GET_CLASS (osxsink); + pad_template = gst_element_class_get_pad_template (element_class, "sink"); + in_caps = gst_pad_template_get_caps (pad_template); + + /* Create the allowed subset */ + caps = gst_caps_new_empty (); + for (i = 0; i < gst_caps_get_size (in_caps); i++) { + GstStructure *in_s, *out_s; + + in_s = gst_caps_get_structure (in_caps, i); + + if (gst_structure_has_name (in_s, "audio/x-ac3") || + gst_structure_has_name (in_s, "audio/x-dts")) { + if (spdif_allowed) { + gst_caps_append_structure (caps, gst_structure_copy (in_s)); + } + } + gst_audio_channel_positions_to_mask (pos, channels, false, &channel_mask); + out_s = gst_structure_copy (in_s); + gst_structure_remove_fields (out_s, "channels", "channel-mask", NULL); + gst_structure_set (out_s, "channels", G_TYPE_INT, channels, + "channel-mask", GST_TYPE_BITMASK, channel_mask, NULL); + gst_caps_append_structure (caps, out_s); + } + + if (osxsink->cached_caps) { + gst_caps_unref (osxsink->cached_caps); + } + + osxsink->cached_caps = caps; + osxsink->channels = channels; + + return TRUE; +} + +static gboolean +gst_osx_audio_sink_select_device (GstOsxAudioSink * osxsink) +{ + gboolean res = FALSE; + + if (!gst_core_audio_select_device (&osxsink->device_id)) + return FALSE; + res = gst_osx_audio_sink_allowed_caps (osxsink); + + return res; +} diff --git a/sys/osxaudio/gstosxaudiosink.h b/sys/osxaudio/gstosxaudiosink.h new file mode 100755 index 0000000..84949b7 --- /dev/null +++ b/sys/osxaudio/gstosxaudiosink.h @@ -0,0 +1,98 @@ +/* + * GStreamer + * Copyright (C) 2005-2006 Zaheer Abbas Merali <zaheerabbas at merali dot org> + * Copyright (C) 2007 Pioneers of the Inevitable <songbird@songbirdnest.com> + * Copyright (C) 2012 Fluendo S.A. <support@fluendo.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + * The development of this code was made possible due to the involvement of + * Pioneers of the Inevitable, the creators of the Songbird Music player + * + */ + +#ifndef __GST_OSXAUDIOSINK_H__ +#define __GST_OSXAUDIOSINK_H__ + +#include <gst/gst.h> +#include <gst/audio/audio.h> +#include <gst/audio/gstaudiobasesink.h> +#include "gstosxaudioringbuffer.h" + +G_BEGIN_DECLS + +#define GST_TYPE_OSX_AUDIO_SINK \ + (gst_osx_audio_sink_get_type()) +#define GST_OSX_AUDIO_SINK(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSX_AUDIO_SINK,GstOsxAudioSink)) +#define GST_OSX_AUDIO_SINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSX_AUDIO_SINK,GstOsxAudioSinkClass)) +#define GST_IS_OSX_AUDIO_SINK(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OSX_AUDIO_SINK)) + +#define GST_OSX_AUDIO_MAX_CHANNEL (9) + +typedef struct _GstOsxAudioSink GstOsxAudioSink; +typedef struct _GstOsxAudioSinkClass GstOsxAudioSinkClass; + +struct _GstOsxAudioSink +{ + GstAudioBaseSink sink; + + AudioDeviceID device_id; + + AudioUnit audiounit; + double volume; + GstCaps *cached_caps; + + guint channels; + GstAudioChannelPosition channel_positions[GST_OSX_AUDIO_MAX_CHANNEL]; +}; + +struct _GstOsxAudioSinkClass +{ + GstAudioBaseSinkClass parent_class; +}; + +GType gst_osx_audio_sink_get_type (void); + +G_END_DECLS + +#endif /* __GST_OSXAUDIOSINK_H__ */ + diff --git a/sys/osxaudio/gstosxaudiosrc.c b/sys/osxaudio/gstosxaudiosrc.c new file mode 100755 index 0000000..fa5da16 --- /dev/null +++ b/sys/osxaudio/gstosxaudiosrc.c @@ -0,0 +1,334 @@ +/* + * GStreamer + * Copyright (C) 2005,2006 Zaheer Abbas Merali <zaheerabbas at merali dot org> + * Copyright (C) 2008 Pioneers of the Inevitable <songbird@songbirdnest.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/** + * SECTION:element-osxaudiosrc + * + * This element captures raw audio samples using the CoreAudio api. + * + * <refsect2> + * <title>Example launch line</title> + * |[ + * gst-launch-1.0 osxaudiosrc ! wavenc ! filesink location=audio.wav + * ]| + * </refsect2> + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gst/gst.h> +#include "gstosxaudiosrc.h" +#include "gstosxaudioelement.h" + +GST_DEBUG_CATEGORY_STATIC (osx_audiosrc_debug); +#define GST_CAT_DEFAULT osx_audiosrc_debug + +/* Filter signals and args */ +enum +{ + /* FILL ME */ + LAST_SIGNAL +}; + +enum +{ + ARG_0, + ARG_DEVICE +}; + +#if (G_BYTE_ORDER == G_LITTLE_ENDIAN) +# define FORMATS "{ S32LE }" +#else +# define FORMATS "{ S32BE }" +#endif + +static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("audio/x-raw, " + "format = (string) " FORMATS ", " + "layout = (string) interleaved, " + "rate = (int) [1, MAX], " "channels = (int) [1, MAX]") + ); + +static void gst_osx_audio_src_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_osx_audio_src_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static GstCaps *gst_osx_audio_src_get_caps (GstBaseSrc * src, GstCaps * filter); + +static GstAudioRingBuffer *gst_osx_audio_src_create_ringbuffer (GstAudioBaseSrc + * src); +static void gst_osx_audio_src_osxelement_init (gpointer g_iface, + gpointer iface_data); +static OSStatus gst_osx_audio_src_io_proc (GstOsxAudioRingBuffer * buf, + AudioUnitRenderActionFlags * ioActionFlags, + const AudioTimeStamp * inTimeStamp, UInt32 inBusNumber, + UInt32 inNumberFrames, AudioBufferList * bufferList); +static void gst_osx_audio_src_select_device (GstOsxAudioSrc * osxsrc); + +static void +gst_osx_audio_src_do_init (GType type) +{ + static const GInterfaceInfo osxelement_info = { + gst_osx_audio_src_osxelement_init, + NULL, + NULL + }; + + GST_DEBUG_CATEGORY_INIT (osx_audiosrc_debug, "osxaudiosrc", 0, + "OSX Audio Src"); + GST_DEBUG ("Adding static interface"); + g_type_add_interface_static (type, GST_OSX_AUDIO_ELEMENT_TYPE, + &osxelement_info); +} + +G_DEFINE_TYPE_WITH_CODE (GstOsxAudioSrc, gst_osx_audio_src, + GST_TYPE_AUDIO_BASE_SRC, gst_osx_audio_src_do_init (g_define_type_id)); + +static void +gst_osx_audio_src_class_init (GstOsxAudioSrcClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + GstBaseSrcClass *gstbasesrc_class; + GstAudioBaseSrcClass *gstaudiobasesrc_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + gstbasesrc_class = (GstBaseSrcClass *) klass; + gstaudiobasesrc_class = (GstAudioBaseSrcClass *) klass; + + gobject_class->set_property = gst_osx_audio_src_set_property; + gobject_class->get_property = gst_osx_audio_src_get_property; + + gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_osx_audio_src_get_caps); + + g_object_class_install_property (gobject_class, ARG_DEVICE, + g_param_spec_int ("device", "Device ID", "Device ID of input device", + 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + gstaudiobasesrc_class->create_ringbuffer = + GST_DEBUG_FUNCPTR (gst_osx_audio_src_create_ringbuffer); + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&src_factory)); + + gst_element_class_set_static_metadata (gstelement_class, "Audio Source (OSX)", + "Source/Audio", + "Input from a sound card in OS X", + "Zaheer Abbas Merali <zaheerabbas at merali dot org>"); +} + +static void +gst_osx_audio_src_init (GstOsxAudioSrc * src) +{ + gst_base_src_set_live (GST_BASE_SRC (src), TRUE); + + src->device_id = kAudioDeviceUnknown; + src->deviceChannels = -1; +} + +static void +gst_osx_audio_src_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstOsxAudioSrc *src = GST_OSX_AUDIO_SRC (object); + + switch (prop_id) { + case ARG_DEVICE: + src->device_id = g_value_get_int (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_osx_audio_src_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstOsxAudioSrc *src = GST_OSX_AUDIO_SRC (object); + + switch (prop_id) { + case ARG_DEVICE: + g_value_set_int (value, src->device_id); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GstCaps * +gst_osx_audio_src_get_caps (GstBaseSrc * src, GstCaps * filter) +{ + GstElementClass *gstelement_class; + GstOsxAudioSrc *osxsrc; + GstPadTemplate *pad_template; + GstCaps *caps; + gint min, max; + + gstelement_class = GST_ELEMENT_GET_CLASS (src); + osxsrc = GST_OSX_AUDIO_SRC (src); + + if (osxsrc->deviceChannels == -1) { + /* -1 means we don't know the number of channels yet. for now, return + * template caps. + */ + return NULL; + } + + max = osxsrc->deviceChannels; + if (max < 1) + max = 1; /* 0 channels means 1 channel? */ + + min = MIN (1, max); + + pad_template = gst_element_class_get_pad_template (gstelement_class, "src"); + g_return_val_if_fail (pad_template != NULL, NULL); + + caps = gst_caps_copy (gst_pad_template_get_caps (pad_template)); + + if (min == max) { + gst_caps_set_simple (caps, "channels", G_TYPE_INT, max, NULL); + } else { + gst_caps_set_simple (caps, "channels", GST_TYPE_INT_RANGE, min, max, NULL); + } + + return caps; +} + +static GstAudioRingBuffer * +gst_osx_audio_src_create_ringbuffer (GstAudioBaseSrc * src) +{ + GstOsxAudioSrc *osxsrc; + GstOsxAudioRingBuffer *ringbuffer; + + osxsrc = GST_OSX_AUDIO_SRC (src); + + gst_osx_audio_src_select_device (osxsrc); + + GST_DEBUG ("Creating ringbuffer"); + ringbuffer = g_object_new (GST_TYPE_OSX_AUDIO_RING_BUFFER, NULL); + GST_DEBUG ("osx src 0x%p element 0x%p ioproc 0x%p", osxsrc, + GST_OSX_AUDIO_ELEMENT_GET_INTERFACE (osxsrc), + (void *) gst_osx_audio_src_io_proc); + + ringbuffer->core_audio->element = + GST_OSX_AUDIO_ELEMENT_GET_INTERFACE (osxsrc); + ringbuffer->core_audio->is_src = TRUE; + ringbuffer->core_audio->device_id = osxsrc->device_id; + + return GST_AUDIO_RING_BUFFER (ringbuffer); +} + +static OSStatus +gst_osx_audio_src_io_proc (GstOsxAudioRingBuffer * buf, + AudioUnitRenderActionFlags * ioActionFlags, + const AudioTimeStamp * inTimeStamp, + UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList * bufferList) +{ + OSStatus status; + guint8 *writeptr; + gint writeseg; + gint len; + gint remaining; + gint offset = 0; + + status = AudioUnitRender (buf->core_audio->audiounit, ioActionFlags, + inTimeStamp, inBusNumber, inNumberFrames, buf->core_audio->recBufferList); + + if (status) { + GST_WARNING_OBJECT (buf, "AudioUnitRender returned %d", (int) status); + return status; + } + + remaining = buf->core_audio->recBufferList->mBuffers[0].mDataByteSize; + + while (remaining) { + if (!gst_audio_ring_buffer_prepare_read (GST_AUDIO_RING_BUFFER (buf), + &writeseg, &writeptr, &len)) + return 0; + + len -= buf->segoffset; + + if (len > remaining) + len = remaining; + + memcpy (writeptr + buf->segoffset, + (char *) buf->core_audio->recBufferList->mBuffers[0].mData + offset, + len); + + buf->segoffset += len; + offset += len; + remaining -= len; + + if ((gint) buf->segoffset == GST_AUDIO_RING_BUFFER (buf)->spec.segsize) { + /* we wrote one segment */ + gst_audio_ring_buffer_advance (GST_AUDIO_RING_BUFFER (buf), 1); + + buf->segoffset = 0; + } + } + return 0; +} + +static void +gst_osx_audio_src_osxelement_init (gpointer g_iface, gpointer iface_data) +{ + GstOsxAudioElementInterface *iface = (GstOsxAudioElementInterface *) g_iface; + + iface->io_proc = (AURenderCallback) gst_osx_audio_src_io_proc; +} + +static void +gst_osx_audio_src_select_device (GstOsxAudioSrc * osxsrc) +{ + gst_core_audio_select_source_device (&osxsrc->device_id); +} diff --git a/sys/osxaudio/gstosxaudiosrc.h b/sys/osxaudio/gstosxaudiosrc.h new file mode 100755 index 0000000..a5f5d84 --- /dev/null +++ b/sys/osxaudio/gstosxaudiosrc.h @@ -0,0 +1,83 @@ +/* + * GStreamer + * Copyright (C) 2005-2006 Zaheer Abbas Merali <zaheerabbas at merali dot org> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_OSXAUDIOSRC_H__ +#define __GST_OSXAUDIOSRC_H__ + +#include <gst/gst.h> +#include <gst/audio/audio.h> +#include <gst/audio/gstaudiobasesrc.h> +#include "gstosxaudioringbuffer.h" + +G_BEGIN_DECLS + +#define GST_TYPE_OSX_AUDIO_SRC \ + (gst_osx_audio_src_get_type()) +#define GST_OSX_AUDIO_SRC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSX_AUDIO_SRC,GstOsxAudioSrc)) +#define GST_OSX_AUDIO_SRC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSX_AUDIO_SRC,GstOsxAudioSrcClass)) + +typedef struct _GstOsxAudioSrc GstOsxAudioSrc; +typedef struct _GstOsxAudioSrcClass GstOsxAudioSrcClass; + +struct _GstOsxAudioSrc +{ + GstAudioBaseSrc src; + + AudioDeviceID device_id; + + /* actual number of channels reported by input device */ + int deviceChannels; +}; + +struct _GstOsxAudioSrcClass +{ + GstAudioBaseSrcClass parent_class; +}; + +GType gst_osx_audio_src_get_type (void); + +G_END_DECLS + +#endif /* __GST_OSXAUDIOSRC_H__ */ diff --git a/sys/osxaudio/gstosxcoreaudio.c b/sys/osxaudio/gstosxcoreaudio.c new file mode 100755 index 0000000..9f69dc0 --- /dev/null +++ b/sys/osxaudio/gstosxcoreaudio.c @@ -0,0 +1,221 @@ +/* + * GStreamer + * Copyright (C) 2012-2013 Fluendo S.A. <support@fluendo.com> + * Authors: Josep Torra Vallès <josep@fluendo.com> + * Andoni Morales Alastruey <amorales@fluendo.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#include "gstosxcoreaudio.h" +#include "gstosxcoreaudiocommon.h" +#include "gstosxaudiosrc.h" + +GST_DEBUG_CATEGORY_STATIC (osx_audio_debug); +#define GST_CAT_DEFAULT osx_audio_debug + +G_DEFINE_TYPE (GstCoreAudio, gst_core_audio, G_TYPE_OBJECT); + +#ifdef HAVE_IOS +#include "gstosxcoreaudioremoteio.c" +#else +#include "gstosxcoreaudiohal.c" +#endif + + +static void +gst_core_audio_class_init (GstCoreAudioClass * klass) +{ +} + +static void +gst_core_audio_init (GstCoreAudio * core_audio) +{ + core_audio->is_passthrough = FALSE; + core_audio->device_id = kAudioDeviceUnknown; + core_audio->is_src = FALSE; + core_audio->audiounit = NULL; +#ifndef HAVE_IOS + core_audio->hog_pid = -1; + core_audio->disabled_mixing = FALSE; +#endif +} + +/************************** + * Public API * + *************************/ + +GstCoreAudio * +gst_core_audio_new (GstObject * osxbuf) +{ + GstCoreAudio *core_audio; + + core_audio = g_object_new (GST_TYPE_CORE_AUDIO, NULL); + core_audio->osxbuf = osxbuf; + return core_audio; +} + +gboolean +gst_core_audio_close (GstCoreAudio * core_audio) +{ + AudioComponentInstanceDispose (core_audio->audiounit); + core_audio->audiounit = NULL; + return TRUE; +} + +gboolean +gst_core_audio_open (GstCoreAudio * core_audio) +{ + + if (!gst_core_audio_open_impl (core_audio)) + return FALSE; + + if (core_audio->is_src) { + AudioStreamBasicDescription asbd_in; + UInt32 propertySize; + OSStatus status; + + GstOsxAudioSrc *src = + GST_OSX_AUDIO_SRC (GST_OBJECT_PARENT (core_audio->osxbuf)); + + propertySize = sizeof (asbd_in); + status = AudioUnitGetProperty (core_audio->audiounit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, 1, &asbd_in, &propertySize); + + if (status) { + AudioComponentInstanceDispose (core_audio->audiounit); + core_audio->audiounit = NULL; + GST_WARNING_OBJECT (core_audio, + "Unable to obtain device properties: %d", (int) status); + return FALSE; + } else { + src->deviceChannels = asbd_in.mChannelsPerFrame; + } + } + + return TRUE; +} + +gboolean +gst_core_audio_start_processing (GstCoreAudio * core_audio) +{ + return gst_core_audio_start_processing_impl (core_audio); +} + +gboolean +gst_core_audio_pause_processing (GstCoreAudio * core_audio) +{ + return gst_core_audio_pause_processing_impl (core_audio); +} + +gboolean +gst_core_audio_stop_processing (GstCoreAudio * core_audio) +{ + return gst_core_audio_stop_processing_impl (core_audio); +} + +gboolean +gst_core_audio_get_samples_and_latency (GstCoreAudio * core_audio, + gdouble rate, guint * samples, gdouble * latency) +{ + return gst_core_audio_get_samples_and_latency_impl (core_audio, rate, + samples, latency); +} + +gboolean +gst_core_audio_initialize (GstCoreAudio * core_audio, + AudioStreamBasicDescription format, GstCaps * caps, gboolean is_passthrough) +{ + guint32 frame_size; + OSStatus status; + + GST_DEBUG_OBJECT (core_audio, + "Initializing: passthrough:%d caps:%" GST_PTR_FORMAT, is_passthrough, + caps); + + if (!gst_core_audio_initialize_impl (core_audio, format, caps, + is_passthrough, &frame_size)) { + goto error; + } + + if (core_audio->is_src) { + /* create AudioBufferList needed for recording */ + core_audio->recBufferList = + buffer_list_alloc (format.mChannelsPerFrame, + frame_size * format.mBytesPerFrame); + } + + /* Initialize the AudioUnit */ + status = AudioUnitInitialize (core_audio->audiounit); + if (status) { + GST_ERROR_OBJECT (core_audio, "Failed to initialise AudioUnit: %d", + (int) status); + goto error; + } + return TRUE; + +error: + if (core_audio->is_src && core_audio->recBufferList) { + buffer_list_free (core_audio->recBufferList); + core_audio->recBufferList = NULL; + } + return FALSE; +} + +void +gst_core_audio_unitialize (GstCoreAudio * core_audio) +{ + AudioUnitUninitialize (core_audio->audiounit); + + if (core_audio->recBufferList) { + buffer_list_free (core_audio->recBufferList); + core_audio->recBufferList = NULL; + } +} + +void +gst_core_audio_set_volume (GstCoreAudio * core_audio, gfloat volume) +{ + AudioUnitSetParameter (core_audio->audiounit, kHALOutputParam_Volume, + kAudioUnitScope_Global, 0, (float) volume, 0); +} + +gboolean +gst_core_audio_select_device (AudioDeviceID * device_id) +{ + return gst_core_audio_select_device_impl (device_id); +} + +gboolean +gst_core_audio_select_source_device (AudioDeviceID * device_id) +{ + return gst_core_audio_select_source_device_impl (device_id); +} + +void +gst_core_audio_init_debug (void) +{ + GST_DEBUG_CATEGORY_INIT (osx_audio_debug, "osxaudio", 0, + "OSX Audio Elements"); +} + +gboolean +gst_core_audio_audio_device_is_spdif_avail (AudioDeviceID device_id) +{ + return gst_core_audio_audio_device_is_spdif_avail_impl (device_id); +} diff --git a/sys/osxaudio/gstosxcoreaudio.h b/sys/osxaudio/gstosxcoreaudio.h new file mode 100755 index 0000000..78cd4b9 --- /dev/null +++ b/sys/osxaudio/gstosxcoreaudio.h @@ -0,0 +1,151 @@ +/* + * GStreamer + * Copyright (C) 2012 Fluendo S.A. <support@fluendo.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef __GST_CORE_AUDIO_H__ +#define __GST_CORE_AUDIO_H__ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gst/gst.h> +#ifdef HAVE_IOS + #include <CoreAudio/CoreAudioTypes.h> + #define AudioDeviceID gint + #define kAudioDeviceUnknown 0 +#else + #include <CoreAudio/CoreAudio.h> + #include <AudioToolbox/AudioToolbox.h> + #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 + #include <CoreServices/CoreServices.h> + #define AudioComponentFindNext FindNextComponent + #define AudioComponentInstanceNew OpenAComponent + #define AudioComponentInstanceDispose CloseComponent + #define AudioComponent Component + #define AudioComponentDescription ComponentDescription + #endif +#endif +#include <AudioUnit/AudioUnit.h> +#include "gstosxaudioelement.h" + + +G_BEGIN_DECLS + +#define GST_TYPE_CORE_AUDIO \ + (gst_core_audio_get_type()) +#define GST_CORE_AUDIO(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CORE_AUDIO,GstCoreAudio)) +#define GST_CORE_AUDIO_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CORE_AUDIO,GstCoreAudioClass)) +#define GST_CORE_AUDIO_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_CORE_AUDIO,GstCoreAudioClass)) +#define GST_IS_CORE_AUDIO(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CORE_AUDIO)) +#define GST_IS_CORE_AUDIO_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CORE_AUDIO)) + +#define CORE_AUDIO_FORMAT_IS_SPDIF(f) ((f).mFormat.mFormatID == 'IAC3' || (f).mFormat.mFormatID == 'iac3' || (f).mFormat.mFormatID == kAudioFormat60958AC3 || (f).mFormat.mFormatID == kAudioFormatAC3) + +#define CORE_AUDIO_FORMAT "FormatID: %" GST_FOURCC_FORMAT " rate: %f flags: 0x%x BytesPerPacket: %u FramesPerPacket: %u BytesPerFrame: %u ChannelsPerFrame: %u BitsPerChannel: %u" +#define CORE_AUDIO_FORMAT_ARGS(f) GST_FOURCC_ARGS((f).mFormatID),(f).mSampleRate,(unsigned)(f).mFormatFlags,(unsigned)(f).mBytesPerPacket,(unsigned)(f).mFramesPerPacket,(unsigned)(f).mBytesPerFrame,(unsigned)(f).mChannelsPerFrame,(unsigned)(f).mBitsPerChannel + +typedef struct _GstCoreAudio GstCoreAudio; +typedef struct _GstCoreAudioClass GstCoreAudioClass; + +struct _GstCoreAudio +{ + GObject object; + + GstObject *osxbuf; + GstOsxAudioElementInterface *element; + + gboolean is_src; + gboolean is_passthrough; + AudioDeviceID device_id; + AudioStreamBasicDescription stream_format; + gint stream_idx; + gboolean io_proc_active; + gboolean io_proc_needs_deactivation; + + /* For LPCM in/out */ + AudioUnit audiounit; + AudioBufferList *recBufferList; + +#ifndef HAVE_IOS + /* For SPDIF out */ + pid_t hog_pid; + gboolean disabled_mixing; + AudioStreamID stream_id; + gboolean revert_format; + AudioStreamBasicDescription original_format; + AudioDeviceIOProcID procID; +#endif +}; + +struct _GstCoreAudioClass +{ + GObjectClass parent_class; +}; + +GType gst_core_audio_get_type (void); + +void gst_core_audio_init_debug (void); + +GstCoreAudio * gst_core_audio_new (GstObject *osxbuf); + +gboolean gst_core_audio_open (GstCoreAudio *core_audio); + +gboolean gst_core_audio_close (GstCoreAudio *core_audio); + +gboolean gst_core_audio_initialize (GstCoreAudio *core_audio, + AudioStreamBasicDescription format, + GstCaps *caps, + gboolean is_passthrough); + +void gst_core_audio_unitialize (GstCoreAudio *core_audio); + +gboolean gst_core_audio_start_processing (GstCoreAudio *core_audio); + +gboolean gst_core_audio_pause_processing (GstCoreAudio *core_audio); + +gboolean gst_core_audio_stop_processing (GstCoreAudio *core_audio); + +gboolean gst_core_audio_get_samples_and_latency (GstCoreAudio * core_audio, + gdouble rate, + guint *samples, + gdouble *latency); + +void gst_core_audio_set_volume (GstCoreAudio *core_audio, + gfloat volume); + +gboolean gst_core_audio_audio_device_is_spdif_avail (AudioDeviceID device_id); + + +gboolean gst_core_audio_select_device (AudioDeviceID *device_id); + +gboolean gst_core_audio_select_source_device (AudioDeviceID *device_id); + +AudioChannelLayout * gst_core_audio_audio_device_get_channel_layout (AudioDeviceID device_id); + + +G_END_DECLS + +#endif /* __GST_CORE_AUDIO_H__ */ diff --git a/sys/osxaudio/gstosxcoreaudiocommon.c b/sys/osxaudio/gstosxcoreaudiocommon.c new file mode 100755 index 0000000..badb40c --- /dev/null +++ b/sys/osxaudio/gstosxcoreaudiocommon.c @@ -0,0 +1,430 @@ +/* + * GStreamer + * Copyright (C) 2012-2013 Fluendo S.A. <support@fluendo.com> + * Authors: Josep Torra Vallès <josep@fluendo.com> + * Andoni Morales Alastruey <amorales@fluendo.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#include "gstosxcoreaudiocommon.h" + +void +gst_core_audio_remove_render_callback (GstCoreAudio * core_audio) +{ + AURenderCallbackStruct input; + OSStatus status; + + /* Deactivate the render callback by calling SetRenderCallback + * with a NULL inputProc. + */ + input.inputProc = NULL; + input.inputProcRefCon = NULL; + + status = AudioUnitSetProperty (core_audio->audiounit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, 0, /* N/A for global */ + &input, sizeof (input)); + + if (status) { + GST_WARNING_OBJECT (core_audio->osxbuf, + "Failed to remove render callback %d", (int) status); + } + + /* Remove the RenderNotify too */ + status = AudioUnitRemoveRenderNotify (core_audio->audiounit, + (AURenderCallback) gst_core_audio_render_notify, core_audio); + + if (status) { + GST_WARNING_OBJECT (core_audio->osxbuf, + "Failed to remove render notify callback %d", (int) status); + } + + /* We're deactivated.. */ + core_audio->io_proc_needs_deactivation = FALSE; + core_audio->io_proc_active = FALSE; +} + +OSStatus +gst_core_audio_render_notify (GstCoreAudio * core_audio, + AudioUnitRenderActionFlags * ioActionFlags, + const AudioTimeStamp * inTimeStamp, + unsigned int inBusNumber, + unsigned int inNumberFrames, AudioBufferList * ioData) +{ + /* Before rendering a frame, we get the PreRender notification. + * Here, we detach the RenderCallback if we've been paused. + * + * This is necessary (rather than just directly detaching it) to + * work around some thread-safety issues in CoreAudio + */ + if ((*ioActionFlags) & kAudioUnitRenderAction_PreRender) { + if (core_audio->io_proc_needs_deactivation) { + gst_core_audio_remove_render_callback (core_audio); + } + } + + return noErr; +} + +gboolean +gst_core_audio_io_proc_start (GstCoreAudio * core_audio) +{ + OSStatus status; + AURenderCallbackStruct input; + AudioUnitPropertyID callback_type; + + GST_DEBUG_OBJECT (core_audio->osxbuf, + "osx ring buffer start ioproc: %p device_id %lu", + core_audio->element->io_proc, (gulong) core_audio->device_id); + if (!core_audio->io_proc_active) { + callback_type = core_audio->is_src ? + kAudioOutputUnitProperty_SetInputCallback : + kAudioUnitProperty_SetRenderCallback; + + input.inputProc = (AURenderCallback) core_audio->element->io_proc; + input.inputProcRefCon = core_audio->osxbuf; + + status = AudioUnitSetProperty (core_audio->audiounit, callback_type, kAudioUnitScope_Global, 0, /* N/A for global */ + &input, sizeof (input)); + + if (status) { + GST_ERROR_OBJECT (core_audio->osxbuf, + "AudioUnitSetProperty failed: %d", (int) status); + return FALSE; + } + // ### does it make sense to do this notify stuff for input mode? + status = AudioUnitAddRenderNotify (core_audio->audiounit, + (AURenderCallback) gst_core_audio_render_notify, core_audio); + + if (status) { + GST_ERROR_OBJECT (core_audio->osxbuf, + "AudioUnitAddRenderNotify failed %d", (int) status); + return FALSE; + } + core_audio->io_proc_active = TRUE; + } + + core_audio->io_proc_needs_deactivation = FALSE; + + status = AudioOutputUnitStart (core_audio->audiounit); + if (status) { + GST_ERROR_OBJECT (core_audio->osxbuf, "AudioOutputUnitStart failed: %d", + (int) status); + return FALSE; + } + return TRUE; +} + +gboolean +gst_core_audio_io_proc_stop (GstCoreAudio * core_audio) +{ + OSErr status; + + GST_DEBUG_OBJECT (core_audio->osxbuf, + "osx ring buffer stop ioproc: %p device_id %lu", + core_audio->element->io_proc, (gulong) core_audio->device_id); + + status = AudioOutputUnitStop (core_audio->audiounit); + if (status) { + GST_WARNING_OBJECT (core_audio->osxbuf, + "AudioOutputUnitStop failed: %d", (int) status); + } + // ###: why is it okay to directly remove from here but not from pause() ? + if (core_audio->io_proc_active) { + gst_core_audio_remove_render_callback (core_audio); + } + return TRUE; +} + +AudioBufferList * +buffer_list_alloc (int channels, int size) +{ + AudioBufferList *list; + int total_size; + int n; + + total_size = sizeof (AudioBufferList) + 1 * sizeof (AudioBuffer); + list = (AudioBufferList *) g_malloc (total_size); + + list->mNumberBuffers = 1; + for (n = 0; n < (int) list->mNumberBuffers; ++n) { + list->mBuffers[n].mNumberChannels = channels; + list->mBuffers[n].mDataByteSize = size; + list->mBuffers[n].mData = g_malloc (size); + } + + return list; +} + +void +buffer_list_free (AudioBufferList * list) +{ + int n; + + for (n = 0; n < (int) list->mNumberBuffers; ++n) { + if (list->mBuffers[n].mData) + g_free (list->mBuffers[n].mData); + } + + g_free (list); +} + +gboolean +gst_core_audio_bind_device (GstCoreAudio * core_audio) +{ + OSStatus status; + + /* Specify which device we're using. */ + GST_DEBUG_OBJECT (core_audio->osxbuf, "Bind AudioUnit to device %d", + (int) core_audio->device_id); + status = AudioUnitSetProperty (core_audio->audiounit, + kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, + &core_audio->device_id, sizeof (AudioDeviceID)); + if (status) { + GST_ERROR_OBJECT (core_audio->osxbuf, "Failed binding to device: %d", + (int) status); + goto audiounit_error; + } + return TRUE; + +audiounit_error: + if (core_audio->recBufferList) { + buffer_list_free (core_audio->recBufferList); + core_audio->recBufferList = NULL; + } + return FALSE; +} + +gboolean +gst_core_audio_set_channels_layout (GstCoreAudio * core_audio, + gint channels, GstCaps * caps) +{ + /* Configure the output stream and allocate ringbuffer memory */ + AudioChannelLayout *layout = NULL; + OSStatus status; + int layoutSize, element, i; + AudioUnitScope scope; + GstStructure *structure; + GstAudioChannelPosition *positions = NULL; + guint64 channel_mask; + + /* Describe channels */ + layoutSize = sizeof (AudioChannelLayout) + + channels * sizeof (AudioChannelDescription); + layout = g_malloc (layoutSize); + + structure = gst_caps_get_structure (caps, 0); + if (gst_structure_get (structure, "channel-mask", GST_TYPE_BITMASK, + &channel_mask, NULL)) { + positions = g_new (GstAudioChannelPosition, channels); + gst_audio_channel_positions_from_mask (channels, channel_mask, positions); + } + + layout->mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions; + layout->mChannelBitmap = 0; /* Not used */ + layout->mNumberChannelDescriptions = channels; + for (i = 0; i < channels; i++) { + if (positions) { + layout->mChannelDescriptions[i].mChannelLabel = + gst_audio_channel_position_to_coreaudio_channel_label (positions[i], + i); + } else { + /* Discrete channel numbers are ORed into this */ + layout->mChannelDescriptions[i].mChannelLabel = + kAudioChannelLabel_Discrete_0 | i; + } + + /* Others unused */ + layout->mChannelDescriptions[i].mChannelFlags = 0; + layout->mChannelDescriptions[i].mCoordinates[0] = 0.f; + layout->mChannelDescriptions[i].mCoordinates[1] = 0.f; + layout->mChannelDescriptions[i].mCoordinates[2] = 0.f; + } + + if (positions) { + g_free (positions); + positions = NULL; + } + + scope = core_audio->is_src ? kAudioUnitScope_Output : kAudioUnitScope_Input; + element = core_audio->is_src ? 1 : 0; + + if (layoutSize) { + status = AudioUnitSetProperty (core_audio->audiounit, + kAudioUnitProperty_AudioChannelLayout, + scope, element, layout, layoutSize); + if (status) { + GST_WARNING_OBJECT (core_audio->osxbuf, + "Failed to set output channel layout: %d", (int) status); + return FALSE; + } + } + + g_free (layout); + return TRUE; +} + +gboolean +gst_core_audio_set_format (GstCoreAudio * core_audio, + AudioStreamBasicDescription format) +{ + /* Configure the output stream and allocate ringbuffer memory */ + OSStatus status; + UInt32 propertySize; + int element; + AudioUnitScope scope; + + GST_DEBUG_OBJECT (core_audio->osxbuf, "Setting format for AudioUnit"); + + scope = core_audio->is_src ? kAudioUnitScope_Output : kAudioUnitScope_Input; + element = core_audio->is_src ? 1 : 0; + + propertySize = sizeof (AudioStreamBasicDescription); + status = AudioUnitSetProperty (core_audio->audiounit, + kAudioUnitProperty_StreamFormat, scope, element, &format, propertySize); + + if (status) { + GST_WARNING_OBJECT (core_audio->osxbuf, + "Failed to set audio description: %d", (int) status); + return FALSE;; + } + + return TRUE; +} + +gboolean +gst_core_audio_open_device (GstCoreAudio * core_audio, OSType sub_type, + const gchar * adesc) +{ + AudioComponentDescription desc; + AudioComponent comp; + OSStatus status; + AudioUnit unit; + UInt32 enableIO; + + desc.componentType = kAudioUnitType_Output; + desc.componentSubType = sub_type; + desc.componentManufacturer = kAudioUnitManufacturer_Apple; + desc.componentFlags = 0; + desc.componentFlagsMask = 0; + + comp = AudioComponentFindNext (NULL, &desc); + + if (comp == NULL) { + GST_WARNING_OBJECT (core_audio->osxbuf, "Couldn't find %s component", + adesc); + return FALSE; + } + + status = AudioComponentInstanceNew (comp, &unit); + + if (status) { + GST_ERROR_OBJECT (core_audio->osxbuf, "Couldn't open %s component %d", + adesc, (int) status); + return FALSE; + } + + if (core_audio->is_src) { + /* enable input */ + enableIO = 1; + status = AudioUnitSetProperty (unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, /* 1 = input element */ + &enableIO, sizeof (enableIO)); + + if (status) { + AudioComponentInstanceDispose (unit); + GST_WARNING_OBJECT (core_audio->osxbuf, "Failed to enable input: %d", + (int) status); + return FALSE; + } + + /* disable output */ + enableIO = 0; + status = AudioUnitSetProperty (unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, /* 0 = output element */ + &enableIO, sizeof (enableIO)); + + if (status) { + AudioComponentInstanceDispose (unit); + GST_WARNING_OBJECT (core_audio->osxbuf, "Failed to disable output: %d", + (int) status); + return FALSE; + } + } + + GST_DEBUG_OBJECT (core_audio->osxbuf, "Created %s AudioUnit: %p", adesc, + unit); + core_audio->audiounit = unit; + return TRUE; +} + +AudioChannelLabel +gst_audio_channel_position_to_coreaudio_channel_label (GstAudioChannelPosition + position, int channel) +{ + switch (position) { + case GST_AUDIO_CHANNEL_POSITION_NONE: + return kAudioChannelLabel_Discrete_0 | channel; + case GST_AUDIO_CHANNEL_POSITION_MONO: + return kAudioChannelLabel_Mono; + case GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT: + return kAudioChannelLabel_Left; + case GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT: + return kAudioChannelLabel_Right; + case GST_AUDIO_CHANNEL_POSITION_REAR_CENTER: + return kAudioChannelLabel_CenterSurround; + case GST_AUDIO_CHANNEL_POSITION_REAR_LEFT: + return kAudioChannelLabel_LeftSurround; + case GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT: + return kAudioChannelLabel_RightSurround; + case GST_AUDIO_CHANNEL_POSITION_LFE1: + return kAudioChannelLabel_LFEScreen; + case GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER: + return kAudioChannelLabel_Center; + case GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER: + return kAudioChannelLabel_Center; // ??? + case GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER: + return kAudioChannelLabel_Center; // ??? + case GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT: + return kAudioChannelLabel_LeftSurroundDirect; + case GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT: + return kAudioChannelLabel_RightSurroundDirect; + default: + return kAudioChannelLabel_Unknown; + } +} + +void +gst_core_audio_dump_channel_layout (AudioChannelLayout * channel_layout) +{ + UInt32 i; + + GST_DEBUG ("mChannelLayoutTag: 0x%lx", + (unsigned long) channel_layout->mChannelLayoutTag); + GST_DEBUG ("mChannelBitmap: 0x%lx", + (unsigned long) channel_layout->mChannelBitmap); + GST_DEBUG ("mNumberChannelDescriptions: %lu", + (unsigned long) channel_layout->mNumberChannelDescriptions); + for (i = 0; i < channel_layout->mNumberChannelDescriptions; i++) { + AudioChannelDescription *channel_desc = + &channel_layout->mChannelDescriptions[i]; + GST_DEBUG (" mChannelLabel: 0x%lx mChannelFlags: 0x%lx " + "mCoordinates[0]: %f mCoordinates[1]: %f " + "mCoordinates[2]: %f", + (unsigned long) channel_desc->mChannelLabel, + (unsigned long) channel_desc->mChannelFlags, + channel_desc->mCoordinates[0], channel_desc->mCoordinates[1], + channel_desc->mCoordinates[2]); + } +} diff --git a/sys/osxaudio/gstosxcoreaudiocommon.h b/sys/osxaudio/gstosxcoreaudiocommon.h new file mode 100755 index 0000000..e9fbb8e --- /dev/null +++ b/sys/osxaudio/gstosxcoreaudiocommon.h @@ -0,0 +1,65 @@ +/* + * GStreamer + * Copyright (C) 2012-2013 Fluendo S.A. <support@fluendo.com> + * Authors: Josep Torra Vallès <josep@fluendo.com> + * Andoni Morales Alastruey <amorales@fluendo.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#include "gstosxcoreaudio.h" +#include <gst/audio/audio-channels.h> + +typedef struct +{ + GMutex lock; + GCond cond; +} PropertyMutex; + +gboolean gst_core_audio_bind_device (GstCoreAudio *core_audio); + +void gst_core_audio_dump_channel_layout (AudioChannelLayout * channel_layout); + +void gst_core_audio_remove_render_callback (GstCoreAudio * core_audio); + +gboolean gst_core_audio_io_proc_start (GstCoreAudio * core_audio); + +gboolean gst_core_audio_io_proc_stop (GstCoreAudio * core_audio); + +AudioBufferList * buffer_list_alloc (int channels, int size); + +void buffer_list_free (AudioBufferList * list); + +gboolean gst_core_audio_set_format (GstCoreAudio * core_audio, + AudioStreamBasicDescription format); + +gboolean gst_core_audio_set_channels_layout (GstCoreAudio * core_audio, + gint channels, GstCaps * caps); + +gboolean gst_core_audio_open_device (GstCoreAudio *core_audio, + OSType sub_type, + const gchar *adesc); + +OSStatus gst_core_audio_render_notify (GstCoreAudio * core_audio, + AudioUnitRenderActionFlags * ioActionFlags, + const AudioTimeStamp * inTimeStamp, + unsigned int inBusNumber, + unsigned int inNumberFrames, + AudioBufferList * ioData); + +AudioChannelLabel gst_audio_channel_position_to_coreaudio_channel_label (GstAudioChannelPosition position, int channel); + diff --git a/sys/osxaudio/gstosxcoreaudiohal.c b/sys/osxaudio/gstosxcoreaudiohal.c new file mode 100755 index 0000000..fde41f3 --- /dev/null +++ b/sys/osxaudio/gstosxcoreaudiohal.c @@ -0,0 +1,1254 @@ +/* + * GStreamer + * Copyright (C) 2012-2013 Fluendo S.A. <support@fluendo.com> + * Authors: Josep Torra Vallès <josep@fluendo.com> + * Andoni Morales Alastruey <amorales@fluendo.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#include <unistd.h> /* for getpid */ +#include "gstosxaudiosink.h" + +static inline gboolean +_audio_system_set_runloop (CFRunLoopRef runLoop) +{ + OSStatus status = noErr; + + gboolean res = FALSE; + + AudioObjectPropertyAddress runloopAddress = { + kAudioHardwarePropertyRunLoop, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster + }; + + status = AudioObjectSetPropertyData (kAudioObjectSystemObject, + &runloopAddress, 0, NULL, sizeof (CFRunLoopRef), &runLoop); + if (status == noErr) { + res = TRUE; + } else { + GST_ERROR ("failed to set runloop to %p: %d", runLoop, (int) status); + } + + return res; +} + +static inline AudioDeviceID +_audio_system_get_default_output (void) +{ + OSStatus status = noErr; + UInt32 propertySize = sizeof (AudioDeviceID); + AudioDeviceID device_id = kAudioDeviceUnknown; + + AudioObjectPropertyAddress defaultDeviceAddress = { + kAudioHardwarePropertyDefaultOutputDevice, + kAudioDevicePropertyScopeOutput, + kAudioObjectPropertyElementMaster + }; + + status = AudioObjectGetPropertyData (kAudioObjectSystemObject, + &defaultDeviceAddress, 0, NULL, &propertySize, &device_id); + if (status != noErr) { + GST_ERROR ("failed getting default output device: %d", (int) status); + } + + return device_id; +} + +static inline AudioDeviceID * +_audio_system_get_devices (gint * ndevices) +{ + OSStatus status = noErr; + UInt32 propertySize = 0; + AudioDeviceID *devices = NULL; + + AudioObjectPropertyAddress audioDevicesAddress = { + kAudioHardwarePropertyDevices, + kAudioDevicePropertyScopeOutput, + kAudioObjectPropertyElementMaster + }; + + status = AudioObjectGetPropertyDataSize (kAudioObjectSystemObject, + &audioDevicesAddress, 0, NULL, &propertySize); + if (status != noErr) { + GST_WARNING ("failed getting number of devices: %d", (int) status); + return NULL; + } + + *ndevices = propertySize / sizeof (AudioDeviceID); + + devices = (AudioDeviceID *) g_malloc (propertySize); + if (devices) { + status = AudioObjectGetPropertyData (kAudioObjectSystemObject, + &audioDevicesAddress, 0, NULL, &propertySize, devices); + if (status != noErr) { + GST_WARNING ("failed getting the list of devices: %d", (int) status); + g_free (devices); + *ndevices = 0; + return NULL; + } + } + return devices; +} + +static inline gboolean +_audio_device_is_alive (AudioDeviceID device_id) +{ + OSStatus status = noErr; + int alive = FALSE; + UInt32 propertySize = sizeof (alive); + + AudioObjectPropertyAddress audioDeviceAliveAddress = { + kAudioDevicePropertyDeviceIsAlive, + kAudioDevicePropertyScopeOutput, + kAudioObjectPropertyElementMaster + }; + + status = AudioObjectGetPropertyData (device_id, + &audioDeviceAliveAddress, 0, NULL, &propertySize, &alive); + if (status != noErr) { + alive = FALSE; + } + + return alive; +} + +static inline guint +_audio_device_get_latency (AudioDeviceID device_id) +{ + OSStatus status = noErr; + UInt32 latency = 0; + UInt32 propertySize = sizeof (latency); + + AudioObjectPropertyAddress audioDeviceLatencyAddress = { + kAudioDevicePropertyLatency, + kAudioDevicePropertyScopeOutput, + kAudioObjectPropertyElementMaster + }; + + status = AudioObjectGetPropertyData (device_id, + &audioDeviceLatencyAddress, 0, NULL, &propertySize, &latency); + if (status != noErr) { + GST_ERROR ("failed to get latency: %d", (int) status); + latency = -1; + } + + return latency; +} + +static inline pid_t +_audio_device_get_hog (AudioDeviceID device_id) +{ + OSStatus status = noErr; + pid_t hog_pid; + UInt32 propertySize = sizeof (hog_pid); + + AudioObjectPropertyAddress audioDeviceHogModeAddress = { + kAudioDevicePropertyHogMode, + kAudioDevicePropertyScopeOutput, + kAudioObjectPropertyElementMaster + }; + + status = AudioObjectGetPropertyData (device_id, + &audioDeviceHogModeAddress, 0, NULL, &propertySize, &hog_pid); + if (status != noErr) { + GST_ERROR ("failed to get hog: %d", (int) status); + hog_pid = -1; + } + + return hog_pid; +} + +static inline gboolean +_audio_device_set_hog (AudioDeviceID device_id, pid_t hog_pid) +{ + OSStatus status = noErr; + UInt32 propertySize = sizeof (hog_pid); + gboolean res = FALSE; + + AudioObjectPropertyAddress audioDeviceHogModeAddress = { + kAudioDevicePropertyHogMode, + kAudioDevicePropertyScopeOutput, + kAudioObjectPropertyElementMaster + }; + + status = AudioObjectSetPropertyData (device_id, + &audioDeviceHogModeAddress, 0, NULL, propertySize, &hog_pid); + + if (status == noErr) { + res = TRUE; + } else { + GST_ERROR ("failed to set hog: %d", (int) status); + } + + return res; +} + +static inline gboolean +_audio_device_set_mixing (AudioDeviceID device_id, gboolean enable_mix) +{ + OSStatus status = noErr; + UInt32 propertySize = 0, can_mix = enable_mix; + Boolean writable = FALSE; + gboolean res = FALSE; + + AudioObjectPropertyAddress audioDeviceSupportsMixingAddress = { + kAudioDevicePropertySupportsMixing, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster + }; + + if (AudioObjectHasProperty (device_id, &audioDeviceSupportsMixingAddress)) { + /* Set mixable to false if we are allowed to */ + status = AudioObjectIsPropertySettable (device_id, + &audioDeviceSupportsMixingAddress, &writable); + if (status) { + GST_DEBUG ("AudioObjectIsPropertySettable: %d", (int) status); + } + status = AudioObjectGetPropertyDataSize (device_id, + &audioDeviceSupportsMixingAddress, 0, NULL, &propertySize); + if (status) { + GST_DEBUG ("AudioObjectGetPropertyDataSize: %d", (int) status); + } + status = AudioObjectGetPropertyData (device_id, + &audioDeviceSupportsMixingAddress, 0, NULL, &propertySize, &can_mix); + if (status) { + GST_DEBUG ("AudioObjectGetPropertyData: %d", (int) status); + } + + if (status == noErr && writable) { + can_mix = enable_mix; + status = AudioObjectSetPropertyData (device_id, + &audioDeviceSupportsMixingAddress, 0, NULL, propertySize, &can_mix); + res = TRUE; + } + + if (status != noErr) { + GST_ERROR ("failed to set mixmode: %d", (int) status); + } + } else { + GST_DEBUG ("property not found, mixing coudln't be changed"); + } + + return res; +} + +static inline gchar * +_audio_device_get_name (AudioDeviceID device_id) +{ + OSStatus status = noErr; + UInt32 propertySize = 0; + gchar *device_name = NULL; + + AudioObjectPropertyAddress deviceNameAddress = { + kAudioDevicePropertyDeviceName, + kAudioDevicePropertyScopeOutput, + kAudioObjectPropertyElementMaster + }; + + /* Get the length of the device name */ + status = AudioObjectGetPropertyDataSize (device_id, + &deviceNameAddress, 0, NULL, &propertySize); + if (status != noErr) { + goto beach; + } + + /* Get the name of the device */ + device_name = (gchar *) g_malloc (propertySize); + status = AudioObjectGetPropertyData (device_id, + &deviceNameAddress, 0, NULL, &propertySize, device_name); + if (status != noErr) { + g_free (device_name); + device_name = NULL; + } + +beach: + return device_name; +} + +static inline gboolean +_audio_device_has_output (AudioDeviceID device_id) +{ + OSStatus status = noErr; + UInt32 propertySize; + + AudioObjectPropertyAddress streamsAddress = { + kAudioDevicePropertyStreams, + kAudioDevicePropertyScopeOutput, + kAudioObjectPropertyElementMaster + }; + + status = AudioObjectGetPropertyDataSize (device_id, + &streamsAddress, 0, NULL, &propertySize); + if (status != noErr) { + return FALSE; + } + if (propertySize == 0) { + return FALSE; + } + + return TRUE; +} + +AudioChannelLayout * +gst_core_audio_audio_device_get_channel_layout (AudioDeviceID device_id) +{ + OSStatus status = noErr; + UInt32 propertySize = 0; + AudioChannelLayout *layout = NULL; + + AudioObjectPropertyAddress channelLayoutAddress = { + kAudioDevicePropertyPreferredChannelLayout, + kAudioDevicePropertyScopeOutput, + kAudioObjectPropertyElementMaster + }; + + /* Get the length of the default channel layout structure */ + status = AudioObjectGetPropertyDataSize (device_id, + &channelLayoutAddress, 0, NULL, &propertySize); + if (status != noErr) { + GST_ERROR ("failed to get prefered layout: %d", (int) status); + goto beach; + } + + /* Get the default channel layout of the device */ + layout = (AudioChannelLayout *) g_malloc (propertySize); + status = AudioObjectGetPropertyData (device_id, + &channelLayoutAddress, 0, NULL, &propertySize, layout); + if (status != noErr) { + GST_ERROR ("failed to get prefered layout: %d", (int) status); + goto failed; + } + + if (layout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap) { + /* bitmap defined channellayout */ + status = + AudioFormatGetProperty (kAudioFormatProperty_ChannelLayoutForBitmap, + sizeof (UInt32), &layout->mChannelBitmap, &propertySize, layout); + if (status != noErr) { + GST_ERROR ("failed to get layout for bitmap: %d", (int) status); + goto failed; + } + } else if (layout->mChannelLayoutTag != + kAudioChannelLayoutTag_UseChannelDescriptions) { + /* layouttags defined channellayout */ + status = AudioFormatGetProperty (kAudioFormatProperty_ChannelLayoutForTag, + sizeof (AudioChannelLayoutTag), &layout->mChannelLayoutTag, + &propertySize, layout); + if (status != noErr) { + GST_ERROR ("failed to get layout for tag: %d", (int) status); + goto failed; + } + } + + gst_core_audio_dump_channel_layout (layout); + +beach: + return layout; + +failed: + g_free (layout); + return NULL; +} + +static inline AudioStreamID * +_audio_device_get_streams (AudioDeviceID device_id, gint * nstreams) +{ + OSStatus status = noErr; + UInt32 propertySize = 0; + AudioStreamID *streams = NULL; + + AudioObjectPropertyAddress streamsAddress = { + kAudioDevicePropertyStreams, + kAudioDevicePropertyScopeOutput, + kAudioObjectPropertyElementMaster + }; + + status = AudioObjectGetPropertyDataSize (device_id, + &streamsAddress, 0, NULL, &propertySize); + if (status != noErr) { + GST_WARNING ("failed getting number of streams: %d", (int) status); + return NULL; + } + + *nstreams = propertySize / sizeof (AudioStreamID); + streams = (AudioStreamID *) g_malloc (propertySize); + + if (streams) { + status = AudioObjectGetPropertyData (device_id, + &streamsAddress, 0, NULL, &propertySize, streams); + if (status != noErr) { + GST_WARNING ("failed getting the list of streams: %d", (int) status); + g_free (streams); + *nstreams = 0; + return NULL; + } + } + + return streams; +} + +static inline guint +_audio_stream_get_latency (AudioStreamID stream_id) +{ + OSStatus status = noErr; + UInt32 latency; + UInt32 propertySize = sizeof (latency); + + AudioObjectPropertyAddress latencyAddress = { + kAudioStreamPropertyLatency, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster + }; + + status = AudioObjectGetPropertyData (stream_id, + &latencyAddress, 0, NULL, &propertySize, &latency); + if (status != noErr) { + GST_ERROR ("failed to get latency: %d", (int) status); + latency = -1; + } + + return latency; +} + +static inline gboolean +_audio_stream_get_current_format (AudioStreamID stream_id, + AudioStreamBasicDescription * format) +{ + OSStatus status = noErr; + UInt32 propertySize = sizeof (AudioStreamBasicDescription); + + AudioObjectPropertyAddress formatAddress = { + kAudioStreamPropertyPhysicalFormat, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster + }; + + status = AudioObjectGetPropertyData (stream_id, + &formatAddress, 0, NULL, &propertySize, format); + if (status != noErr) { + GST_ERROR ("failed to get current format: %d", (int) status); + return FALSE; + } + + return TRUE; +} + +static inline gboolean +_audio_stream_set_current_format (AudioStreamID stream_id, + AudioStreamBasicDescription format) +{ + OSStatus status = noErr; + UInt32 propertySize = sizeof (AudioStreamBasicDescription); + + AudioObjectPropertyAddress formatAddress = { + kAudioStreamPropertyPhysicalFormat, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster + }; + + status = AudioObjectSetPropertyData (stream_id, + &formatAddress, 0, NULL, propertySize, &format); + if (status != noErr) { + GST_ERROR ("failed to set current format: %d", (int) status); + return FALSE; + } + + return TRUE; +} + +static inline AudioStreamRangedDescription * +_audio_stream_get_formats (AudioStreamID stream_id, gint * nformats) +{ + OSStatus status = noErr; + UInt32 propertySize = 0; + AudioStreamRangedDescription *formats = NULL; + + AudioObjectPropertyAddress formatsAddress = { + kAudioStreamPropertyAvailablePhysicalFormats, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster + }; + + status = AudioObjectGetPropertyDataSize (stream_id, + &formatsAddress, 0, NULL, &propertySize); + if (status != noErr) { + GST_WARNING ("failed getting number of stream formats: %d", (int) status); + return NULL; + } + + *nformats = propertySize / sizeof (AudioStreamRangedDescription); + + formats = (AudioStreamRangedDescription *) g_malloc (propertySize); + if (formats) { + status = AudioObjectGetPropertyData (stream_id, + &formatsAddress, 0, NULL, &propertySize, formats); + if (status != noErr) { + GST_WARNING ("failed getting the list of stream formats: %d", + (int) status); + g_free (formats); + *nformats = 0; + return NULL; + } + } + return formats; +} + +static inline gboolean +_audio_stream_is_spdif_avail (AudioStreamID stream_id) +{ + AudioStreamRangedDescription *formats; + gint i, nformats = 0; + gboolean res = FALSE; + + formats = _audio_stream_get_formats (stream_id, &nformats); + GST_DEBUG ("found %d stream formats", nformats); + + if (formats) { + GST_DEBUG ("formats supported on stream ID: %u", (unsigned) stream_id); + + for (i = 0; i < nformats; i++) { + GST_DEBUG (" " CORE_AUDIO_FORMAT, + CORE_AUDIO_FORMAT_ARGS (formats[i].mFormat)); + + if (CORE_AUDIO_FORMAT_IS_SPDIF (formats[i])) { + res = TRUE; + } + } + g_free (formats); + } + + return res; +} + +static OSStatus +_audio_stream_format_listener (AudioObjectID inObjectID, + UInt32 inNumberAddresses, + const AudioObjectPropertyAddress inAddresses[], void *inClientData) +{ + OSStatus status = noErr; + guint i; + PropertyMutex *prop_mutex = inClientData; + + for (i = 0; i < inNumberAddresses; i++) { + if (inAddresses[i].mSelector == kAudioStreamPropertyPhysicalFormat) { + g_mutex_lock (&prop_mutex->lock); + g_cond_signal (&prop_mutex->cond); + g_mutex_unlock (&prop_mutex->lock); + break; + } + } + return (status); +} + +static gboolean +_audio_stream_change_format (AudioStreamID stream_id, + AudioStreamBasicDescription format) +{ + OSStatus status = noErr; + gint i; + gboolean ret = FALSE; + AudioStreamBasicDescription cformat; + PropertyMutex prop_mutex; + + AudioObjectPropertyAddress formatAddress = { + kAudioStreamPropertyPhysicalFormat, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster + }; + + GST_DEBUG ("setting stream format: " CORE_AUDIO_FORMAT, + CORE_AUDIO_FORMAT_ARGS (format)); + + /* Condition because SetProperty is asynchronous */ + g_mutex_init (&prop_mutex.lock); + g_cond_init (&prop_mutex.cond); + + g_mutex_lock (&prop_mutex.lock); + + /* Install the property listener to serialize the operations */ + status = AudioObjectAddPropertyListener (stream_id, &formatAddress, + _audio_stream_format_listener, (void *) &prop_mutex); + if (status != noErr) { + GST_ERROR ("AudioObjectAddPropertyListener failed: %d", (int) status); + goto done; + } + + /* Change the format */ + if (!_audio_stream_set_current_format (stream_id, format)) { + goto done; + } + + /* The AudioObjectSetProperty is not only asynchronous + * it is also not atomic in its behaviour. + * Therefore we check 4 times before we really give up. */ + for (i = 0; i < 4; i++) { + GTimeVal timeout; + + g_get_current_time (&timeout); + g_time_val_add (&timeout, 250000); + + if (!g_cond_wait_until (&prop_mutex.cond, &prop_mutex.lock, timeout.tv_sec)) { + GST_LOG ("timeout..."); + } + + if (_audio_stream_get_current_format (stream_id, &cformat)) { + GST_DEBUG ("current stream format: " CORE_AUDIO_FORMAT, + CORE_AUDIO_FORMAT_ARGS (cformat)); + + if (cformat.mSampleRate == format.mSampleRate && + cformat.mFormatID == format.mFormatID && + cformat.mFramesPerPacket == format.mFramesPerPacket) { + /* The right format is now active */ + break; + } + } + } + + if (cformat.mSampleRate != format.mSampleRate || + cformat.mFormatID != format.mFormatID || + cformat.mFramesPerPacket != format.mFramesPerPacket) { + goto done; + } + + ret = TRUE; + +done: + /* Removing the property listener */ + status = AudioObjectRemovePropertyListener (stream_id, + &formatAddress, _audio_stream_format_listener, (void *) &prop_mutex); + if (status != noErr) { + GST_ERROR ("AudioObjectRemovePropertyListener failed: %d", (int) status); + } + /* Destroy the lock and condition */ + g_mutex_unlock (&prop_mutex.lock); + g_mutex_clear (&prop_mutex.lock); + g_cond_clear (&prop_mutex.cond); + + return ret; +} + +static OSStatus +_audio_stream_hardware_changed_listener (AudioObjectID inObjectID, + UInt32 inNumberAddresses, + const AudioObjectPropertyAddress inAddresses[], void *inClientData) +{ + OSStatus status = noErr; + guint i; + GstCoreAudio *core_audio = inClientData; + + for (i = 0; i < inNumberAddresses; i++) { + if (inAddresses[i].mSelector == kAudioDevicePropertyDeviceHasChanged) { + if (!gst_core_audio_audio_device_is_spdif_avail (core_audio->device_id)) { + GstOsxAudioSink *sink = + GST_OSX_AUDIO_SINK (GST_OBJECT_PARENT (core_audio->osxbuf)); + GST_ELEMENT_ERROR (sink, RESOURCE, FAILED, + ("SPDIF output no longer available"), + ("Audio device is reporting that SPDIF output isn't available")); + } + break; + } + } + return (status); +} + +static inline gboolean +_monitorize_spdif (GstCoreAudio * core_audio) +{ + OSStatus status = noErr; + gboolean ret = TRUE; + + AudioObjectPropertyAddress propAddress = { + kAudioDevicePropertyDeviceHasChanged, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster + }; + + /* Install the property listener */ + status = AudioObjectAddPropertyListener (core_audio->device_id, + &propAddress, _audio_stream_hardware_changed_listener, + (void *) core_audio); + if (status != noErr) { + GST_ERROR_OBJECT (core_audio->osxbuf, + "AudioObjectAddPropertyListener failed: %d", (int) status); + ret = FALSE; + } + + return ret; +} + +static inline gboolean +_unmonitorize_spdif (GstCoreAudio * core_audio) +{ + OSStatus status = noErr; + gboolean ret = TRUE; + + AudioObjectPropertyAddress propAddress = { + kAudioDevicePropertyDeviceHasChanged, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster + }; + + /* Remove the property listener */ + status = AudioObjectRemovePropertyListener (core_audio->device_id, + &propAddress, _audio_stream_hardware_changed_listener, + (void *) core_audio); + if (status != noErr) { + GST_ERROR_OBJECT (core_audio->osxbuf, + "AudioObjectRemovePropertyListener failed: %d", (int) status); + ret = FALSE; + } + + return ret; +} + +static inline gboolean +_open_spdif (GstCoreAudio * core_audio) +{ + gboolean res = FALSE; + pid_t hog_pid, own_pid = getpid (); + + /* We need the device in exclusive and disable the mixing */ + hog_pid = _audio_device_get_hog (core_audio->device_id); + + if (hog_pid != -1 && hog_pid != own_pid) { + GST_DEBUG_OBJECT (core_audio, + "device is currently in use by another application"); + goto done; + } + + if (_audio_device_set_hog (core_audio->device_id, own_pid)) { + core_audio->hog_pid = own_pid; + } + + if (_audio_device_set_mixing (core_audio->device_id, FALSE)) { + GST_DEBUG_OBJECT (core_audio, "disabled mixing on the device"); + core_audio->disabled_mixing = TRUE; + } + + res = TRUE; +done: + return res; +} + +static inline gboolean +_close_spdif (GstCoreAudio * core_audio) +{ + pid_t hog_pid; + + _unmonitorize_spdif (core_audio); + + if (core_audio->revert_format) { + if (!_audio_stream_change_format (core_audio->stream_id, + core_audio->original_format)) { + GST_WARNING_OBJECT (core_audio->osxbuf, "Format revert failed"); + } + core_audio->revert_format = FALSE; + } + + if (core_audio->disabled_mixing) { + _audio_device_set_mixing (core_audio->device_id, TRUE); + core_audio->disabled_mixing = FALSE; + } + + if (core_audio->hog_pid != -1) { + hog_pid = _audio_device_get_hog (core_audio->device_id); + if (hog_pid == getpid ()) { + if (_audio_device_set_hog (core_audio->device_id, -1)) { + core_audio->hog_pid = -1; + } + } + } + + return TRUE; +} + +static OSStatus +_io_proc_spdif (AudioDeviceID inDevice, + const AudioTimeStamp * inNow, + const void *inInputData, + const AudioTimeStamp * inTimestamp, + AudioBufferList * bufferList, + const AudioTimeStamp * inOutputTime, GstCoreAudio * core_audio) +{ + OSStatus status; + + status = core_audio->element->io_proc (core_audio->osxbuf, NULL, inTimestamp, + 0, 0, bufferList); + + return status; +} + +static inline gboolean +_acquire_spdif (GstCoreAudio * core_audio, AudioStreamBasicDescription format) +{ + AudioStreamID *streams = NULL; + gint i, j, nstreams = 0; + gboolean ret = FALSE; + + if (!_open_spdif (core_audio)) + goto done; + + streams = _audio_device_get_streams (core_audio->device_id, &nstreams); + + for (i = 0; i < nstreams; i++) { + AudioStreamRangedDescription *formats = NULL; + gint nformats = 0; + + formats = _audio_stream_get_formats (streams[i], &nformats); + + if (formats) { + gboolean is_spdif = FALSE; + + /* Check if one of the supported formats is a digital format */ + for (j = 0; j < nformats; j++) { + if (CORE_AUDIO_FORMAT_IS_SPDIF (formats[j])) { + is_spdif = TRUE; + break; + } + } + + if (is_spdif) { + /* if this stream supports a digital (cac3) format, + * then go set it. */ + gint requested_rate_format = -1; + gint current_rate_format = -1; + gint backup_rate_format = -1; + + core_audio->stream_id = streams[i]; + core_audio->stream_idx = i; + + if (!core_audio->revert_format) { + if (!_audio_stream_get_current_format (core_audio->stream_id, + &core_audio->original_format)) { + GST_WARNING_OBJECT (core_audio->osxbuf, + "format could not be saved"); + g_free (formats); + continue; + } + core_audio->revert_format = TRUE; + } + + for (j = 0; j < nformats; j++) { + if (CORE_AUDIO_FORMAT_IS_SPDIF (formats[j])) { + GST_LOG_OBJECT (core_audio->osxbuf, + "found stream format: " CORE_AUDIO_FORMAT, + CORE_AUDIO_FORMAT_ARGS (formats[j].mFormat)); + + if (formats[j].mFormat.mSampleRate == format.mSampleRate) { + requested_rate_format = j; + break; + } else if (formats[j].mFormat.mSampleRate == + core_audio->original_format.mSampleRate) { + current_rate_format = j; + } else { + if (backup_rate_format < 0 || + formats[j].mFormat.mSampleRate > + formats[backup_rate_format].mFormat.mSampleRate) { + backup_rate_format = j; + } + } + } + } + + if (requested_rate_format >= 0) { + /* We prefer to output at the rate of the original audio */ + core_audio->stream_format = formats[requested_rate_format].mFormat; + } else if (current_rate_format >= 0) { + /* If not possible, we will try to use the current rate */ + core_audio->stream_format = formats[current_rate_format].mFormat; + } else { + /* And if we have to, any digital format will be just + * fine (highest rate possible) */ + core_audio->stream_format = formats[backup_rate_format].mFormat; + } + } + g_free (formats); + } + } + g_free (streams); + + GST_DEBUG_OBJECT (core_audio, + "original stream format: " CORE_AUDIO_FORMAT, + CORE_AUDIO_FORMAT_ARGS (core_audio->original_format)); + + if (!_audio_stream_change_format (core_audio->stream_id, + core_audio->stream_format)) + goto done; + + ret = TRUE; + +done: + return ret; +} + +static inline void +_remove_render_spdif_callback (GstCoreAudio * core_audio) +{ + OSStatus status; + + /* Deactivate the render callback by calling + * AudioDeviceDestroyIOProcID */ + status = + AudioDeviceDestroyIOProcID (core_audio->device_id, core_audio->procID); + if (status != noErr) { + GST_ERROR_OBJECT (core_audio->osxbuf, + "AudioDeviceDestroyIOProcID failed: %d", (int) status); + } + + GST_DEBUG_OBJECT (core_audio, + "osx ring buffer removed ioproc ID: %p device_id %lu", + core_audio->procID, (gulong) core_audio->device_id); + + /* We're deactivated.. */ + core_audio->procID = 0; + core_audio->io_proc_needs_deactivation = FALSE; + core_audio->io_proc_active = FALSE; +} + +static inline gboolean +_io_proc_spdif_start (GstCoreAudio * core_audio) +{ + OSErr status; + + GST_DEBUG_OBJECT (core_audio, + "osx ring buffer start ioproc ID: %p device_id %lu", + core_audio->procID, (gulong) core_audio->device_id); + + if (!core_audio->io_proc_active) { + /* Add IOProc callback */ + status = AudioDeviceCreateIOProcID (core_audio->device_id, + (AudioDeviceIOProc) _io_proc_spdif, + (void *) core_audio, &core_audio->procID); + if (status != noErr) { + GST_ERROR_OBJECT (core_audio->osxbuf, + ":AudioDeviceCreateIOProcID failed: %d", (int) status); + return FALSE; + } + core_audio->io_proc_active = TRUE; + } + + core_audio->io_proc_needs_deactivation = FALSE; + + /* Start device */ + status = AudioDeviceStart (core_audio->device_id, core_audio->procID); + if (status != noErr) { + GST_ERROR_OBJECT (core_audio->osxbuf, + "AudioDeviceStart failed: %d", (int) status); + return FALSE; + } + return TRUE; +} + +static inline gboolean +_io_proc_spdif_stop (GstCoreAudio * core_audio) +{ + OSErr status; + + /* Stop device */ + status = AudioDeviceStop (core_audio->device_id, core_audio->procID); + if (status != noErr) { + GST_ERROR_OBJECT (core_audio->osxbuf, + "AudioDeviceStop failed: %d", (int) status); + } + + GST_DEBUG_OBJECT (core_audio, + "osx ring buffer stop ioproc ID: %p device_id %lu", + core_audio->procID, (gulong) core_audio->device_id); + + if (core_audio->io_proc_active) { + _remove_render_spdif_callback (core_audio); + } + + _close_spdif (core_audio); + + return TRUE; +} + + +/*********************** + * Implementation * + **********************/ + +static gboolean +gst_core_audio_open_impl (GstCoreAudio * core_audio) +{ + /* The following is needed to instruct HAL to create their own + * thread to handle the notifications. */ + _audio_system_set_runloop (NULL); + + /* Create a HALOutput AudioUnit. + * This is the lowest-level output API that is actually sensibly + * usable (the lower level ones require that you do + * channel-remapping yourself, and the CoreAudio channel mapping + * is sufficiently complex that doing so would be very difficult) + * + * Note that for input we request an output unit even though + * we will do input with it. + * http://developer.apple.com/technotes/tn2002/tn2091.html + */ + return gst_core_audio_open_device (core_audio, kAudioUnitSubType_HALOutput, + "HALOutput"); +} + +static gboolean +gst_core_audio_start_processing_impl (GstCoreAudio * core_audio) +{ + if (core_audio->is_passthrough) { + return _io_proc_spdif_start (core_audio); + } else { + return gst_core_audio_io_proc_start (core_audio); + } +} + +static gboolean +gst_core_audio_pause_processing_impl (GstCoreAudio * core_audio) +{ + if (core_audio->is_passthrough) { + GST_DEBUG_OBJECT (core_audio, + "osx ring buffer pause ioproc ID: %p device_id %lu", + core_audio->procID, (gulong) core_audio->device_id); + + if (core_audio->io_proc_active) { + _remove_render_spdif_callback (core_audio); + } + } else { + GST_DEBUG_OBJECT (core_audio, + "osx ring buffer pause ioproc: %p device_id %lu", + core_audio->element->io_proc, (gulong) core_audio->device_id); + if (core_audio->io_proc_active) { + /* CoreAudio isn't threadsafe enough to do this here; + * we must deactivate the render callback elsewhere. See: + * http://lists.apple.com/archives/Coreaudio-api/2006/Mar/msg00010.html + */ + core_audio->io_proc_needs_deactivation = TRUE; + } + } + return TRUE; +} + +static gboolean +gst_core_audio_stop_processing_impl (GstCoreAudio * core_audio) +{ + if (core_audio->is_passthrough) { + _io_proc_spdif_stop (core_audio); + } else { + gst_core_audio_io_proc_stop (core_audio); + } + + return TRUE; +} + +static gboolean +gst_core_audio_get_samples_and_latency_impl (GstCoreAudio * core_audio, + gdouble rate, guint * samples, gdouble * latency) +{ + OSStatus status; + UInt32 size = sizeof (double); + + if (core_audio->is_passthrough) { + *samples = _audio_device_get_latency (core_audio->device_id); + *samples += _audio_stream_get_latency (core_audio->stream_id); + *latency = (double) *samples / rate; + } else { + status = AudioUnitGetProperty (core_audio->audiounit, kAudioUnitProperty_Latency, kAudioUnitScope_Global, 0, /* N/A for global */ + latency, &size); + + if (status) { + GST_WARNING_OBJECT (core_audio->osxbuf, "Failed to get latency: %d", + (int) status); + *samples = 0; + return FALSE; + } + + *samples = *latency * rate; + } + return TRUE; +} + +static gboolean +gst_core_audio_initialize_impl (GstCoreAudio * core_audio, + AudioStreamBasicDescription format, GstCaps * caps, + gboolean is_passthrough, guint32 * frame_size) +{ + gboolean ret = FALSE; + + core_audio->is_passthrough = is_passthrough; + if (is_passthrough) { + if (!_acquire_spdif (core_audio, format)) + goto done; + _monitorize_spdif (core_audio); + } else { + OSStatus status; + UInt32 propertySize; + + core_audio->stream_idx = 0; + if (!gst_core_audio_set_format (core_audio, format)) + goto done; + + if (!gst_core_audio_set_channels_layout (core_audio, + format.mChannelsPerFrame, caps)) + goto done; + + if (!gst_core_audio_bind_device (core_audio)) + goto done; + + if (core_audio->is_src) { + propertySize = sizeof (*frame_size); + status = AudioUnitGetProperty (core_audio->audiounit, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Global, 0, /* N/A for global */ + frame_size, &propertySize); + + if (status) { + GST_WARNING_OBJECT (core_audio->osxbuf, "Failed to get frame size: %d", + (int) status); + goto done; + } + } + } + + ret = TRUE; + +done: + if (ret) { + GST_DEBUG_OBJECT (core_audio, "osxbuf ring buffer acquired"); + } + return ret; +} + +static gboolean +gst_core_audio_select_device_impl (AudioDeviceID * device_id) +{ + AudioDeviceID *devices = NULL; + AudioDeviceID default_device_id = 0; + AudioChannelLayout *channel_layout; + gint i, ndevices = 0; + gboolean res = FALSE; + + devices = _audio_system_get_devices (&ndevices); + + if (ndevices < 1) { + GST_ERROR ("no audio output devices found"); + goto done; + } + + GST_DEBUG ("found %d audio device(s)", ndevices); + + for (i = 0; i < ndevices; i++) { + gchar *device_name; + + if ((device_name = _audio_device_get_name (devices[i]))) { + if (!_audio_device_has_output (devices[i])) { + GST_DEBUG ("Input Device ID: %u Name: %s", + (unsigned) devices[i], device_name); + } else { + GST_DEBUG ("Output Device ID: %u Name: %s", + (unsigned) devices[i], device_name); + + channel_layout = + gst_core_audio_audio_device_get_channel_layout (devices[i]); + if (channel_layout) { + gst_core_audio_dump_channel_layout (channel_layout); + g_free (channel_layout); + } + } + + g_free (device_name); + } + } + + /* Find the ID of the default output device */ + default_device_id = _audio_system_get_default_output (); + + /* Here we decide if selected device is valid or autoselect + * the default one when required */ + if (*device_id == kAudioDeviceUnknown) { + if (default_device_id != kAudioDeviceUnknown) { + *device_id = default_device_id; + res = TRUE; + } + } else { + for (i = 0; i < ndevices; i++) { + if (*device_id == devices[i]) { + res = TRUE; + } + } + + if (res && !_audio_device_is_alive (*device_id)) { + GST_ERROR ("Requested device not usable"); + res = FALSE; + goto done; + } + } + +done: + g_free (devices); + return res; +} + +static gboolean +gst_core_audio_audio_device_is_spdif_avail_impl (AudioDeviceID device_id) +{ + AudioStreamID *streams = NULL; + gint i, nstreams = 0; + gboolean res = FALSE; + + streams = _audio_device_get_streams (device_id, &nstreams); + GST_DEBUG ("found %d streams", nstreams); + if (streams) { + for (i = 0; i < nstreams; i++) { + if (_audio_stream_is_spdif_avail (streams[i])) { + res = TRUE; + } + } + + g_free (streams); + } + + return res; +} + +static gboolean +gst_core_audio_select_source_device_impl (AudioDeviceID * device_id) +{ + OSStatus status; + UInt32 propertySize; + + if (*device_id == kAudioDeviceUnknown) { + /* If no specific device has been selected by the user, then pick the + * default device */ + GST_DEBUG ("Selecting device for OSXAudioSrc"); + propertySize = sizeof (*device_id); + status = AudioHardwareGetProperty (kAudioHardwarePropertyDefaultInputDevice, + &propertySize, device_id); + + if (status) { + GST_WARNING ("AudioHardwareGetProperty returned %d", (int) status); + } else { + GST_DEBUG ("AudioHardwareGetProperty returned 0"); + } + + if (*device_id == kAudioDeviceUnknown) { + GST_WARNING ("AudioHardwareGetProperty: device_id is " + "kAudioDeviceUnknown"); + } + + GST_DEBUG ("AudioHardwareGetProperty: device_id is %lu", (long) *device_id); + } + + return TRUE; +} diff --git a/sys/osxaudio/gstosxcoreaudioremoteio.c b/sys/osxaudio/gstosxcoreaudioremoteio.c new file mode 100755 index 0000000..dd97aa1 --- /dev/null +++ b/sys/osxaudio/gstosxcoreaudioremoteio.c @@ -0,0 +1,126 @@ +/* + * GStreamer + * Copyright (C) 2012 Fluendo S.A. <support@fluendo.com> + * Authors: Andoni Morales Alastruey <amorales@fluendo.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#import <AudioUnit/AUComponent.h> + +static gboolean +gst_core_audio_open_impl (GstCoreAudio * core_audio) +{ + return gst_core_audio_open_device (core_audio, kAudioUnitSubType_RemoteIO, + "RemoteIO"); +} + +static gboolean +gst_core_audio_start_processing_impl (GstCoreAudio * core_audio) +{ + return gst_core_audio_io_proc_start (core_audio); +} + +static gboolean +gst_core_audio_pause_processing_impl (GstCoreAudio * core_audio) +{ + GST_DEBUG_OBJECT (core_audio, + "osx ring buffer pause ioproc: %p device_id %lu", + core_audio->element->io_proc, (gulong) core_audio->device_id); + + if (core_audio->io_proc_active) { + /* CoreAudio isn't threadsafe enough to do this here; + * we must deactivate the render callback elsewhere. See: + * http://lists.apple.com/archives/Coreaudio-api/2006/Mar/msg00010.html + */ + core_audio->io_proc_needs_deactivation = TRUE; + } + return TRUE; +} + +static gboolean +gst_core_audio_stop_processing_impl (GstCoreAudio * core_audio) +{ + gst_core_audio_io_proc_stop (core_audio); + return TRUE; +} + +static gboolean +gst_core_audio_get_samples_and_latency_impl (GstCoreAudio * core_audio, + gdouble rate, guint * samples, gdouble * latency) +{ + OSStatus status; + UInt32 size; + + status = AudioUnitGetProperty (core_audio->audiounit, kAudioUnitProperty_Latency, kAudioUnitScope_Global, 0, /* N/A for global */ + latency, &size); + + if (status) { + GST_WARNING_OBJECT (core_audio, "Failed to get latency: %d", (int) status); + *samples = 0; + return FALSE; + } + + *samples = *latency * rate; + return TRUE; +} + +static gboolean +gst_core_audio_initialize_impl (GstCoreAudio * core_audio, + AudioStreamBasicDescription format, GstCaps * caps, + gboolean is_passthrough, guint32 * frame_size) +{ + core_audio->is_passthrough = is_passthrough; + core_audio->stream_idx = 0; + if (!gst_core_audio_set_format (core_audio, format)) + return FALSE; + + /* FIXME: Use kAudioSessionProperty_CurrentHardwareSampleRate and + * kAudioSessionProperty_CurrentHardwareIOBufferDuration with property + * listeners to detect changes in screen locks. + * For now use the maximum value */ + *frame_size = 4196; + + GST_DEBUG_OBJECT (core_audio, "osxbuf ring buffer acquired"); + return TRUE; +} + +AudioChannelLayout * +gst_core_audio_audio_device_get_channel_layout (AudioDeviceID device_id) +{ + return NULL; +} + +static gboolean +gst_core_audio_select_device_impl (AudioDeviceID * device_id) +{ + /* No device selection in iOS */ + return TRUE; +} + +static gboolean +gst_core_audio_select_source_device_impl (AudioDeviceID * device_id) +{ + return TRUE; +} + +static gboolean +gst_core_audio_audio_device_is_spdif_avail_impl (AudioDeviceID device_id) +{ + /* No SPDIF in iOS */ + return FALSE; +} |