diff --git a/Makefile.in b/Makefile.in index 3f3fb4a..26273cd 100644 --- a/Makefile.in +++ b/Makefile.in @@ -107,6 +107,7 @@ TESTS = \ bin/patest_wire \ bin/patest_write_sine \ bin/patest_write_sine_nonint \ + bin/patest_update_available_device_list \ bin/pa_devs \ bin/pa_fuzz \ bin/pa_minlat @@ -146,6 +147,7 @@ SRC_DIRS = \ src/hostapi/wdmks \ src/hostapi/wmme \ src/os/unix \ + src/os/mac_osx \ src/os/win SUBDIRS = diff --git a/aclocal.m4 b/aclocal.m4 index 54a5978..9a60566 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -680,7 +680,7 @@ _LT_CONFIG_SAVE_COMMANDS([ # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST - fi +fi cfgfile="${ofile}T" trap "$RM \"$cfgfile\"; exit 1" 1 2 15 @@ -1101,104 +1101,104 @@ fi (unset CDPATH) >/dev/null 2>&1 && unset CDPATH if test -z "$lt_ECHO"; then - if test "X${echo_test_string+set}" != Xset; then - # find a string as large as possible, as long as the shell can cope with it - for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do - # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... +if test "X${echo_test_string+set}" != Xset; then +# find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... if { echo_test_string=`eval $cmd`; } 2>/dev/null && { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null - then - break - fi - done - fi + then + break + fi + done +fi if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - : - else - # The Solaris, AIX, and Digital Unix default echo programs unquote - # backslashes. This makes it impossible to quote backslashes using - # echo "$something" | sed 's/\\/\\\\/g' - # - # So, first we look for a working echo in the user's PATH. + test "X$echo_testing_string" = "X$echo_test_string"; then + : +else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. - lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR - for dir in $PATH /usr/ucb; do - IFS="$lt_save_ifs" - if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && - test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && - echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - ECHO="$dir/echo" - break - fi - done + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do IFS="$lt_save_ifs" + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + ECHO="$dir/echo" + break + fi + done + IFS="$lt_save_ifs" if test "X$ECHO" = Xecho; then - # We didn't find a better echo, so look for alternatives. + # We didn't find a better echo, so look for alternatives. if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' && echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - # This shell has a builtin print -r that does the trick. + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. ECHO='print -r' elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } && - test "X$CONFIG_SHELL" != X/bin/ksh; then - # If we have ksh, try running configure again with it. - ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} - export ORIGINAL_CONFIG_SHELL - CONFIG_SHELL=/bin/ksh - export CONFIG_SHELL - exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} - else - # Try using printf. + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} + else + # Try using printf. ECHO='printf %s\n' if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then - # Cool, printf works - : - elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && - test "X$echo_testing_string" = 'X\t' && - echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL - export CONFIG_SHELL - SHELL="$CONFIG_SHELL" - export SHELL + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL ECHO="$CONFIG_SHELL [$]0 --fallback-echo" - elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && - test "X$echo_testing_string" = 'X\t' && - echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then + elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then ECHO="$CONFIG_SHELL [$]0 --fallback-echo" - else - # maybe with a smaller string... - prev=: + else + # maybe with a smaller string... + prev=: - for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do + for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null - then - break - fi - prev="$cmd" - done - - if test "$prev" != 'sed 50q "[$]0"'; then - echo_test_string=`eval $prev` - export echo_test_string - exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} - else - # Oops. We lost completely, so just stick with echo. - ECHO=echo + then + break fi - fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "[$]0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} + else + # Oops. We lost completely, so just stick with echo. + ECHO=echo + fi fi fi fi fi +fi # Copy echo and quote the copy suitably for passing to libtool from # the Makefile, instead of quoting the original, which is used later. @@ -1220,7 +1220,7 @@ _LT_DECL([], [ECHO], [1], m4_defun([_LT_ENABLE_LOCK], [AC_ARG_ENABLE([libtool-lock], [AS_HELP_STRING([--disable-libtool-lock], - [avoid locking (might break parallel builds)])]) + [avoid locking (might break parallel builds)])]) test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good @@ -1231,12 +1231,12 @@ ia64-*-hpux*) echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.$ac_objext` in - *ELF-32*) - HPUX_IA64_MODE="32" - ;; - *ELF-64*) - HPUX_IA64_MODE="64" - ;; + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; esac fi rm -rf conftest* @@ -1245,31 +1245,31 @@ ia64-*-hpux*) # Find out which ABI we are using. echo '[#]line __oline__ "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then - if test "$lt_cv_prog_gnu_ld" = yes; then - case `/usr/bin/file conftest.$ac_objext` in - *32-bit*) - LD="${LD-ld} -melf32bsmip" - ;; - *N32*) - LD="${LD-ld} -melf32bmipn32" - ;; - *64-bit*) - LD="${LD-ld} -melf64bmip" - ;; - esac - else - case `/usr/bin/file conftest.$ac_objext` in - *32-bit*) - LD="${LD-ld} -32" - ;; - *N32*) - LD="${LD-ld} -n32" - ;; - *64-bit*) - LD="${LD-ld} -64" - ;; - esac - fi + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi fi rm -rf conftest* ;; @@ -1280,44 +1280,44 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in - *32-bit*) - case $host in + *32-bit*) + case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; - x86_64-*linux*) - LD="${LD-ld} -m elf_i386" - ;; - ppc64-*linux*|powerpc64-*linux*) - LD="${LD-ld} -m elf32ppclinux" - ;; - s390x-*linux*) - LD="${LD-ld} -m elf_s390" - ;; - sparc64-*linux*) - LD="${LD-ld} -m elf32_sparc" - ;; - esac - ;; - *64-bit*) - case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; - x86_64-*linux*) - LD="${LD-ld} -m elf_x86_64" - ;; - ppc*-*linux*|powerpc*-*linux*) - LD="${LD-ld} -m elf64ppc" - ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; s390*-*linux*|s390*-*tpf*) - LD="${LD-ld} -m elf64_s390" - ;; - sparc*-*linux*) - LD="${LD-ld} -m elf64_sparc" - ;; - esac - ;; + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; esac fi rm -rf conftest* @@ -1454,7 +1454,7 @@ dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) # _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, -# [ACTION-SUCCESS], [ACTION-FAILURE]) +# [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------- # Check whether the given linker option works AC_DEFUN([_LT_LINKER_OPTION], @@ -1578,7 +1578,7 @@ AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then - lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` else lt_cv_sys_max_cmd_len=32768 fi @@ -1595,23 +1595,23 @@ AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} - # If test is not a shell built-in, we'll probably end up computing a - # maximum length that is only half of the actual maximum length, but - # we can't tell. + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. while { test "X"`$SHELL [$]0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \ = "XX$teststring$teststring"; } >/dev/null 2>&1 && - test $i != 17 # 1/2 MB should be enough - do - i=`expr $i + 1` - teststring=$teststring$teststring - done + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` - teststring= + teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac @@ -1640,7 +1640,7 @@ m4_defun([_LT_HEADER_DLFCN], # _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, -# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) # ---------------------------------------------------------------- m4_defun([_LT_TRY_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl @@ -1748,12 +1748,12 @@ else mingw* | pw32* | cegcc*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= - ;; + ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= - ;; + ;; darwin*) # if libdl is installed we need to link against it @@ -1763,7 +1763,7 @@ else lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ]) - ;; + ;; *) AC_CHECK_FUNC([shl_load], @@ -1813,7 +1813,7 @@ else if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" AC_CACHE_CHECK([whether a statically linked program can dlopen itself], - lt_cv_dlopen_self_static, [dnl + lt_cv_dlopen_self_static, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) @@ -2016,17 +2016,17 @@ if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in - darwin*) - if test -n "$STRIP" ; then - striplib="$STRIP -x" + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" old_striplib="$STRIP -S" - AC_MSG_RESULT([yes]) - else - AC_MSG_RESULT([no]) - fi - ;; - *) - AC_MSG_RESULT([no]) + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) +fi + ;; + *) + AC_MSG_RESULT([no]) ;; esac fi @@ -2180,10 +2180,10 @@ amigaos*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) - library_names_spec='$libname.ixlibrary $libname.a' - # Create ${libname}_ixlibrary.a entries in /sys/libs. + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' - ;; + ;; esac ;; @@ -2218,7 +2218,7 @@ cygwin* | mingw* | pw32* | cegcc*) library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ @@ -2373,18 +2373,18 @@ hpux9* | hpux10* | hpux11*) fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; - hppa*64*) - shrext_cmds='.sl' - hardcode_into_libs=yes - dynamic_linker="$host_os dld.sl" - shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH - shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - ;; - *) + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH @@ -2547,8 +2547,8 @@ openbsd*) need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in - openbsd3.3 | openbsd3.3.*) need_version=yes ;; - *) need_version=no ;; + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' @@ -2702,10 +2702,10 @@ fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" -fi + fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" -fi + fi _LT_DECL([], [variables_saved_for_relink], [1], [Variables whose values should be saved in libtool wrapper scripts and @@ -3022,8 +3022,8 @@ mingw* | pw32*) lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else - lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' - lt_cv_file_magic_cmd='$OBJDUMP -f' + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; @@ -3191,7 +3191,7 @@ AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, lt_cv_path_NM="$NM" else lt_nm_to_check="${ac_tool_prefix}nm" - if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do @@ -3230,7 +3230,7 @@ else : ${lt_cv_path_NM=no} fi]) if test "$lt_cv_path_NM" != "no"; then - NM="$lt_cv_path_NM" +NM="$lt_cv_path_NM" else # Didn't find any BSD compatible name lister, look for dumpbin. AC_CHECK_TOOLS(DUMPBIN, ["dumpbin -symbols" "link -dump -symbols"], :) @@ -3422,7 +3422,7 @@ for ac_symprfx in "" "_"; do " s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx]" else - lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi # Check to see that the pipe works correctly. @@ -3467,7 +3467,7 @@ _LT_EOF cat <<_LT_EOF >> conftest.$ac_ext -/* The mapping between symbol names and symbols. */ +/* The mapping between symbol names and symbols. */ const struct { const char *name; void *address; @@ -3579,11 +3579,11 @@ m4_if([$1], [CXX], [ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) - # FIXME: we need at least 68020 code to build shared libraries, but - # adding the `-m68020' flag to GCC prevents building anything better, - # like `-m68040'. + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' - ;; + ;; esac ;; @@ -3758,11 +3758,11 @@ m4_if([$1], [CXX], [ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' - ;; - esac ;; esac ;; + esac + ;; lynxos*) ;; m88k*) @@ -3885,11 +3885,11 @@ m4_if([$1], [CXX], [ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) - # FIXME: we need at least 68020 code to build shared libraries, but - # adding the `-m68020' flag to GCC prevents building anything better, - # like `-m68040'. + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' - ;; + ;; esac ;; @@ -3950,10 +3950,10 @@ m4_if([$1], [CXX], [ fi ;; - *) + *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' - ;; - esac + ;; + esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in @@ -4049,8 +4049,8 @@ m4_if([$1], [CXX], [ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='' ;; - esac - ;; + esac + ;; esac ;; @@ -4209,7 +4209,7 @@ m4_if([$1], [CXX], [ ;; esac _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] -], [ +],[ runpath_var= _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no @@ -4287,7 +4287,7 @@ dnl Note also adjust exclude_expsyms for C++ above. # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' - else + else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi supports_anon_versioning=no @@ -4324,7 +4324,7 @@ _LT_EOF # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' - ;; + ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' @@ -4397,14 +4397,14 @@ _LT_EOF tmp_addflag= tmp_sharedflag='-shared' case $cc_basename,$host_cpu in - pgcc*) # Portland Group C compiler + pgcc*) # Portland Group C compiler _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; - ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; @@ -4429,10 +4429,10 @@ _LT_EOF if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ - cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' - fi + fi case $cc_basename in xlf*) @@ -4487,7 +4487,7 @@ _LT_EOF sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in - *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 @@ -4578,10 +4578,10 @@ _LT_EOF # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do - if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then - aix_use_runtimelinking=yes - break - fi + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi done ;; esac @@ -4611,14 +4611,14 @@ _LT_EOF if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then - # We have reworked collect2 + # We have reworked collect2 : else - # We have old collect2 + # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported - # It fails to find uninstalled libraries when the uninstalled - # path is not listed in the libpath. Setting hardcode_minus_L - # to unsupported forces relinking + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= @@ -4633,8 +4633,8 @@ _LT_EOF else # not using gcc if test "$host_cpu" = ia64; then - # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release - # chokes on -Wl,-G. The following line is correct: + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then @@ -4658,7 +4658,7 @@ _LT_EOF _LT_SYS_MODULE_PATH_AIX _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" - else + else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" @@ -4687,7 +4687,7 @@ _LT_EOF # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' - ;; + ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' @@ -4723,7 +4723,7 @@ _LT_EOF darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) - ;; + ;; dgux*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' @@ -4900,18 +4900,18 @@ _LT_EOF _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' - else - case $host_os in - openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) + else + case $host_os in + openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' - ;; - *) + ;; + *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' - ;; - esac - fi + ;; + esac + fi else _LT_TAGVAR(ld_shlibs, $1)=no fi @@ -4966,7 +4966,7 @@ _LT_EOF else case `$CC -V 2>&1` in *"Compilers 5.0"*) - wlarc='' + wlarc='' _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' @@ -4987,7 +4987,7 @@ _LT_EOF # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. GCC discards it without `$wl', # but is careful enough not to reorder. - # Supported since Solaris 2.6 (maybe 2.5.1?) + # Supported since Solaris 2.6 (maybe 2.5.1?) if test "$GCC" = yes; then _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' else @@ -5108,7 +5108,7 @@ _LT_EOF _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym' ;; esac - fi + fi fi ]) AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) @@ -5727,7 +5727,7 @@ if test "$_lt_caught_CXX_error" != yes; then # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. - # +# # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library @@ -5792,7 +5792,7 @@ if test "$_lt_caught_CXX_error" != yes; then # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. - # +# # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library @@ -5877,7 +5877,7 @@ if test "$_lt_caught_CXX_error" != yes; then # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. - # +# # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library @@ -5960,7 +5960,7 @@ if test "$_lt_caught_CXX_error" != yes; then # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. - # +# # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library @@ -6987,7 +6987,7 @@ AC_DEFUN([LT_PROG_GCJ], [m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], [AC_CHECK_TOOL(GCJ, gcj,) - test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" + test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" AC_SUBST(GCJFLAGS)])])[]dnl ]) @@ -8048,13 +8048,13 @@ fi]) # --------------------------------------------- m4_define([_PKG_CONFIG], [if test -n "$$1"; then - pkg_cv_[]$1="$$1" + pkg_cv_[]$1="$$1" elif test -n "$PKG_CONFIG"; then - PKG_CHECK_EXISTS([$3], - [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`], - [pkg_failed=yes]) - else - pkg_failed=untried + PKG_CHECK_EXISTS([$3], + [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`], + [pkg_failed=yes]) +else + pkg_failed=untried fi[]dnl ])# _PKG_CONFIG diff --git a/bindings/cpp/INSTALL b/bindings/cpp/INSTALL index 7d1c323..7b9c0bb 100644 --- a/bindings/cpp/INSTALL +++ b/bindings/cpp/INSTALL @@ -48,7 +48,7 @@ may remove or edit it. you want to change it or regenerate `configure' using a newer version of `autoconf'. - The simplest way to compile this package is: +The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. @@ -111,7 +111,7 @@ is an example: Compiling For Multiple Architectures ==================================== - You can compile the package for more than one kind of computer at the +You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you can use GNU `make'. `cd' to the directory where you want the object files and executables to go and run @@ -141,7 +141,7 @@ using the `lipo' tool if you have problems. Installation Names ================== - By default, `make install' installs the package's commands under +By default, `make install' installs the package's commands under `/usr/local/bin', include files under `/usr/local/include', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PREFIX', where PREFIX must be an @@ -196,7 +196,7 @@ Optional Features with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. - Some packages pay attention to `--enable-FEATURE' options to +Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The @@ -292,7 +292,7 @@ A warning: not all `configure' scripts look for a site script. Defining Variables ================== - Variables not defined in a site shell script can be set in the +Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set diff --git a/bindings/cpp/Makefile.in b/bindings/cpp/Makefile.in index 8cb8ee0..a9ab7eb 100644 --- a/bindings/cpp/Makefile.in +++ b/bindings/cpp/Makefile.in @@ -262,15 +262,15 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ - echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \ + echo ' cd $(srcdir) && $(AUTOMAKE) --gnu '; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \ && exit 0; \ exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --gnu Makefile + $(AUTOMAKE) --gnu Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ @@ -429,7 +429,7 @@ TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ 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) \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ @@ -470,14 +470,14 @@ distdir: $(DISTFILES) */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ - esac; \ + 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; \ + 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 {} \;; \ diff --git a/bindings/cpp/aclocal.m4 b/bindings/cpp/aclocal.m4 index 18abb73..f2aab8d 100644 --- a/bindings/cpp/aclocal.m4 +++ b/bindings/cpp/aclocal.m4 @@ -688,7 +688,7 @@ _LT_CONFIG_SAVE_COMMANDS([ # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST - fi +fi cfgfile="${ofile}T" trap "$RM \"$cfgfile\"; exit 1" 1 2 15 @@ -1109,104 +1109,104 @@ fi (unset CDPATH) >/dev/null 2>&1 && unset CDPATH if test -z "$lt_ECHO"; then - if test "X${echo_test_string+set}" != Xset; then - # find a string as large as possible, as long as the shell can cope with it - for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do - # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... +if test "X${echo_test_string+set}" != Xset; then +# find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... if { echo_test_string=`eval $cmd`; } 2>/dev/null && { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null - then - break - fi - done - fi + then + break + fi + done +fi if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - : - else - # The Solaris, AIX, and Digital Unix default echo programs unquote - # backslashes. This makes it impossible to quote backslashes using - # echo "$something" | sed 's/\\/\\\\/g' - # - # So, first we look for a working echo in the user's PATH. + test "X$echo_testing_string" = "X$echo_test_string"; then + : +else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. - lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR - for dir in $PATH /usr/ucb; do - IFS="$lt_save_ifs" - if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && - test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && - echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - ECHO="$dir/echo" - break - fi - done + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do IFS="$lt_save_ifs" + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + ECHO="$dir/echo" + break + fi + done + IFS="$lt_save_ifs" if test "X$ECHO" = Xecho; then - # We didn't find a better echo, so look for alternatives. + # We didn't find a better echo, so look for alternatives. if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' && echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - # This shell has a builtin print -r that does the trick. + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. ECHO='print -r' elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } && - test "X$CONFIG_SHELL" != X/bin/ksh; then - # If we have ksh, try running configure again with it. - ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} - export ORIGINAL_CONFIG_SHELL - CONFIG_SHELL=/bin/ksh - export CONFIG_SHELL - exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} - else - # Try using printf. + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} + else + # Try using printf. ECHO='printf %s\n' if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && test "X$echo_testing_string" = "X$echo_test_string"; then - # Cool, printf works - : - elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && - test "X$echo_testing_string" = 'X\t' && - echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL - export CONFIG_SHELL - SHELL="$CONFIG_SHELL" - export SHELL + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL ECHO="$CONFIG_SHELL [$]0 --fallback-echo" - elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && - test "X$echo_testing_string" = 'X\t' && - echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then + elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then ECHO="$CONFIG_SHELL [$]0 --fallback-echo" - else - # maybe with a smaller string... - prev=: + else + # maybe with a smaller string... + prev=: - for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do + for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null - then - break - fi - prev="$cmd" - done - - if test "$prev" != 'sed 50q "[$]0"'; then - echo_test_string=`eval $prev` - export echo_test_string - exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} - else - # Oops. We lost completely, so just stick with echo. - ECHO=echo + then + break fi - fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "[$]0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} + else + # Oops. We lost completely, so just stick with echo. + ECHO=echo + fi fi fi fi fi +fi # Copy echo and quote the copy suitably for passing to libtool from # the Makefile, instead of quoting the original, which is used later. @@ -1228,7 +1228,7 @@ _LT_DECL([], [ECHO], [1], m4_defun([_LT_ENABLE_LOCK], [AC_ARG_ENABLE([libtool-lock], [AS_HELP_STRING([--disable-libtool-lock], - [avoid locking (might break parallel builds)])]) + [avoid locking (might break parallel builds)])]) test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good @@ -1239,12 +1239,12 @@ ia64-*-hpux*) echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.$ac_objext` in - *ELF-32*) - HPUX_IA64_MODE="32" - ;; - *ELF-64*) - HPUX_IA64_MODE="64" - ;; + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; esac fi rm -rf conftest* @@ -1253,31 +1253,31 @@ ia64-*-hpux*) # Find out which ABI we are using. echo '[#]line __oline__ "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then - if test "$lt_cv_prog_gnu_ld" = yes; then - case `/usr/bin/file conftest.$ac_objext` in - *32-bit*) - LD="${LD-ld} -melf32bsmip" - ;; - *N32*) - LD="${LD-ld} -melf32bmipn32" - ;; - *64-bit*) - LD="${LD-ld} -melf64bmip" - ;; - esac - else - case `/usr/bin/file conftest.$ac_objext` in - *32-bit*) - LD="${LD-ld} -32" - ;; - *N32*) - LD="${LD-ld} -n32" - ;; - *64-bit*) - LD="${LD-ld} -64" - ;; - esac - fi + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi fi rm -rf conftest* ;; @@ -1288,44 +1288,44 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in - *32-bit*) - case $host in + *32-bit*) + case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; - x86_64-*linux*) - LD="${LD-ld} -m elf_i386" - ;; - ppc64-*linux*|powerpc64-*linux*) - LD="${LD-ld} -m elf32ppclinux" - ;; - s390x-*linux*) - LD="${LD-ld} -m elf_s390" - ;; - sparc64-*linux*) - LD="${LD-ld} -m elf32_sparc" - ;; - esac - ;; - *64-bit*) - case $host in + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; - x86_64-*linux*) - LD="${LD-ld} -m elf_x86_64" - ;; - ppc*-*linux*|powerpc*-*linux*) - LD="${LD-ld} -m elf64ppc" - ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; s390*-*linux*|s390*-*tpf*) - LD="${LD-ld} -m elf64_s390" - ;; - sparc*-*linux*) - LD="${LD-ld} -m elf64_sparc" - ;; - esac - ;; + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; esac fi rm -rf conftest* @@ -1462,7 +1462,7 @@ dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) # _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, -# [ACTION-SUCCESS], [ACTION-FAILURE]) +# [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------- # Check whether the given linker option works AC_DEFUN([_LT_LINKER_OPTION], @@ -1586,7 +1586,7 @@ AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then - lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` else lt_cv_sys_max_cmd_len=32768 fi @@ -1603,23 +1603,23 @@ AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} - # If test is not a shell built-in, we'll probably end up computing a - # maximum length that is only half of the actual maximum length, but - # we can't tell. + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. while { test "X"`$SHELL [$]0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \ = "XX$teststring$teststring"; } >/dev/null 2>&1 && - test $i != 17 # 1/2 MB should be enough - do - i=`expr $i + 1` - teststring=$teststring$teststring - done + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` - teststring= + teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac @@ -1648,7 +1648,7 @@ m4_defun([_LT_HEADER_DLFCN], # _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, -# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) # ---------------------------------------------------------------- m4_defun([_LT_TRY_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl @@ -1756,12 +1756,12 @@ else mingw* | pw32* | cegcc*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= - ;; + ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= - ;; + ;; darwin*) # if libdl is installed we need to link against it @@ -1771,7 +1771,7 @@ else lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ]) - ;; + ;; *) AC_CHECK_FUNC([shl_load], @@ -1821,7 +1821,7 @@ else if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" AC_CACHE_CHECK([whether a statically linked program can dlopen itself], - lt_cv_dlopen_self_static, [dnl + lt_cv_dlopen_self_static, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) @@ -2024,17 +2024,17 @@ if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in - darwin*) - if test -n "$STRIP" ; then - striplib="$STRIP -x" + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" old_striplib="$STRIP -S" - AC_MSG_RESULT([yes]) - else - AC_MSG_RESULT([no]) - fi - ;; - *) - AC_MSG_RESULT([no]) + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) +fi + ;; + *) + AC_MSG_RESULT([no]) ;; esac fi @@ -2188,10 +2188,10 @@ amigaos*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) - library_names_spec='$libname.ixlibrary $libname.a' - # Create ${libname}_ixlibrary.a entries in /sys/libs. + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' - ;; + ;; esac ;; @@ -2226,7 +2226,7 @@ cygwin* | mingw* | pw32* | cegcc*) library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i;echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ @@ -2381,18 +2381,18 @@ hpux9* | hpux10* | hpux11*) fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; - hppa*64*) - shrext_cmds='.sl' - hardcode_into_libs=yes - dynamic_linker="$host_os dld.sl" - shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH - shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - ;; - *) + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH @@ -2555,8 +2555,8 @@ openbsd*) need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in - openbsd3.3 | openbsd3.3.*) need_version=yes ;; - *) need_version=no ;; + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' @@ -2710,10 +2710,10 @@ fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" -fi + fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" -fi + fi _LT_DECL([], [variables_saved_for_relink], [1], [Variables whose values should be saved in libtool wrapper scripts and @@ -3030,8 +3030,8 @@ mingw* | pw32*) lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else - lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' - lt_cv_file_magic_cmd='$OBJDUMP -f' + lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; @@ -3199,7 +3199,7 @@ AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, lt_cv_path_NM="$NM" else lt_nm_to_check="${ac_tool_prefix}nm" - if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do @@ -3238,7 +3238,7 @@ else : ${lt_cv_path_NM=no} fi]) if test "$lt_cv_path_NM" != "no"; then - NM="$lt_cv_path_NM" +NM="$lt_cv_path_NM" else # Didn't find any BSD compatible name lister, look for dumpbin. AC_CHECK_TOOLS(DUMPBIN, ["dumpbin -symbols" "link -dump -symbols"], :) @@ -3430,7 +3430,7 @@ for ac_symprfx in "" "_"; do " s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx]" else - lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi # Check to see that the pipe works correctly. @@ -3475,7 +3475,7 @@ _LT_EOF cat <<_LT_EOF >> conftest.$ac_ext -/* The mapping between symbol names and symbols. */ +/* The mapping between symbol names and symbols. */ const struct { const char *name; void *address; @@ -3587,11 +3587,11 @@ m4_if([$1], [CXX], [ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) - # FIXME: we need at least 68020 code to build shared libraries, but - # adding the `-m68020' flag to GCC prevents building anything better, - # like `-m68040'. + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' - ;; + ;; esac ;; @@ -3766,11 +3766,11 @@ m4_if([$1], [CXX], [ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' - ;; - esac ;; esac ;; + esac + ;; lynxos*) ;; m88k*) @@ -3893,11 +3893,11 @@ m4_if([$1], [CXX], [ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) - # FIXME: we need at least 68020 code to build shared libraries, but - # adding the `-m68020' flag to GCC prevents building anything better, - # like `-m68040'. + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' - ;; + ;; esac ;; @@ -3958,10 +3958,10 @@ m4_if([$1], [CXX], [ fi ;; - *) + *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' - ;; - esac + ;; + esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in @@ -4057,8 +4057,8 @@ m4_if([$1], [CXX], [ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='' ;; - esac - ;; + esac + ;; esac ;; @@ -4217,7 +4217,7 @@ m4_if([$1], [CXX], [ ;; esac _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] -], [ +],[ runpath_var= _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no @@ -4295,7 +4295,7 @@ dnl Note also adjust exclude_expsyms for C++ above. # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' - else + else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi supports_anon_versioning=no @@ -4332,7 +4332,7 @@ _LT_EOF # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' - ;; + ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' @@ -4405,14 +4405,14 @@ _LT_EOF tmp_addflag= tmp_sharedflag='-shared' case $cc_basename,$host_cpu in - pgcc*) # Portland Group C compiler + pgcc*) # Portland Group C compiler _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; - ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; @@ -4437,10 +4437,10 @@ _LT_EOF if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ - cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' - fi + fi case $cc_basename in xlf*) @@ -4495,7 +4495,7 @@ _LT_EOF sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in - *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 @@ -4586,10 +4586,10 @@ _LT_EOF # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do - if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then - aix_use_runtimelinking=yes - break - fi + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi done ;; esac @@ -4619,14 +4619,14 @@ _LT_EOF if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then - # We have reworked collect2 + # We have reworked collect2 : else - # We have old collect2 + # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported - # It fails to find uninstalled libraries when the uninstalled - # path is not listed in the libpath. Setting hardcode_minus_L - # to unsupported forces relinking + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= @@ -4641,8 +4641,8 @@ _LT_EOF else # not using gcc if test "$host_cpu" = ia64; then - # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release - # chokes on -Wl,-G. The following line is correct: + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then @@ -4666,7 +4666,7 @@ _LT_EOF _LT_SYS_MODULE_PATH_AIX _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" - else + else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" @@ -4695,7 +4695,7 @@ _LT_EOF # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' - ;; + ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' @@ -4731,7 +4731,7 @@ _LT_EOF darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) - ;; + ;; dgux*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' @@ -4908,18 +4908,18 @@ _LT_EOF _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' - else - case $host_os in - openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) + else + case $host_os in + openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' - ;; - *) + ;; + *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' - ;; - esac - fi + ;; + esac + fi else _LT_TAGVAR(ld_shlibs, $1)=no fi @@ -4974,7 +4974,7 @@ _LT_EOF else case `$CC -V 2>&1` in *"Compilers 5.0"*) - wlarc='' + wlarc='' _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' @@ -4995,7 +4995,7 @@ _LT_EOF # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. GCC discards it without `$wl', # but is careful enough not to reorder. - # Supported since Solaris 2.6 (maybe 2.5.1?) + # Supported since Solaris 2.6 (maybe 2.5.1?) if test "$GCC" = yes; then _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' else @@ -5116,7 +5116,7 @@ _LT_EOF _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym' ;; esac - fi + fi fi ]) AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) @@ -5735,7 +5735,7 @@ if test "$_lt_caught_CXX_error" != yes; then # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. - # +# # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library @@ -5800,7 +5800,7 @@ if test "$_lt_caught_CXX_error" != yes; then # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. - # +# # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library @@ -5885,7 +5885,7 @@ if test "$_lt_caught_CXX_error" != yes; then # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. - # +# # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library @@ -5968,7 +5968,7 @@ if test "$_lt_caught_CXX_error" != yes; then # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. - # +# # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library @@ -6995,7 +6995,7 @@ AC_DEFUN([LT_PROG_GCJ], [m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], [AC_CHECK_TOOL(GCJ, gcj,) - test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" + test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" AC_SUBST(GCJFLAGS)])])[]dnl ]) @@ -8317,44 +8317,44 @@ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], shift for mf do - # Strip MF so we end up with the name of the file. - mf=`echo "$mf" | sed -e 's/:.*$//'` - # Check whether this is an Automake generated Makefile or not. - # We used to match only the files named `Makefile.in', but - # some people rename them; so instead we look at the file content. - # Grep'ing the first line is not enough: some people post-process - # each Makefile.in and add a new line on top of each file to say so. + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then - dirpart=`AS_DIRNAME("$mf")` - else - continue - fi - # Extract the definition of DEPDIR, am__include, and am__quote - # from the Makefile without running `make'. - DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` - test -z "$DEPDIR" && continue - am__include=`sed -n 's/^am__include = //p' < "$mf"` - test -z "am__include" && continue - am__quote=`sed -n 's/^am__quote = //p' < "$mf"` - # When using ansi2knr, U may be empty or an underscore; expand it - U=`sed -n 's/^U = //p' < "$mf"` - # Find all dependency output files, they are included files with - # $(DEPDIR) in their names. We invoke sed twice because it is the - # simplest approach to changing $(DEPDIR) to its actual value in the - # expansion. - for file in `sed -n " - s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ - sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do - # Make sure the directory exists. - test -f "$dirpart/$file" && continue - fdir=`AS_DIRNAME(["$file"])` - AS_MKDIR_P([$dirpart/$fdir]) - # echo "creating $dirpart/$file" - echo '# dummy' > "$dirpart/$file" - done + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" done +done } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS @@ -8408,10 +8408,10 @@ if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl - # test to see if srcdir already configured +# test to see if srcdir already configured if test -f $srcdir/config.status; then - AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) - fi + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) +fi fi # test whether we have cygpath @@ -8458,17 +8458,17 @@ AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], - [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], - [_AM_PROG_TAR([v7])])]) + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], - [_AM_DEPENDENCIES(CC)], - [define([AC_PROG_CC], - defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], - [_AM_DEPENDENCIES(CXX)], - [define([AC_PROG_CXX], - defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES(OBJC)], [define([AC_PROG_OBJC], @@ -8623,9 +8623,9 @@ echo "include confinc" > confmf # Ignore all kinds of additional output from `make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) - am__include=include - am__quote= - _am_result=GNU + am__include=include + am__quote= + _am_result=GNU ;; esac # Now try BSD make style include. @@ -8633,12 +8633,12 @@ if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) - am__include=.include - am__quote="\"" - _am_result=BSD + am__include=.include + am__quote="\"" + _am_result=BSD ;; esac -fi + fi AC_SUBST([am__include]) AC_SUBST([am__quote]) AC_MSG_RESULT([$_am_result]) diff --git a/bindings/cpp/configure b/bindings/cpp/configure index c906267..3b44044 100755 Binary files a/bindings/cpp/configure and b/bindings/cpp/configure differ diff --git a/build/msvc/portaudio.def b/build/msvc/portaudio.def index d25414f..25bf7b4 100644 --- a/build/msvc/portaudio.def +++ b/build/msvc/portaudio.def @@ -35,6 +35,8 @@ Pa_GetStreamReadAvailable @31 Pa_GetStreamWriteAvailable @32 Pa_GetSampleSize @33 Pa_Sleep @34 +Pa_UpdateAvailableDeviceList @35 +Pa_SetDevicesChangedCallback @36 PaAsio_GetAvailableLatencyValues @50 PaAsio_ShowControlPanel @51 PaUtil_InitializeX86PlainConverters @52 diff --git a/configure b/configure index f91cbe7..ac738aa 100755 Binary files a/configure and b/configure differ diff --git a/configure.in b/configure.in index dd39fb7..0749eb0 100644 --- a/configure.in +++ b/configure.in @@ -216,7 +216,7 @@ case "${host_os}" in fi SHARED_FLAGS="$LIBS -dynamiclib $mac_arches $mac_sysroot $mac_version_min" CFLAGS="-std=c99 $CFLAGS $mac_arches $mac_sysroot $mac_version_min" - OTHER_OBJS="src/os/unix/pa_unix_hostapis.o src/os/unix/pa_unix_util.o src/hostapi/coreaudio/pa_mac_core.o src/hostapi/coreaudio/pa_mac_core_utilities.o src/hostapi/coreaudio/pa_mac_core_blocking.o src/common/pa_ringbuffer.o" + OTHER_OBJS="src/os/unix/pa_unix_hostapis.o src/os/unix/pa_unix_util.o src/hostapi/coreaudio/pa_mac_core.o src/hostapi/coreaudio/pa_mac_core_utilities.o src/hostapi/coreaudio/pa_mac_core_blocking.o src/common/pa_ringbuffer.o src/os/mac_osx/pa_osx_hotplug.o" PADLL="libportaudio.dylib" ;; @@ -230,7 +230,7 @@ case "${host_os}" in if [[ "x$with_directx" = "xyes" ]]; then DXDIR="$with_dxdir" - add_objects src/hostapi/dsound/pa_win_ds.o src/hostapi/dsound/pa_win_ds_dynlink.o src/os/win/pa_win_hostapis.o src/os/win/pa_win_util.o src/os/win/pa_win_waveformat.o + add_objects src/hostapi/dsound/pa_win_ds.o src/hostapi/dsound/pa_win_ds_dynlink.o src/os/win/pa_win_hostapis.o src/os/win/pa_win_util.o src/os/win/pa_win_waveformat.o src/os/win/pa_win_hotplug.o LIBS="-lwinmm -lm -ldsound -lole32" DLL_LIBS="${DLL_LIBS} -lwinmm -lm -L$DXDIR/lib -ldsound -lole32" #VC98="\"/c/Program Files/Microsoft Visual Studio/VC98/Include\"" @@ -249,7 +249,7 @@ case "${host_os}" in if [[ "x$with_wdmks" = "xyes" ]]; then DXDIR="$with_dxdir" - add_objects src/hostapi/wdmks/pa_win_wdmks.o src/os/win/pa_win_hostapis.o src/os/win/pa_win_util.o + add_objects src/hostapi/wdmks/pa_win_wdmks.o src/os/win/pa_win_hostapis.o src/os/win/pa_win_util.o src/os/win/pa_win_wdmks_utils.o LIBS="-lwinmm -lm -luuid -lsetupapi -lole32" DLL_LIBS="${DLL_LIBS} -lwinmm -lm -L$DXDIR/lib -luuid -lsetupapi -lole32" #VC98="\"/c/Program Files/Microsoft Visual Studio/VC98/Include\"" @@ -319,7 +319,7 @@ case "${host_os}" in if [[ "$have_alsa" = "yes" ] && [ "$with_alsa" != "no" ]] ; then DLL_LIBS="$DLL_LIBS -lasound" LIBS="$LIBS -lasound" - OTHER_OBJS="$OTHER_OBJS src/hostapi/alsa/pa_linux_alsa.o" + OTHER_OBJS="$OTHER_OBJS src/hostapi/alsa/pa_linux_alsa.o src/os/unix/pa_linux_hotplug.o" INCLUDES="$INCLUDES pa_linux_alsa.h" AC_DEFINE(PA_USE_ALSA) fi @@ -337,7 +337,7 @@ case "${host_os}" in if [[ "$have_libossaudio" = "yes" ]] ; then DLL_LIBS="$DLL_LIBS -lossaudio" LIBS="$LIBS -lossaudio" - fi + fi AC_DEFINE(PA_USE_OSS) fi diff --git a/include/pa_mac_core.h b/include/pa_mac_core.h index 43321b6..5ab36c4 100644 --- a/include/pa_mac_core.h +++ b/include/pa_mac_core.h @@ -46,7 +46,7 @@ #include "portaudio.h" #include -//#include +#include #ifdef __cplusplus extern "C" { diff --git a/include/portaudio.h b/include/portaudio.h index 53418cb..ecfa1c6 100644 --- a/include/portaudio.h +++ b/include/portaudio.h @@ -1,7 +1,7 @@ #ifndef PORTAUDIO_H #define PORTAUDIO_H /* - * $Id$ + * $Id: portaudio.h 1670 2011-05-04 16:37:52Z rob_bielik $ * PortAudio Portable Real-Time Audio Library * PortAudio API Header File * Latest version available at: http://www.portaudio.com/ @@ -121,9 +121,17 @@ const char *Pa_GetErrorText( PaError errorCode ); Pairs of calls to Pa_Initialize()/Pa_Terminate() may overlap, and are not required to be fully nested. - Note that if Pa_Initialize() returns an error code, Pa_Terminate() should + If Pa_Initialize() returns an error code, Pa_Terminate() should NOT be called. + @note The device list returned by Pa_GetDeviceCount() et al. is frozen + at the time Pa_Initialize() is called, and not updated dynamically, even if + hardware devices (e.g. USB or firewire devices) are connected or disconnected + during the course of the program's lifetime. If it is required to re-scan the + list of devices, one must call Pa_UpdateAvailableDeviceList() or, completely + uninitialize PortAudio using Pa_Terminate(), and then reinitialize it by calling + Pa_Initialize(). + @return paNoError if successful, otherwise an error code indicating the cause of failure. @@ -397,11 +405,25 @@ PaDeviceIndex Pa_GetDefaultInputDevice( void ); */ PaDeviceIndex Pa_GetDefaultOutputDevice( void ); +/** Update the list of available devices to match currently available hardware devices. + + PortAudio's list of available devices is usually frozen at the time Pa_Initialize() is + called. Pa_UpdateAvailableDeviceList() may be called to refresh PortAudio's list + of available devices at any time while PortAudio is initialized. + + @note Open streams will not be affected by calls to this function, but + any previously returned PaDeviceInfo pointers are invalidated once this + function is called. + + @return an error code indicating whether the device refresh was successful. + */ +PaError Pa_UpdateAvailableDeviceList( void ); + /** The type used to represent monotonic time in seconds. PaTime is used for the fields of the PaStreamCallbackTimeInfo argument to the PaStreamCallback and as the result of Pa_GetStreamTime(). - + PaTime values have unspecified origin. @see PaStreamCallback, PaStreamCallbackTimeInfo, Pa_GetStreamTime @@ -439,7 +461,7 @@ typedef unsigned long PaSampleFormat; #define paInt16 ((PaSampleFormat) 0x00000008) /**< @see PaSampleFormat */ #define paInt8 ((PaSampleFormat) 0x00000010) /**< @see PaSampleFormat */ #define paUInt8 ((PaSampleFormat) 0x00000020) /**< @see PaSampleFormat */ -#define paCustomFormat ((PaSampleFormat) 0x00010000) /**< @see PaSampleFormat */ +#define paCustomFormat ((PaSampleFormat) 0x00010000)/**< @see PaSampleFormat */ #define paNonInterleaved ((PaSampleFormat) 0x80000000) /**< @see PaSampleFormat */ @@ -448,7 +470,7 @@ typedef unsigned long PaSampleFormat; */ typedef struct PaDeviceInfo { - int structVersion; /* this is struct version 2 */ + int structVersion; /* this is struct version 3 */ const char *name; PaHostApiIndex hostApi; /* note this is a host API index, not a type id*/ @@ -463,6 +485,11 @@ typedef struct PaDeviceInfo PaTime defaultHighOutputLatency; double defaultSampleRate; + + /*The transport type used by this device: USB, BuiltIn, Bluetooth, etc.*/ + const char *transportType; + /*The unique identifier of this device (persistent across boots).*/ + const char *deviceUID; } PaDeviceInfo; @@ -1012,7 +1039,7 @@ const PaStreamInfo* Pa_GetStreamInfo( PaStream *stream ); /** Returns the current time in seconds for a stream according to the same clock used to generate callback PaStreamCallbackTimeInfo timestamps. The time values are monotonically increasing and have unspecified origin. - + Pa_GetStreamTime returns valid time values for the entire life of the stream, from when the stream is opened until it is closed. Starting and stopping the stream does not affect the passage of time returned by Pa_GetStreamTime. @@ -1143,6 +1170,13 @@ void Pa_Sleep( long msec ); +typedef void PaDevicesChangedCallback( void *userData ); + +PaError Pa_SetDevicesChangedCallback( void *userData, PaStreamFinishedCallback* devicesChangedCallback ); + + + + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/install-sh b/install-sh index 6781b98..0eec190 100755 Binary files a/install-sh and b/install-sh differ diff --git a/ltmain.sh b/ltmain.sh index 7ed280b..6f931c3 100644 --- a/ltmain.sh +++ b/ltmain.sh @@ -162,9 +162,9 @@ func_dirname_and_basename () func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" - else +else func_dirname_result="$func_dirname_result${2}" - fi +fi func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` } @@ -193,7 +193,7 @@ case $progpath in progdir=$func_dirname_result progdir=`cd "$progdir" && pwd` progpath="$progdir/$progname" - ;; + ;; *) save_IFS="$IFS" IFS=: @@ -204,7 +204,7 @@ case $progpath in IFS="$save_IFS" test -n "$progdir" || progdir=`pwd` progpath="$progdir/$progname" - ;; + ;; esac # Sed substitution that helps us do robust quoting. It backslashifies @@ -280,7 +280,7 @@ func_warning () func_fatal_error () { func_error ${1+"$@"} - exit $EXIT_FAILURE + exit $EXIT_FAILURE } # func_fatal_help arg... @@ -293,7 +293,7 @@ func_fatal_help () } help="Try \`$progname --help' for more information." ## default - + # func_grep expression filename # Check whether EXPRESSION matches any line of FILENAME, without output. func_grep () @@ -327,7 +327,7 @@ func_mkdir_p () # ...otherwise throw away the child directory and loop my_directory_path=`$ECHO "X$my_directory_path" | $Xsed -e "$dirname"` - done + done my_dir_list=`$ECHO "X$my_dir_list" | $Xsed -e 's,:*$,,'` save_mkdir_p_IFS="$IFS"; IFS=':' @@ -343,7 +343,7 @@ func_mkdir_p () # Bail out if we (or some other process) failed to create a directory. test -d "$my_directory_path" || \ func_fatal_error "Failed to create \`$1'" - fi +fi } @@ -364,13 +364,13 @@ func_mktempdir () my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` if test ! -d "$my_tmpdir"; then - # Failing that, at least try and use $RANDOM to avoid a race - my_tmpdir="${my_template}-${RANDOM-0}$$" + # Failing that, at least try and use $RANDOM to avoid a race + my_tmpdir="${my_template}-${RANDOM-0}$$" - save_mktempdir_umask=`umask` - umask 0077 + save_mktempdir_umask=`umask` + umask 0077 $MKDIR "$my_tmpdir" - umask $save_mktempdir_umask + umask $save_mktempdir_umask fi # If we're not in dry-run mode, bomb out on failure @@ -395,7 +395,7 @@ func_quote_for_eval () func_quote_for_eval_unquoted_result=`$ECHO "X$1" | $Xsed -e "$sed_quote_subst"` ;; *) func_quote_for_eval_unquoted_result="$1" ;; - esac + esac case $func_quote_for_eval_unquoted_result in # Double-quote args containing shell metacharacters to delay @@ -405,7 +405,7 @@ func_quote_for_eval () # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" - ;; + ;; *) func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" esac @@ -423,17 +423,17 @@ func_quote_for_expand () -e "$double_quote_subst" -e "$sed_double_backslash"` ;; *) my_arg="$1" ;; - esac + esac case $my_arg in # Double-quote args containing shell metacharacters to delay # word splitting and command substitution for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") my_arg="\"$my_arg\"" - ;; - esac + ;; + esac func_quote_for_expand_result="$my_arg" } @@ -458,7 +458,7 @@ func_show_eval () my_status=$? if test "$my_status" -eq 0; then :; else eval "(exit $my_status); $my_fail_exp" - fi + fi fi } @@ -480,11 +480,11 @@ func_show_eval_locale () if ${opt_dry_run-false}; then :; else eval "$lt_user_locale $my_cmd" - my_status=$? + my_status=$? eval "$lt_safe_locale" if test "$my_status" -eq 0; then :; else eval "(exit $my_status); $my_fail_exp" - fi + fi fi } @@ -566,10 +566,10 @@ elif test "X$1" = X--fallback-echo; then elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t'; then # Yippee, $ECHO works! : -else + else # Restart under the correct shell, and then maybe $ECHO will work. exec $SHELL "$progpath" --no-reexec ${1+"$@"} -fi + fi if test "X$1" = X--fallback-echo; then # used as fallback echo @@ -578,7 +578,7 @@ if test "X$1" = X--fallback-echo; then $* EOF exit $EXIT_SUCCESS -fi + fi magic="%%%MAGIC variable%%%" magic_exe="%%%MAGIC EXE variable%%%" @@ -688,7 +688,7 @@ func_enable_tag () else func_error "ignoring unknown tag $tagname" fi - ;; + ;; esac } @@ -733,12 +733,12 @@ func_enable_tag () func_echo "enabling shell trace mode" opt_debug='set -x' $opt_debug - ;; + ;; -dlopen) test "$#" -eq 0 && func_missing_arg "$opt" && break execute_dlfiles="$execute_dlfiles $1" shift - ;; + ;; --dry-run | -n) opt_dry_run=: ;; --features) func_features ;; @@ -759,9 +759,9 @@ func_enable_tag () # Catch anything else as an error *) func_error "invalid argument for $opt" exit_cmd=exit - break - ;; - esac + break + ;; + esac mode="$1" shift @@ -772,17 +772,17 @@ func_enable_tag () --quiet|--silent) preserve_args="$preserve_args $opt" opt_silent=: - ;; + ;; --verbose| -v) preserve_args="$preserve_args $opt" opt_silent=false - ;; + ;; --tag) test "$#" -eq 0 && func_missing_arg "$opt" && break preserve_args="$preserve_args $opt $1" func_enable_tag "$1" # tagname is set here shift - ;; + ;; # Separate optargs to long options: -dlopen=*|--mode=*|--tag=*) @@ -798,10 +798,10 @@ func_enable_tag () -*) func_fatal_help "unrecognized option \`$opt'" ;; *) nonopt="$opt" - break - ;; - esac - done + break + ;; + esac + done case $host in @@ -833,14 +833,14 @@ $progname: definition of this LT_INIT comes from an older release. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF - else + else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from $PACKAGE $macro_version. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF - fi + fi else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, @@ -848,7 +848,7 @@ $progname: but the definition of this LT_INIT comes from revision $macro_revisio $progname: You should recreate aclocal.m4 with macros from revision $package_revision $progname: of $PACKAGE $VERSION and run autoconf again. _LT_EOF - fi + fi exit $EXIT_MISMATCH fi @@ -1161,7 +1161,7 @@ func_mode_compile () args=$func_stripname_result lastarg= save_ifs="$IFS"; IFS=',' - for arg in $args; do + for arg in $args; do IFS="$save_ifs" func_quote_for_eval "$arg" lastarg="$lastarg $func_quote_for_eval_result" @@ -1175,7 +1175,7 @@ func_mode_compile () continue ;; - *) + * ) # Accept the current argument as the source file. # The previous "srcfile" becomes the current argument. # @@ -1379,11 +1379,11 @@ compiler." if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then func_show_eval '$MV "$output_obj" "$lobj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' - fi + fi # Allow error messages only from the first compilation. if test "$suppress_opt" = yes; then - suppress_output=' >/dev/null 2>&1' + suppress_output=' >/dev/null 2>&1' fi fi @@ -1675,8 +1675,8 @@ func_mode_execute () else if test ! -f "$dir/$dlname"; then func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" - fi fi + fi ;; *.lo) @@ -1698,7 +1698,7 @@ func_mode_execute () # Now add the directory to shlibpath_var. if eval "test -z \"\$$shlibpath_var\""; then eval "$shlibpath_var=\"\$dir\"" - else + else eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" fi done @@ -1724,7 +1724,7 @@ func_mode_execute () func_source "$func_ltwrapper_scriptname_result" # Transform arg to wrapped name. file="$progdir/$program" - fi + fi ;; esac # Quote arguments (to preserve shell metacharacters). @@ -1755,7 +1755,7 @@ func_mode_execute () if test -n "$shlibpath_var"; then eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" $ECHO "export $shlibpath_var" - fi + fi $ECHO "$cmd$args" exit $EXIT_SUCCESS fi @@ -1891,7 +1891,7 @@ func_mode_install () *[\\\ /]cp\ *) ;; *) prev=$arg ;; esac - ;; + ;; -g | -m | -o) prev=$arg ;; @@ -2152,7 +2152,7 @@ func_mode_install () esac # Do a test to see if this is really a libtool program. - case $host in + case $host in *cygwin* | *mingw*) if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" @@ -4132,7 +4132,7 @@ func_mode_link () -static-libtool-libs) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static - fi + fi prefer_static_libs=yes ;; esac @@ -4222,7 +4222,7 @@ func_mode_link () case "$deplibs " in *" $qarg.ltframework "*) ;; *) deplibs="$deplibs $qarg.ltframework" # this is fixed later - ;; + ;; esac ;; esac @@ -4318,10 +4318,10 @@ func_mode_link () non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" - else + else func_fatal_error "\`$arg' is not a valid libtool object" + fi fi - fi done else func_fatal_error "link input file \`$arg' does not exist" @@ -4584,8 +4584,8 @@ func_mode_link () *" $arg "*) ;; * ) new_inherited_linker_flags="$new_inherited_linker_flags $arg" ;; esac - continue - ;; + continue + ;; -multi_module) single_module="${wl}-multi_module" @@ -4778,7 +4778,7 @@ func_mode_link () -* | +*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" - ;; + ;; *.$objext) # A standard object. @@ -4862,10 +4862,10 @@ func_mode_link () non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" - else + else func_fatal_error "\`$arg' is not a valid libtool object" + fi fi - fi ;; *.$libext) @@ -4898,7 +4898,7 @@ func_mode_link () # to be aesthetically quoted because they are evaled later. func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" - ;; + ;; esac # arg # Now actually substitute the argument into the commands. @@ -5081,7 +5081,7 @@ func_mode_link () *" $deplib "*) ;; * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;; esac - fi + fi fi continue ;; @@ -5149,7 +5149,7 @@ func_mode_link () continue fi fi - ;; + ;; *) ;; esac fi @@ -5225,21 +5225,21 @@ func_mode_link () case " $dlpreconveniencelibs " in *" $deplib "*) ;; *) - valid_a_lib=no - case $deplibs_check_method in - match_pattern*) + valid_a_lib=no + case $deplibs_check_method in + match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` if eval "\$ECHO \"X$deplib\"" 2>/dev/null | $Xsed -e 10q \ | $EGREP "$match_pattern_regex" > /dev/null; then - valid_a_lib=yes - fi - ;; - pass_all) valid_a_lib=yes + fi ;; - esac - if test "$valid_a_lib" != yes; then + pass_all) + valid_a_lib=yes + ;; + esac + if test "$valid_a_lib" != yes; then $ECHO $ECHO "*** Warning: Trying to link with static lib archive $deplib." $ECHO "*** I have the capability to make that library automatically link in when" @@ -5247,12 +5247,12 @@ func_mode_link () $ECHO "*** shared version of the library, which you do not appear to have" $ECHO "*** because the file extensions .$libext of this argument makes me believe" $ECHO "*** that it is just a static archive that I should not use here." - else + else $ECHO $ECHO "*** Warning: Linking the shared library $output against the" $ECHO "*** static library $deplib is not portable!" - deplibs="$deplib $deplibs" - fi + deplibs="$deplib $deplibs" + fi ;; esac continue @@ -5326,7 +5326,7 @@ func_mode_link () case " $new_inherited_linker_flags " in *" $tmp_inherited_linker_flag "*) ;; *) new_inherited_linker_flags="$new_inherited_linker_flags $tmp_inherited_linker_flag";; - esac + esac done fi dependency_libs=`$ECHO "X $dependency_libs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` @@ -5351,10 +5351,10 @@ func_mode_link () for deplib in $dependency_libs; do deplibs="$deplib $deplibs" if $opt_duplicate_deps ; then - case "$tmp_libs " in - *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; - esac - fi + case "$tmp_libs " in + *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + esac + fi tmp_libs="$tmp_libs $deplib" done elif test "$linkmode" != prog && test "$linkmode" != lib; then @@ -5553,7 +5553,7 @@ func_mode_link () link_static=no # Whether the deplib will be linked statically use_static_libs=$prefer_static_libs - if test "$use_static_libs" = built && test "$installed" = yes; then + if test "$use_static_libs" = built && test "$installed" = yes ; then use_static_libs=no fi if test -n "$library_names" && @@ -5565,10 +5565,10 @@ func_mode_link () need_relink=no ;; *) - if test "$installed" = no; then - notinst_deplibs="$notinst_deplibs $lib" - need_relink=yes - fi + if test "$installed" = no; then + notinst_deplibs="$notinst_deplibs $lib" + need_relink=yes + fi ;; esac # This is a shared library @@ -5685,16 +5685,16 @@ func_mode_link () $GREP ": [^:]* bundle" >/dev/null ; then if test "X$dlopenmodule" != "X$lib"; then $ECHO "*** Warning: lib $linklib is a module, not a shared library" - if test -z "$old_library" ; then + if test -z "$old_library" ; then $ECHO $ECHO "*** And there doesn't seem to be a static archive available" $ECHO "*** The link will probably fail, sorry" - else - add="$dir/$old_library" - fi + else + add="$dir/$old_library" + fi elif test -n "$old_library"; then add="$dir/$old_library" - fi + fi fi esac elif test "$hardcode_minus_L" = no; then @@ -5782,9 +5782,9 @@ func_mode_link () elif test "$hardcode_automatic" = yes; then if test -n "$inst_prefix_dir" && test -f "$inst_prefix_dir$libdir/$linklib" ; then - add="$inst_prefix_dir$libdir/$linklib" + add="$inst_prefix_dir$libdir/$linklib" else - add="$libdir/$linklib" + add="$libdir/$linklib" fi else # We cannot seem to hardcode it, guess we'll fake it. @@ -5927,11 +5927,11 @@ func_mode_link () darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` if test -z "$darwin_install_name"; then darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` - fi + fi compiler_flags="$compiler_flags ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" linker_flags="$linker_flags -dylib_file ${darwin_install_name}:${depdepl}" path= - fi + fi fi ;; *) @@ -5946,9 +5946,9 @@ func_mode_link () func_warning "\`$deplib' seems to be moved" path="-L$absdir" - fi - ;; - esac + fi + ;; + esac case " $deplibs " in *" $path "*) ;; *) deplibs="$path $deplibs" ;; @@ -6417,7 +6417,7 @@ func_mode_link () $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) if test "X$precious_files_regex" != "X"; then if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 - then + then continue fi fi @@ -6428,7 +6428,7 @@ func_mode_link () done test -n "$removelist" && \ func_show_eval "${RM}r \$removelist" - fi + fi # Now set the variables for building old libraries. if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then @@ -6502,7 +6502,7 @@ func_mode_link () *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work ;; - *) + *) # Add libc to deplibs on all other systems if necessary. if test "$build_libtool_need_lc" = "yes"; then deplibs="$deplibs -lc" @@ -6558,7 +6558,7 @@ EOF i="" ;; esac - fi + fi if test -n "$i" ; then libname=`eval "\\$ECHO \"$libname_spec\""` deplib_matches=`eval "\\$ECHO \"$library_names_spec\""` @@ -6678,9 +6678,9 @@ EOF if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | $SED -e 10q | $EGREP "$file_magic_regex" > /dev/null; then - newdeplibs="$newdeplibs $a_deplib" - a_deplib="" - break 2 + newdeplibs="$newdeplibs $a_deplib" + a_deplib="" + break 2 fi done done @@ -7015,11 +7015,11 @@ EOF len=$func_len_result if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then func_show_eval "$cmd" 'exit $?' - skipped_export=false + skipped_export=false else - # The command line is too long to execute in one step. + # The command line is too long to execute in one step. func_verbose "using reloadable object file for export list..." - skipped_export=: + skipped_export=: # Break out early, otherwise skipped_export may be # set to false by a later but shorter cmd. break @@ -7055,12 +7055,12 @@ EOF tmp_deplibs= for test_deplib in $deplibs; do - case " $convenience " in - *" $test_deplib "*) ;; - *) - tmp_deplibs="$tmp_deplibs $test_deplib" - ;; - esac + case " $convenience " in + *" $test_deplib "*) ;; + *) + tmp_deplibs="$tmp_deplibs $test_deplib" + ;; + esac done deplibs="$tmp_deplibs" @@ -7085,7 +7085,7 @@ EOF test "X$libobjs" = "X " && libobjs= fi fi - + if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then eval flag=\"$thread_safe_flag_spec\" linker_flags="$linker_flags $flag" @@ -7106,12 +7106,12 @@ EOF cmds=$module_cmds fi else - if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then - eval test_cmds=\"$archive_expsym_cmds\" - cmds=$archive_expsym_cmds - else - eval test_cmds=\"$archive_cmds\" - cmds=$archive_cmds + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval test_cmds=\"$archive_expsym_cmds\" + cmds=$archive_expsym_cmds + else + eval test_cmds=\"$archive_cmds\" + cmds=$archive_cmds fi fi @@ -7177,47 +7177,47 @@ EOF else if test -n "$save_libobjs"; then func_verbose "creating reloadable object files..." - output=$output_objdir/$output_la-${k}.$objext + output=$output_objdir/$output_la-${k}.$objext eval test_cmds=\"$reload_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 - # Loop over the list of objects to be linked. - for obj in $save_libobjs - do + # Loop over the list of objects to be linked. + for obj in $save_libobjs + do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result - if test "X$objlist" = X || + if test "X$objlist" = X || test "$len" -lt "$max_cmd_len"; then func_append objlist " $obj" - else - # The command $test_cmds is almost too long, add a - # command to the queue. - if test "$k" -eq 1 ; then - # The first file doesn't have a previous command to add. - eval concat_cmds=\"$reload_cmds $objlist $last_robj\" - else - # All subsequent reloadable object files will link in - # the last one created. + else + # The command $test_cmds is almost too long, add a + # command to the queue. + if test "$k" -eq 1 ; then + # The first file doesn't have a previous command to add. + eval concat_cmds=\"$reload_cmds $objlist $last_robj\" + else + # All subsequent reloadable object files will link in + # the last one created. eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj~\$RM $last_robj\" - fi - last_robj=$output_objdir/$output_la-${k}.$objext + fi + last_robj=$output_objdir/$output_la-${k}.$objext func_arith $k + 1 k=$func_arith_result - output=$output_objdir/$output_la-${k}.$objext - objlist=$obj + output=$output_objdir/$output_la-${k}.$objext + objlist=$obj func_len " $last_robj" func_arith $len0 + $func_len_result len=$func_arith_result - fi - done - # Handle the remaining objects by creating one last - # reloadable object file. All subsequent reloadable object - # files will link in the last one created. - test -z "$concat_cmds" || concat_cmds=$concat_cmds~ - eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\" + fi + done + # Handle the remaining objects by creating one last + # reloadable object file. All subsequent reloadable object + # files will link in the last one created. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\" if test -n "$last_robj"; then eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\" fi @@ -7227,26 +7227,26 @@ EOF output= fi - if ${skipped_export-false}; then + if ${skipped_export-false}; then func_verbose "generating symbol list for \`$libname.la'" - export_symbols="$output_objdir/$libname.exp" + export_symbols="$output_objdir/$libname.exp" $opt_dry_run || $RM $export_symbols - libobjs=$output - # Append the command to create the export file. + libobjs=$output + # Append the command to create the export file. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" - fi + fi fi test -n "$save_libobjs" && func_verbose "creating a temporary reloadable object file: $output" - # Loop through the commands generated above and execute them. - save_ifs="$IFS"; IFS='~' - for cmd in $concat_cmds; do - IFS="$save_ifs" + # Loop through the commands generated above and execute them. + save_ifs="$IFS"; IFS='~' + for cmd in $concat_cmds; do + IFS="$save_ifs" $opt_silent || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" @@ -7263,8 +7263,8 @@ EOF exit $lt_exit } - done - IFS="$save_ifs" + done + IFS="$save_ifs" if test -n "$export_symbols_regex" && ${skipped_export-false}; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' @@ -7313,10 +7313,10 @@ EOF cmds=$module_cmds fi else - if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then - cmds=$archive_expsym_cmds - else - cmds=$archive_cmds + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + cmds=$archive_expsym_cmds + else + cmds=$archive_cmds fi fi fi @@ -7519,20 +7519,20 @@ EOF case $host in *-*-darwin*) - # Don't allow lazy linking, it breaks C++ global constructors + # Don't allow lazy linking, it breaks C++ global constructors # But is supposedly fixed on 10.4 or later (yay!). - if test "$tagname" = CXX ; then + if test "$tagname" = CXX ; then case ${MACOSX_DEPLOYMENT_TARGET-10.0} in 10.[0123]) - compile_command="$compile_command ${wl}-bind_at_load" - finalize_command="$finalize_command ${wl}-bind_at_load" + compile_command="$compile_command ${wl}-bind_at_load" + finalize_command="$finalize_command ${wl}-bind_at_load" ;; esac - fi + fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" compile_deplibs=`$ECHO "X $compile_deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` finalize_deplibs=`$ECHO "X $finalize_deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` - ;; + ;; esac @@ -7677,25 +7677,25 @@ EOF # template prelinking step if test -n "$prelink_cmds"; then func_execute_cmds "$prelink_cmds" 'exit $?' - fi + fi wrappers_required=yes - case $host in - *cygwin* | *mingw* ) + case $host in + *cygwin* | *mingw* ) if test "$build_libtool_libs" != yes; then wrappers_required=no fi - ;; + ;; *cegcc) # Disable wrappers for cegcc, we are cross compiling anyway. wrappers_required=no - ;; - *) + ;; + * ) if test "$need_relink" = no || test "$build_libtool_libs" != yes; then wrappers_required=no - fi - ;; - esac + fi + ;; + esac if test "$wrappers_required" = no; then # Replace the output file specification. compile_command=`$ECHO "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` @@ -7835,8 +7835,8 @@ EOF func_dirname_and_basename "$output" "" "." output_name=$func_basename_result output_path=$func_dirname_result - cwrappersource="$output_path/$objdir/lt-$output_name.c" - cwrapper="$output_path/$output_name.exe" + cwrappersource="$output_path/$objdir/lt-$output_name.c" + cwrapper="$output_path/$output_name.exe" $RM $cwrappersource $cwrapper trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 @@ -7849,7 +7849,7 @@ EOF $opt_dry_run || { $LTCC $LTCFLAGS -o $cwrapper $cwrappersource $STRIP $cwrapper - } + } # Now, create the wrapper script for func_source use: func_ltwrapper_scriptname $cwrapper @@ -7859,11 +7859,11 @@ EOF # note: this script will not be executed, so do not chmod. if test "x$build" = "x$host" ; then $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result - else + else func_emit_wrapper no > $func_ltwrapper_scriptname_result fi - } - ;; +} + ;; * ) $RM $output trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 @@ -7892,7 +7892,7 @@ EOF oldobjs="$old_deplibs $non_pic_objects" if test "$preload" = yes && test -f "$symfileobj"; then oldobjs="$oldobjs $symfileobj" - fi + fi fi addlibs="$old_convenience" fi @@ -7907,7 +7907,7 @@ EOF # Do each command in the archive commands. if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then - cmds=$old_archive_from_new_cmds + cmds=$old_archive_from_new_cmds else # Add any objects from preloaded convenience libraries @@ -7933,8 +7933,8 @@ EOF : else $ECHO "copying selected object files to avoid basename conflicts..." - gentop="$output_objdir/${outputname}x" - generated="$generated $gentop" + gentop="$output_objdir/${outputname}x" + generated="$generated $gentop" func_mkdir_p "$gentop" save_oldobjs=$oldobjs oldobjs= @@ -8000,7 +8000,7 @@ EOF # the above command should be used before it gets too long oldobjs=$objlist if test "$obj" = "$last_oldobj" ; then - RANLIB=$save_RANLIB + RANLIB=$save_RANLIB fi test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" @@ -8018,7 +8018,7 @@ EOF fi fi func_execute_cmds "$cmds" 'exit $?' - done + done test -n "$generated" && \ func_show_eval "${RM}r$generated" @@ -8079,10 +8079,10 @@ EOF *.la) func_basename "$lib" name="$func_basename_result" - eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "\`$lib' is not a valid libtool archive" - newdlfiles="$newdlfiles $libdir/$name" + newdlfiles="$newdlfiles $libdir/$name" ;; *) newdlfiles="$newdlfiles $lib" ;; esac @@ -8098,10 +8098,10 @@ EOF # the library: func_basename "$lib" name="$func_basename_result" - eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "\`$lib' is not a valid libtool archive" - newdlprefiles="$newdlprefiles $libdir/$name" + newdlprefiles="$newdlprefiles $libdir/$name" ;; esac done @@ -8187,7 +8187,7 @@ relink_command=\"$relink_command\"" ;; esac exit $EXIT_SUCCESS -} + } { test "$mode" = link || test "$mode" = relink; } && func_mode_link ${1+"$@"} @@ -8274,18 +8274,18 @@ func_mode_uninstall () *" $dlname "*) ;; *) rmfiles="$rmfiles $objdir/$dlname" ;; esac - test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" + test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" ;; uninstall) if test -n "$library_names"; then # Do each command in the postuninstall commands. func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' - fi + fi if test -n "$old_library"; then # Do each command in the old_postuninstall commands. func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' - fi + fi # FIXME: should reinstall the best remaining shared library. ;; esac @@ -8331,7 +8331,7 @@ func_mode_uninstall () if func_ltwrapper_p "$file"; then if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" - relink_command= + relink_command= func_source $func_ltwrapper_scriptname_result rmfiles="$rmfiles $func_ltwrapper_scriptname_result" else diff --git a/src/common/pa_converters.c b/src/common/pa_converters.c index 92daf8f..fe7a4e2 100644 --- a/src/common/pa_converters.c +++ b/src/common/pa_converters.c @@ -1,5 +1,5 @@ /* - * $Id$ + * $Id: pa_converters.c 1661 2011-04-28 18:54:46Z rob_bielik $ * Portable Audio I/O Library sample conversion mechanism * * Based on the Open Source API proposed by Ross Bencina @@ -45,7 +45,7 @@ @todo Consider whether functions which dither but don't clip should exist, V18 automatically enabled clipping whenever dithering was selected. Perhaps - we should do the same. + we should do the same. see: "require clipping for dithering sample conversion functions?" http://www.portaudio.com/trac/ticket/112 @@ -1167,8 +1167,8 @@ static void Int24_To_Int16_Dither( void *sourceBuffer, signed int sourceStride, unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator ) { - unsigned char *src = (unsigned char*)sourceBuffer; - PaInt16 *dest = (PaInt16*)destinationBuffer; + unsigned char *src = (unsigned char *)sourceBuffer; + PaInt16 *dest = (PaInt16 *)destinationBuffer; PaInt32 temp, dither; @@ -1189,7 +1189,7 @@ static void Int24_To_Int16_Dither( dither = PaUtil_Generate16BitTriangularDither( ditherGenerator ); *dest = (PaInt16) (((temp >> 1) + dither) >> 15); - src += sourceStride * 3; + src += sourceStride * 3; dest += destinationStride; } } @@ -1255,7 +1255,7 @@ static void Int24_To_Int8_Dither( src += sourceStride * 3; dest += destinationStride; - } +} } /* -------------------------------------------------------------------------- */ diff --git a/src/common/pa_front.c b/src/common/pa_front.c index 8dfa27d..5c6aae0 100644 --- a/src/common/pa_front.c +++ b/src/common/pa_front.c @@ -1,5 +1,5 @@ /* - * $Id$ + * $Id: pa_front.c 1673 2011-05-06 04:40:22Z rob_bielik $ * Portable Audio I/O Library Multi-Host API front end * Validate function parameters and manage multiple host APIs. * @@ -80,7 +80,8 @@ #define PA_VERSION_ 1899 #define PA_VERSION_TEXT_ "PortAudio V19-devel (built " __DATE__ " " __TIME__ ")" - +extern void PaUtil_InitializeHotPlug(); +extern void PaUtil_TerminateHotPlug(); int Pa_GetVersion( void ) @@ -113,16 +114,26 @@ void PaUtil_SetLastHostErrorInfo( PaHostApiTypeId hostApiType, long errorCode, } +typedef struct _PaInternalInfo +{ + PaUtilHostApiRepresentation **hostApis_; + int hostApisCount_; + int initializationCount_; + int deviceCount_; -static PaUtilHostApiRepresentation **hostApis_ = 0; -static int hostApisCount_ = 0; -static int initializationCount_ = 0; -static int deviceCount_ = 0; + PaUtilStreamRepresentation *firstOpenStream_; -PaUtilStreamRepresentation *firstOpenStream_ = NULL; + PaDevicesChangedCallback* devicesChangedCallback_; + void* devicesChangedCallbackUserData_; + +} PaInternalInfo; + +static PaInternalInfo paInternalInfo_ = {0}; -#define PA_IS_INITIALISED_ (initializationCount_ != 0) + + +#define PA_IS_INITIALISED_ (paInternalInfo_.initializationCount_ != 0) static int CountHostApiInitializers( void ) @@ -140,17 +151,17 @@ static void TerminateHostApis( void ) /* terminate in reverse order from initialization */ PA_DEBUG(("TerminateHostApis in \n")); - while( hostApisCount_ > 0 ) + while( paInternalInfo_.hostApisCount_ > 0 ) { - --hostApisCount_; - hostApis_[hostApisCount_]->Terminate( hostApis_[hostApisCount_] ); + --paInternalInfo_.hostApisCount_; + paInternalInfo_.hostApis_[paInternalInfo_.hostApisCount_]->Terminate( paInternalInfo_.hostApis_[paInternalInfo_.hostApisCount_] ); } - hostApisCount_ = 0; - deviceCount_ = 0; + paInternalInfo_.hostApisCount_ = 0; + paInternalInfo_.deviceCount_ = 0; - if( hostApis_ != 0 ) - PaUtil_FreeMemory( hostApis_ ); - hostApis_ = 0; + if( paInternalInfo_.hostApis_ != 0 ) + PaUtil_FreeMemory( paInternalInfo_.hostApis_ ); + paInternalInfo_.hostApis_ = 0; PA_DEBUG(("TerminateHostApis out\n")); } @@ -163,33 +174,33 @@ static PaError InitializeHostApis( void ) initializerCount = CountHostApiInitializers(); - hostApis_ = (PaUtilHostApiRepresentation**)PaUtil_AllocateMemory( + paInternalInfo_.hostApis_ = (PaUtilHostApiRepresentation**)PaUtil_AllocateMemory( sizeof(PaUtilHostApiRepresentation*) * initializerCount ); - if( !hostApis_ ) + if( !paInternalInfo_.hostApis_ ) { result = paInsufficientMemory; goto error; } - hostApisCount_ = 0; - deviceCount_ = 0; + paInternalInfo_.hostApisCount_ = 0; + paInternalInfo_.deviceCount_ = 0; baseDeviceIndex = 0; for( i=0; i< initializerCount; ++i ) { - hostApis_[hostApisCount_] = NULL; + paInternalInfo_.hostApis_[paInternalInfo_.hostApisCount_] = NULL; PA_DEBUG(( "before paHostApiInitializers[%d].\n",i)); - result = paHostApiInitializers[i]( &hostApis_[hostApisCount_], hostApisCount_ ); + result = paHostApiInitializers[i]( &paInternalInfo_.hostApis_[paInternalInfo_.hostApisCount_], paInternalInfo_.hostApisCount_ ); if( result != paNoError ) goto error; PA_DEBUG(( "after paHostApiInitializers[%d].\n",i)); - if( hostApis_[hostApisCount_] ) + if( paInternalInfo_.hostApis_[paInternalInfo_.hostApisCount_] ) { - PaUtilHostApiRepresentation* hostApi = hostApis_[hostApisCount_]; + PaUtilHostApiRepresentation* hostApi = paInternalInfo_.hostApis_[paInternalInfo_.hostApisCount_]; assert( hostApi->info.defaultInputDevice < hostApi->info.deviceCount ); assert( hostApi->info.defaultOutputDevice < hostApi->info.deviceCount ); @@ -202,9 +213,9 @@ static PaError InitializeHostApis( void ) hostApi->info.defaultOutputDevice += baseDeviceIndex; baseDeviceIndex += hostApi->info.deviceCount; - deviceCount_ += hostApi->info.deviceCount; + paInternalInfo_.deviceCount_ += hostApi->info.deviceCount; - ++hostApisCount_; + ++paInternalInfo_.hostApisCount_; } } @@ -233,15 +244,15 @@ static int FindHostApi( PaDeviceIndex device, int *hostSpecificDeviceIndex ) if( device < 0 ) return -1; - while( i < hostApisCount_ - && device >= hostApis_[i]->info.deviceCount ) + while( i < paInternalInfo_.hostApisCount_ + && device >= paInternalInfo_.hostApis_[i]->info.deviceCount ) { - device -= hostApis_[i]->info.deviceCount; + device -= paInternalInfo_.hostApis_[i]->info.deviceCount; ++i; } - if( i >= hostApisCount_ ) + if( i >= paInternalInfo_.hostApisCount_ ) return -1; if( hostSpecificDeviceIndex ) @@ -253,15 +264,15 @@ static int FindHostApi( PaDeviceIndex device, int *hostSpecificDeviceIndex ) static void AddOpenStream( PaStream* stream ) { - ((PaUtilStreamRepresentation*)stream)->nextOpenStream = firstOpenStream_; - firstOpenStream_ = (PaUtilStreamRepresentation*)stream; + ((PaUtilStreamRepresentation*)stream)->nextOpenStream = paInternalInfo_.firstOpenStream_; + paInternalInfo_.firstOpenStream_ = (PaUtilStreamRepresentation*)stream; } static void RemoveOpenStream( PaStream* stream ) { PaUtilStreamRepresentation *previous = NULL; - PaUtilStreamRepresentation *current = firstOpenStream_; + PaUtilStreamRepresentation *current = paInternalInfo_.firstOpenStream_; while( current != NULL ) { @@ -269,7 +280,7 @@ static void RemoveOpenStream( PaStream* stream ) { if( previous == NULL ) { - firstOpenStream_ = current->nextOpenStream; + paInternalInfo_.firstOpenStream_ = current->nextOpenStream; } else { @@ -291,8 +302,8 @@ static void CloseOpenStreams( void ) /* we call Pa_CloseStream() here to ensure that the same destruction logic is used for automatically closed streams */ - while( firstOpenStream_ != NULL ) - Pa_CloseStream( firstOpenStream_ ); + while( paInternalInfo_.firstOpenStream_ != NULL ) + Pa_CloseStream( paInternalInfo_.firstOpenStream_ ); } @@ -304,7 +315,7 @@ PaError Pa_Initialize( void ) if( PA_IS_INITIALISED_ ) { - ++initializationCount_; + ++paInternalInfo_.initializationCount_; result = paNoError; } else @@ -315,9 +326,12 @@ PaError Pa_Initialize( void ) PaUtil_InitializeClock(); PaUtil_ResetTraceMessages(); + /* Initialize hot plug here, so all its internal info is setup */ + PaUtil_InitializeHotPlug(); + result = InitializeHostApis(); if( result == paNoError ) - ++initializationCount_; + ++paInternalInfo_.initializationCount_; } PA_LOGAPI_EXIT_PAERROR( "Pa_Initialize", result ); @@ -334,12 +348,14 @@ PaError Pa_Terminate( void ) if( PA_IS_INITIALISED_ ) { - if( --initializationCount_ == 0 ) + if( --paInternalInfo_.initializationCount_ == 0 ) { CloseOpenStreams(); TerminateHostApis(); + PaUtil_TerminateHotPlug(); + PaUtil_DumpTraceMessages(); } result = paNoError; @@ -425,9 +441,9 @@ PaHostApiIndex Pa_HostApiTypeIdToHostApiIndex( PaHostApiTypeId type ) { result = paHostApiNotFound; - for( i=0; i < hostApisCount_; ++i ) + for( i=0; i < paInternalInfo_.hostApisCount_; ++i ) { - if( hostApis_[i]->info.type == type ) + if( paInternalInfo_.hostApis_[i]->info.type == type ) { result = i; break; @@ -455,11 +471,11 @@ PaError PaUtil_GetHostApiRepresentation( struct PaUtilHostApiRepresentation **ho { result = paHostApiNotFound; - for( i=0; i < hostApisCount_; ++i ) + for( i=0; i < paInternalInfo_.hostApisCount_; ++i ) { - if( hostApis_[i]->info.type == type ) + if( paInternalInfo_.hostApis_[i]->info.type == type ) { - *hostApi = hostApis_[i]; + *hostApi = paInternalInfo_.hostApis_[i]; result = paNoError; break; } @@ -504,7 +520,7 @@ PaHostApiIndex Pa_GetHostApiCount( void ) } else { - result = hostApisCount_; + result = paInternalInfo_.hostApisCount_; } PA_LOGAPI_EXIT_PAERROR_OR_T_RESULT( "Pa_GetHostApiCount", "PaHostApiIndex: %d", result ); @@ -530,7 +546,7 @@ PaHostApiIndex Pa_GetDefaultHostApi( void ) /* internal consistency check: make sure that the default host api index is within range */ - if( result < 0 || result >= hostApisCount_ ) + if( result < 0 || result >= paInternalInfo_.hostApisCount_ ) { result = paInternalError; } @@ -557,7 +573,7 @@ const PaHostApiInfo* Pa_GetHostApiInfo( PaHostApiIndex hostApi ) PA_LOGAPI(("\tPaHostApiInfo*: NULL [ PortAudio not initialized ]\n" )); } - else if( hostApi < 0 || hostApi >= hostApisCount_ ) + else if( hostApi < 0 || hostApi >= paInternalInfo_.hostApisCount_ ) { info = NULL; @@ -567,7 +583,7 @@ const PaHostApiInfo* Pa_GetHostApiInfo( PaHostApiIndex hostApi ) } else { - info = &hostApis_[hostApi]->info; + info = &paInternalInfo_.hostApis_[hostApi]->info; PA_LOGAPI(("Pa_GetHostApiInfo returned:\n" )); PA_LOGAPI(("\tPaHostApiInfo*: 0x%p\n", info )); @@ -597,20 +613,20 @@ PaDeviceIndex Pa_HostApiDeviceIndexToDeviceIndex( PaHostApiIndex hostApi, int ho } else { - if( hostApi < 0 || hostApi >= hostApisCount_ ) + if( hostApi < 0 || hostApi >= paInternalInfo_.hostApisCount_ ) { result = paInvalidHostApi; } else { if( hostApiDeviceIndex < 0 || - hostApiDeviceIndex >= hostApis_[hostApi]->info.deviceCount ) + hostApiDeviceIndex >= paInternalInfo_.hostApis_[hostApi]->info.deviceCount ) { result = paInvalidDevice; } else { - result = hostApis_[hostApi]->privatePaFrontInfo.baseDeviceIndex + hostApiDeviceIndex; + result = paInternalInfo_.hostApis_[hostApi]->privatePaFrontInfo.baseDeviceIndex + hostApiDeviceIndex; } } } @@ -633,7 +649,7 @@ PaDeviceIndex Pa_GetDeviceCount( void ) } else { - result = deviceCount_; + result = paInternalInfo_.deviceCount_; } PA_LOGAPI_EXIT_PAERROR_OR_T_RESULT( "Pa_GetDeviceCount", "PaDeviceIndex: %d", result ); @@ -656,7 +672,7 @@ PaDeviceIndex Pa_GetDefaultInputDevice( void ) } else { - result = hostApis_[hostApi]->info.defaultInputDevice; + result = paInternalInfo_.hostApis_[hostApi]->info.defaultInputDevice; } PA_LOGAPI_EXIT_T( "Pa_GetDefaultInputDevice", "PaDeviceIndex: %d", result ); @@ -679,7 +695,7 @@ PaDeviceIndex Pa_GetDefaultOutputDevice( void ) } else { - result = hostApis_[hostApi]->info.defaultOutputDevice; + result = paInternalInfo_.hostApis_[hostApi]->info.defaultOutputDevice; } PA_LOGAPI_EXIT_T( "Pa_GetDefaultOutputDevice", "PaDeviceIndex: %d", result ); @@ -688,6 +704,116 @@ PaDeviceIndex Pa_GetDefaultOutputDevice( void ) } +PaError Pa_UpdateAvailableDeviceList( void ) +{ + PaError result = paNoError; + void **scanResults = NULL; + int *deviceCounts = NULL; + int i = 0; + + PA_LOGAPI_ENTER( "Pa_UpdateAvailableDeviceList" ); + if( !PA_IS_INITIALISED_ ) + { + result = paNotInitialized; + goto done; + } + + /* Allocate data structures used in 2-stage commit */ + scanResults = (void **) PaUtil_AllocateMemory( sizeof(void*) * paInternalInfo_.hostApisCount_ ); + if( !scanResults ) + { + result = paInsufficientMemory; + goto done; + } + + deviceCounts = ( int * ) PaUtil_AllocateMemory( sizeof( int ) * paInternalInfo_.hostApisCount_ ); + if( !deviceCounts ) + { + result = paInsufficientMemory; + goto done; + } + + /* Phase 1: Perform a scan of new devices */ + for( i = 0 ; i < paInternalInfo_.hostApisCount_ ; ++i ) + { + PaUtilHostApiRepresentation *hostApi = paInternalInfo_.hostApis_[i]; + PA_DEBUG(( "Scanning new device list for host api %d.\n",i)); + if( hostApi->ScanDeviceInfos == NULL ) + continue; + + if( hostApi->ScanDeviceInfos( hostApi, i, &scanResults[ i ], &deviceCounts[ i ] ) != paNoError ) + break; + } + + /* Check the result of the scan operation */ + if( i < paInternalInfo_.hostApisCount_ ) + { + /* If failure, rollback the scan changes back to original state */ + int j = 0; + for( j = 0 ; j < i ; ++j ) + { + PaUtilHostApiRepresentation *hostApi = paInternalInfo_.hostApis_[j]; + if( hostApi->DisposeDeviceInfos == NULL ) + continue; + + PA_DEBUG(( "Performing rollback for device list scan for host api %d.\n",i)); + hostApi->DisposeDeviceInfos( hostApi, scanResults[ j ], deviceCounts[ j ] ); + } + } + else + { + int baseDeviceIndex = 0; + paInternalInfo_.deviceCount_ = 0; + + /* Otherwise, commit the scan changes to each back-end */ + for( i = 0 ; i < paInternalInfo_.hostApisCount_ ; ++i ) + { + PaUtilHostApiRepresentation *hostApi = paInternalInfo_.hostApis_[i]; + if( hostApi->CommitDeviceInfos == NULL ) + { + /* Not yet implemented for this backend. Just + assume that the baseDeviceIndex and the paInternalInfo_.deviceCount_ are + incremented according to the values in the info */ + baseDeviceIndex += hostApi->info.deviceCount; + paInternalInfo_.deviceCount_ += hostApi->info.deviceCount; + continue; + } + + PA_DEBUG(( "Committing device list scan for host api %d.\n",i)); + if( hostApi->CommitDeviceInfos( hostApi, i, scanResults[ i ], deviceCounts[ i ] ) != paNoError ) + { + PA_DEBUG(( "Committing failed (shouldn't happen) %d.\n",i)); + result = paInternalError; + goto done; + } + + assert( hostApi->info.defaultInputDevice < hostApi->info.deviceCount ); + assert( hostApi->info.defaultOutputDevice < hostApi->info.deviceCount ); + + hostApi->privatePaFrontInfo.baseDeviceIndex = baseDeviceIndex; + + if( hostApi->info.defaultInputDevice != paNoDevice ) + hostApi->info.defaultInputDevice += baseDeviceIndex; + + if( hostApi->info.defaultOutputDevice != paNoDevice ) + hostApi->info.defaultOutputDevice += baseDeviceIndex; + + baseDeviceIndex += hostApi->info.deviceCount; + paInternalInfo_.deviceCount_ += hostApi->info.deviceCount; + } + } + +done: + + if( scanResults ) + PaUtil_FreeMemory( scanResults ); + + if( deviceCounts ) + PaUtil_FreeMemory( deviceCounts ); + + return result; +} + const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceIndex device ) { int hostSpecificDeviceIndex; @@ -708,7 +834,7 @@ const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceIndex device ) } else { - result = hostApis_[hostApiIndex]->deviceInfos[ hostSpecificDeviceIndex ]; + result = paInternalInfo_.hostApis_[hostApiIndex]->deviceInfos[ hostSpecificDeviceIndex ]; PA_LOGAPI(("Pa_GetDeviceInfo returned:\n" )); PA_LOGAPI(("\tPaDeviceInfo*: 0x%p:\n", result )); @@ -850,7 +976,7 @@ static PaError ValidateOpenStreamParameters( if( inputHostApiIndex != -1 ) { *hostApiInputDevice = paUseHostApiSpecificDeviceSpecification; - *hostApi = hostApis_[inputHostApiIndex]; + *hostApi = paInternalInfo_.hostApis_[inputHostApiIndex]; } else { @@ -864,14 +990,14 @@ static PaError ValidateOpenStreamParameters( } else { - if( inputParameters->device < 0 || inputParameters->device >= deviceCount_ ) + if( inputParameters->device < 0 || inputParameters->device >= paInternalInfo_.deviceCount_ ) return paInvalidDevice; inputHostApiIndex = FindHostApi( inputParameters->device, hostApiInputDevice ); if( inputHostApiIndex < 0 ) return paInternalError; - *hostApi = hostApis_[inputHostApiIndex]; + *hostApi = paInternalInfo_.hostApis_[inputHostApiIndex]; if( inputParameters->channelCount <= 0 ) return paInvalidChannelCount; @@ -901,7 +1027,7 @@ static PaError ValidateOpenStreamParameters( if( outputHostApiIndex != -1 ) { *hostApiOutputDevice = paUseHostApiSpecificDeviceSpecification; - *hostApi = hostApis_[outputHostApiIndex]; + *hostApi = paInternalInfo_.hostApis_[outputHostApiIndex]; } else { @@ -915,14 +1041,14 @@ static PaError ValidateOpenStreamParameters( } else { - if( outputParameters->device < 0 || outputParameters->device >= deviceCount_ ) + if( outputParameters->device < 0 || outputParameters->device >= paInternalInfo_.deviceCount_ ) return paInvalidDevice; outputHostApiIndex = FindHostApi( outputParameters->device, hostApiOutputDevice ); if( outputHostApiIndex < 0 ) return paInternalError; - *hostApi = hostApis_[outputHostApiIndex]; + *hostApi = paInternalInfo_.hostApis_[outputHostApiIndex]; if( outputParameters->channelCount <= 0 ) return paInvalidChannelCount; @@ -1751,3 +1877,29 @@ PaError Pa_GetSampleSize( PaSampleFormat format ) return (PaError) result; } +extern void PaUtil_LockHotPlug(); +extern void PaUtil_UnlockHotPlug(); + + +PaError Pa_SetDevicesChangedCallback( void *userData, PaStreamFinishedCallback* devicesChangedCallback ) +{ + PaUtil_LockHotPlug(); + paInternalInfo_.devicesChangedCallback_ = devicesChangedCallback; + paInternalInfo_.devicesChangedCallbackUserData_ = userData; + PaUtil_UnlockHotPlug(); + return paNoError; +} + +/* Called whenever a OS audio device change has been detected */ +void PaUtil_DevicesChanged(unsigned state, void* pData) +{ + (void)state; + (void)pData; + PaUtil_LockHotPlug(); + if (paInternalInfo_.devicesChangedCallback_) + { + (paInternalInfo_.devicesChangedCallback_)(paInternalInfo_.devicesChangedCallbackUserData_); + } + PaUtil_UnlockHotPlug(); +} + diff --git a/src/common/pa_hostapi.h b/src/common/pa_hostapi.h index dda0f27..91e2172 100644 --- a/src/common/pa_hostapi.h +++ b/src/common/pa_hostapi.h @@ -1,7 +1,7 @@ #ifndef PA_HOSTAPI_H #define PA_HOSTAPI_H /* - * $Id$ + * $Id: pa_hostapi.h 1664 2011-05-01 16:10:58Z rossb $ * Portable Audio I/O Library * host api representation * @@ -275,6 +275,37 @@ typedef struct PaUtilHostApiRepresentation { const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate ); + + /** + Collect current native device information and compute a new device count. + This method should not result in the host API making any changes to its + internal data structures, instead it is the first step in a two-stage commit + process which will be completed only if all host API scans return with no errors. + + Some time later the caller will either (1) pass scanResults and newDeviceCount + to CommitDeviceInfos() to complete the transaction, or (2) pass scanResults + and newDeviceCount to DisposeDeviceInfos() to abort the transaction. + */ + PaError (*ScanDeviceInfos)( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index, void **scanResults, int *newDeviceCount ); + + /** + Replace the previous device information with the device information + passed in as an argument via scanResults. This is the second/final stage of + the two-stage transaction required for updating the available device information. + This function should free any resources associated with the previous device + information. + @FIXME: this function should probably not return an error code as it should not be + permitted to fail. + */ + PaError (*CommitDeviceInfos)( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index, void *scanResults, int deviceCount ); + + /** + Free device information previously returned by ScanDeviceInfos(). This function + will be called in cases where the update available device info transaction + failed for some reason. + */ + PaError (*DisposeDeviceInfos)( struct PaUtilHostApiRepresentation *hostApi, void *scanResults, int deviceCount ); + } PaUtilHostApiRepresentation; diff --git a/src/common/pa_process.c b/src/common/pa_process.c index 8d0500d..5892135 100644 --- a/src/common/pa_process.c +++ b/src/common/pa_process.c @@ -1,5 +1,5 @@ /* - * $Id$ + * $Id: pa_process.c 1661 2011-04-28 18:54:46Z rob_bielik $ * Portable Audio I/O Library * streamCallback <-> host buffer processing adapter * @@ -241,7 +241,7 @@ PaError PaUtil_InitializeBufferProcessor( PaUtilBufferProcessor* bp, bp->inputZeroer = PaUtil_SelectZeroer( hostInputSampleFormat ); bp->userInputIsInterleaved = (userInputSampleFormat & paNonInterleaved)?0:1; - + bp->hostInputIsInterleaved = (hostInputSampleFormat & paNonInterleaved)?0:1; bp->userInputSampleFormatIsEqualToHost = ((userInputSampleFormat & ~paNonInterleaved) == (hostInputSampleFormat & ~paNonInterleaved)); @@ -735,7 +735,7 @@ static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp, } else /* there are input channels */ { - + destBytePtr = (unsigned char *)bp->tempInputBuffer; if( bp->userInputIsInterleaved ) @@ -746,10 +746,10 @@ static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp, /* process host buffer directly, or use temp buffer if formats differ or host buffer non-interleaved */ if( bp->userInputSampleFormatIsEqualToHost && bp->hostInputIsInterleaved && bp->hostInputChannels[0][0].data) { - userInput = hostInputChannels[0].data; - destBytePtr = (unsigned char *)hostInputChannels[0].data; + userInput = hostInputChannels[0].data; + destBytePtr = (unsigned char *)hostInputChannels[0].data; skipInputConvert = 1; - } + } else { userInput = bp->tempInputBuffer; @@ -763,8 +763,8 @@ static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp, /* setup non-interleaved ptrs */ if( bp->userInputSampleFormatIsEqualToHost && !bp->hostInputIsInterleaved && bp->hostInputChannels[0][0].data ) { - for( i=0; iinputChannelCount; ++i ) - { + for( i=0; iinputChannelCount; ++i ) + { bp->tempInputBufferPtrs[i] = hostInputChannels[i].data; } skipInputConvert = 1; @@ -773,9 +773,9 @@ static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp, { for( i=0; iinputChannelCount; ++i ) { - bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) + - i * bp->bytesPerUserInputSample * frameCount; - } + bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) + + i * bp->bytesPerUserInputSample * frameCount; + } } userInput = bp->tempInputBufferPtrs; @@ -793,11 +793,11 @@ static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp, } } else - { + { if( skipInputConvert ) { - for( i=0; iinputChannelCount; ++i ) - { + for( i=0; iinputChannelCount; ++i ) + { /* advance src ptr for next iteration */ hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) + frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample; @@ -807,20 +807,20 @@ static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp, { for( i=0; iinputChannelCount; ++i ) { - bp->inputConverter( destBytePtr, destSampleStrideSamples, - hostInputChannels[i].data, - hostInputChannels[i].stride, - frameCount, &bp->ditherGenerator ); + bp->inputConverter( destBytePtr, destSampleStrideSamples, + hostInputChannels[i].data, + hostInputChannels[i].stride, + frameCount, &bp->ditherGenerator ); - destBytePtr += destChannelStrideBytes; /* skip to next destination channel */ + destBytePtr += destChannelStrideBytes; /* skip to next destination channel */ - /* advance src ptr for next iteration */ - hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) + - frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample; - } + /* advance src ptr for next iteration */ + hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) + + frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample; } } } + } /* configure user output buffer */ if( bp->outputChannelCount == 0 ) @@ -835,9 +835,9 @@ static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp, /* process host buffer directly, or use temp buffer if formats differ or host buffer non-interleaved */ if( bp->userOutputSampleFormatIsEqualToHost && bp->hostOutputIsInterleaved ) { - userOutput = hostOutputChannels[0].data; + userOutput = hostOutputChannels[0].data; skipOutputConvert = 1; - } + } else { userOutput = bp->tempOutputBuffer; @@ -847,8 +847,8 @@ static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp, { if( bp->userOutputSampleFormatIsEqualToHost && !bp->hostOutputIsInterleaved ) { - for( i=0; ioutputChannelCount; ++i ) - { + for( i = 0; i < bp->outputChannelCount; ++i ) + { bp->tempOutputBufferPtrs[i] = hostOutputChannels[i].data; } skipOutputConvert = 1; @@ -857,9 +857,9 @@ static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp, { for( i=0; ioutputChannelCount; ++i ) { - bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) + - i * bp->bytesPerUserOutputSample * frameCount; - } + bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) + + i * bp->bytesPerUserOutputSample * frameCount; + } } userOutput = bp->tempOutputBufferPtrs; @@ -894,34 +894,34 @@ static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp, } else { + + srcBytePtr = (unsigned char *)bp->tempOutputBuffer; - srcBytePtr = (unsigned char *)bp->tempOutputBuffer; + if( bp->userOutputIsInterleaved ) + { + srcSampleStrideSamples = bp->outputChannelCount; + srcChannelStrideBytes = bp->bytesPerUserOutputSample; + } + else /* user output is not interleaved */ + { + srcSampleStrideSamples = 1; + srcChannelStrideBytes = frameCount * bp->bytesPerUserOutputSample; + } - if( bp->userOutputIsInterleaved ) - { - srcSampleStrideSamples = bp->outputChannelCount; - srcChannelStrideBytes = bp->bytesPerUserOutputSample; - } - else /* user output is not interleaved */ - { - srcSampleStrideSamples = 1; - srcChannelStrideBytes = frameCount * bp->bytesPerUserOutputSample; - } + for( i=0; ioutputChannelCount; ++i ) + { + bp->outputConverter( hostOutputChannels[i].data, + hostOutputChannels[i].stride, + srcBytePtr, srcSampleStrideSamples, + frameCount, &bp->ditherGenerator ); - for( i=0; ioutputChannelCount; ++i ) - { - bp->outputConverter( hostOutputChannels[i].data, - hostOutputChannels[i].stride, - srcBytePtr, srcSampleStrideSamples, - frameCount, &bp->ditherGenerator ); + srcBytePtr += srcChannelStrideBytes; /* skip to next source channel */ - srcBytePtr += srcChannelStrideBytes; /* skip to next source channel */ - - /* advance dest ptr for next iteration */ - hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) + - frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample; - } - } + /* advance dest ptr for next iteration */ + hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) + + frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample; + } + } } framesProcessed += frameCount; diff --git a/src/hostapi/alsa/pa_linux_alsa.c b/src/hostapi/alsa/pa_linux_alsa.c index edbbc80..4680652 100644 --- a/src/hostapi/alsa/pa_linux_alsa.c +++ b/src/hostapi/alsa/pa_linux_alsa.c @@ -1,5 +1,5 @@ /* - * $Id$ + * $Id: pa_linux_alsa.c 1661 2011-04-28 18:54:46Z rob_bielik $ * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com * ALSA implementation by Joshua Haberman and Arve Knudsen @@ -668,6 +668,15 @@ typedef struct PaAlsaDeviceInfo } PaAlsaDeviceInfo; +/* used for tranferring device infos during scanning / rescanning */ +typedef struct PaLinuxScanDeviceInfosResults +{ + PaDeviceInfo **deviceInfos; + PaDeviceIndex defaultInputDevice; + PaDeviceIndex defaultOutputDevice; + int deviceCount; +} PaLinuxScanDeviceInfosResults; + /* prototypes for functions declared in this file */ static void Terminate( struct PaUtilHostApiRepresentation *hostApi ); @@ -692,10 +701,17 @@ static PaError IsStreamStopped( PaStream *s ); static PaError IsStreamActive( PaStream *stream ); static PaTime GetStreamTime( PaStream *stream ); static double GetStreamCpuLoad( PaStream* stream ); -static PaError BuildDeviceList( PaAlsaHostApiRepresentation *hostApi ); +static PaError BuildDeviceList( PaAlsaHostApiRepresentation *hostApi, void** scanResults, int* deviceCount ); static int SetApproximateSampleRate( snd_pcm_t *pcm, snd_pcm_hw_params_t *hwParams, double sampleRate ); static int GetExactSampleRate( snd_pcm_hw_params_t *hwParams, double *sampleRate ); +static PaError ScanDeviceInfos(struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index, + void **newDeviceInfos, int *newDeviceCount ); +static PaError CommitDeviceInfos(struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index, + void *deviceInfos, int deviceCount); +static PaError DisposeDeviceInfos(struct PaUtilHostApiRepresentation *hostApi, void *deviceInfos, + int deviceCount ); + /* Callback prototypes */ static void *CallbackThreadFunc( void *userData ); @@ -722,6 +738,8 @@ PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex { PaError result = paNoError; PaAlsaHostApiRepresentation *alsaHostApi = NULL; + void* scanResults = NULL; + int deviceCount = 0; /* Try loading Alsa library. */ if (!PaAlsa_LoadLibrary()) @@ -733,20 +751,29 @@ PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex alsaHostApi->hostApiIndex = hostApiIndex; *hostApi = (PaUtilHostApiRepresentation*)alsaHostApi; + (*hostApi)->deviceInfos = NULL; (*hostApi)->info.structVersion = 1; (*hostApi)->info.type = paALSA; (*hostApi)->info.name = "ALSA"; + (*hostApi)->ScanDeviceInfos = NULL; + (*hostApi)->CommitDeviceInfos = NULL; + (*hostApi)->DisposeDeviceInfos = NULL; (*hostApi)->Terminate = Terminate; (*hostApi)->OpenStream = OpenStream; (*hostApi)->IsFormatSupported = IsFormatSupported; + (*hostApi)->ScanDeviceInfos = ScanDeviceInfos; + (*hostApi)->CommitDeviceInfos = CommitDeviceInfos; + (*hostApi)->DisposeDeviceInfos = DisposeDeviceInfos; /** If AlsaErrorHandler is to be used, do not forget to unregister callback pointer in Terminate function. */ /*ENSURE_( snd_lib_error_set_handler(AlsaErrorHandler), paUnanticipatedHostError );*/ - PA_ENSURE( BuildDeviceList( alsaHostApi ) ); + ScanDeviceInfos(&alsaHostApi->baseHostApiRep, hostApiIndex, &scanResults, + &deviceCount); + CommitDeviceInfos(&alsaHostApi->baseHostApiRep, hostApiIndex, scanResults, deviceCount); PaUtil_InitializeStreamInterface( &alsaHostApi->callbackStreamInterface, CloseStream, StartStream, @@ -802,7 +829,11 @@ static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) } PaUtil_FreeMemory( alsaHostApi ); - alsa_snd_config_update_free_global(); +// damencho, removed fo compability with pulseaudio versions before 0.9.16 +// segfault application: +// bugtrack alsa: 0002124: snd_config_update_free_global kills applications using user space alsa plugins +// snd_config_update_free_global(); +// alsa_snd_config_update_free_global(); /* Close Alsa library. */ PaAlsa_CloseLibrary(); @@ -1075,7 +1106,7 @@ static int OpenPcm( snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t stream, } static PaError FillInDevInfo( PaAlsaHostApiRepresentation *alsaApi, HwDevInfo* deviceName, int blocking, - PaAlsaDeviceInfo* devInfo, int* devIdx ) + PaAlsaDeviceInfo* devInfo, int* devIdx, PaLinuxScanDeviceInfosResults* out ) { PaError result = 0; PaDeviceInfo *baseDeviceInfo = &devInfo->baseDeviceInfo; @@ -1128,20 +1159,20 @@ static PaError FillInDevInfo( PaAlsaHostApiRepresentation *alsaApi, HwDevInfo* d if( baseDeviceInfo->maxInputChannels > 0 || baseDeviceInfo->maxOutputChannels > 0 ) { /* Make device default if there isn't already one or it is the ALSA "default" device */ - if( (baseApi->info.defaultInputDevice == paNoDevice || !strcmp(deviceName->alsaName, + if( (out->defaultInputDevice == paNoDevice || !strcmp(deviceName->alsaName, "default" )) && baseDeviceInfo->maxInputChannels > 0 ) { - baseApi->info.defaultInputDevice = *devIdx; + out->defaultInputDevice = *devIdx; PA_DEBUG(("Default input device: %s\n", deviceName->name)); } - if( (baseApi->info.defaultOutputDevice == paNoDevice || !strcmp(deviceName->alsaName, + if( (out->defaultOutputDevice == paNoDevice || !strcmp(deviceName->alsaName, "default" )) && baseDeviceInfo->maxOutputChannels > 0 ) { - baseApi->info.defaultOutputDevice = *devIdx; + out->defaultOutputDevice = *devIdx; PA_DEBUG(("Default output device: %s\n", deviceName->name)); } PA_DEBUG(("%s: Adding device %s: %d\n", __FUNCTION__, deviceName->name, *devIdx)); - baseApi->deviceInfos[*devIdx] = (PaDeviceInfo *) devInfo; + out->deviceInfos[*devIdx] = (PaDeviceInfo *) devInfo; (*devIdx) += 1; } else @@ -1154,9 +1185,10 @@ end: } /* Build PaDeviceInfo list, ignore devices for which we cannot determine capabilities (possibly busy, sigh) */ -static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi ) +static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi, void** scanResults, int* count) { PaUtilHostApiRepresentation *baseApi = &alsaApi->baseHostApiRep; + PaLinuxScanDeviceInfosResults *outArgument = NULL; PaAlsaDeviceInfo *deviceInfoArray; int cardIdx = -1, devIdx = 0; snd_ctl_card_info_t *cardInfo; @@ -1171,13 +1203,11 @@ static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi ) #ifdef PA_ENABLE_DEBUG_OUTPUT PaTime startTime = PaUtil_GetTime(); #endif + PaLinuxScanDeviceInfosResults* out = NULL; if( getenv( "PA_ALSA_INITIALIZE_BLOCK" ) && atoi( getenv( "PA_ALSA_INITIALIZE_BLOCK" ) ) ) blocking = 0; - /* These two will be set to the first working input and output device, respectively */ - baseApi->info.defaultInputDevice = paNoDevice; - baseApi->info.defaultOutputDevice = paNoDevice; /* Gather info about hw devices @@ -1341,8 +1371,14 @@ static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi ) else PA_DEBUG(( "%s: Iterating over ALSA plugins failed: %s\n", __FUNCTION__, alsa_snd_strerror( res ) )); + out = (PaLinuxScanDeviceInfosResults *) PaUtil_GroupAllocateMemory( + alsaApi->allocations, sizeof(PaLinuxScanDeviceInfosResults) ); + + out->defaultInputDevice = paNoDevice; + out->defaultOutputDevice = paNoDevice; + /* allocate deviceInfo memory based on the number of devices */ - PA_UNLESS( baseApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( + PA_UNLESS( out->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( alsaApi->allocations, sizeof(PaDeviceInfo*) * (numDeviceNames) ), paInsufficientMemory ); /* allocate all device info structs in a contiguous block */ @@ -1367,7 +1403,7 @@ static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi ) continue; } - PA_ENSURE( FillInDevInfo( alsaApi, hwInfo, blocking, devInfo, &devIdx ) ); + PA_ENSURE( FillInDevInfo( alsaApi, hwInfo, blocking, devInfo, &devIdx, out ) ); } assert( devIdx < numDeviceNames ); /* Now inspect 'dmix' and 'default' plugins */ @@ -1381,11 +1417,13 @@ static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi ) } PA_ENSURE( FillInDevInfo( alsaApi, hwInfo, blocking, devInfo, - &devIdx ) ); + &devIdx, out ) ); } free( hwDevInfos ); - baseApi->info.deviceCount = devIdx; /* Number of successfully queried devices */ + out->deviceCount = devIdx; /* Number of successfully queried devices */ + *scanResults = out; + *count = out->deviceCount; #ifdef PA_ENABLE_DEBUG_OUTPUT PA_DEBUG(( "%s: Building device list took %f seconds\n", __FUNCTION__, PaUtil_GetTime() - startTime )); @@ -2037,7 +2075,7 @@ static PaError PaAlsaStreamComponent_FinishConfigure( PaAlsaStreamComponent *sel ENSURE_( alsa_snd_pcm_sw_params_set_avail_min( self->pcm, swParams, self->framesPerBuffer ), paUnanticipatedHostError ); ENSURE_( alsa_snd_pcm_sw_params_set_xfer_align( self->pcm, swParams, 1 ), paUnanticipatedHostError ); - ENSURE_( alsa_snd_pcm_sw_params_set_tstamp_mode( self->pcm, swParams, SND_PCM_TSTAMP_ENABLE ), paUnanticipatedHostError ); + ENSURE_( alsa_snd_pcm_sw_params_set_tstamp_mode( self->pcm, swParams, SND_PCM_TSTAMP_MMAP ), paUnanticipatedHostError ); /* Set the parameters! */ ENSURE_( alsa_snd_pcm_sw_params( self->pcm, swParams ), paUnanticipatedHostError ); @@ -2194,7 +2232,7 @@ static PaError PaAlsaStreamComponent_DetermineFramesPerBuffer( PaAlsaStreamCompo #ifdef PA_ALSA_USE_OBSOLETE_HOST_BUFFER_CALC if( framesPerUserBuffer != paFramesPerBufferUnspecified ) - { + { /* Preferably the host buffer size should be a multiple of the user buffer size */ if( bufferSize > framesPerUserBuffer ) @@ -2271,7 +2309,7 @@ static PaError PaAlsaStreamComponent_DetermineFramesPerBuffer( PaAlsaStreamCompo else if( alsa_snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer / 2, 0 ) == 0 ) framesPerHostBuffer /= 2; - } + } } else { @@ -2291,7 +2329,7 @@ static PaError PaAlsaStreamComponent_DetermineFramesPerBuffer( PaAlsaStreamCompo #ifdef PA_ALSA_USE_OBSOLETE_HOST_BUFFER_CALC if( framesPerUserBuffer != paFramesPerBufferUnspecified ) - { + { /* Try to get a power-of-two of the user buffer size. */ framesPerHostBuffer = framesPerUserBuffer; if( framesPerHostBuffer < bufferSize ) @@ -2373,9 +2411,9 @@ static PaError PaAlsaStreamComponent_DetermineFramesPerBuffer( PaAlsaStreamCompo framesPerHostBuffer = ((minmax_diff == 2) ? max - 1 : max); } - PA_DEBUG(( "%s: device period minimum = %lu\n", __FUNCTION__, min )); - PA_DEBUG(( "%s: device period maximum = %lu\n", __FUNCTION__, max )); - PA_DEBUG(( "%s: host buffer period = %lu\n", __FUNCTION__, framesPerHostBuffer )); + PA_DEBUG(( "%s: device period minimum = %lu\n", __FUNCTION__, min )); + PA_DEBUG(( "%s: device period maximum = %lu\n", __FUNCTION__, max )); + PA_DEBUG(( "%s: host buffer period = %lu\n", __FUNCTION__, framesPerHostBuffer )); PA_DEBUG(( "%s: host buffer period latency = %f\n", __FUNCTION__, (double)(framesPerHostBuffer / sampleRate) )); /* Try setting period size */ @@ -3137,7 +3175,7 @@ error: ENSURE_( alsa_snd_pcm_hw_params_get_rate_min( hwParams, &_min, &_dir ), paUnanticipatedHostError ); ENSURE_( alsa_snd_pcm_hw_params_get_rate_max( hwParams, &_max, &_dir ), paUnanticipatedHostError ); PA_DEBUG(( "%s: SR min = %d, max = %d, req = %lu\n", __FUNCTION__, _min, _max, approx )); - } +} goto end; } @@ -3544,8 +3582,19 @@ static PaError PaAlsaStreamComponent_GetAvailableFrames( PaAlsaStreamComponent * snd_pcm_sframes_t framesAvail = alsa_snd_pcm_avail_update( self->pcm ); *xrunOccurred = 0; - if( -EPIPE == framesAvail ) - { + /* Get pcm_state and check for xrun condition. On playback I often see + * xrun but avail_update does not return -EPIPE but framesAvail larger + * than bufferSize. In case of xrun status set xrun flag, leave framesize + * as reported by avail_update, will be fixed below. In case avail_update + * returns -EPIPE process as usual. wd-xxx + */ + snd_pcm_state_t state = snd_pcm_state( self->pcm ); /* wd-xxx */ + if (state == SND_PCM_STATE_XRUN) { + // printf("xrun, fav %d\n", framesAvail); fflush(stdout); // DEBUG-WD + *xrunOccurred = 1; + } + if( -EPIPE == framesAvail) { + // printf("xrun-1, fav %d\n", framesAvail); fflush(stdout); // DEBUG-WD *xrunOccurred = 1; framesAvail = 0; } @@ -3554,6 +3603,11 @@ static PaError PaAlsaStreamComponent_GetAvailableFrames( PaAlsaStreamComponent * ENSURE_( framesAvail, paUnanticipatedHostError ); } + /* Fix frames avail, should not be bigger than bufferSize wd-xxx */ + if (framesAvail > self->bufferSize) { + // printf("xrun-2, fav %d\n", framesAvail); fflush(stdout); // DEBUG-WD + framesAvail = self->bufferSize; + } *numFrames = framesAvail; error: @@ -3603,6 +3657,13 @@ static PaError PaAlsaStreamComponent_EndPolling( PaAlsaStreamComponent* self, st *shouldPoll = 0; } + else + { + // not actually used + unsigned long framesAvail = 0; + // now check for xrun + PaAlsaStreamComponent_GetAvailableFrames(self, &framesAvail, xrun ); + } error: return result; @@ -3693,6 +3754,10 @@ static PaError PaAlsaStream_WaitForFrames( PaAlsaStream *self, unsigned long *fr framesAvail, &xrun ) ); if( xrun ) { + if(*framesAvail == 0) + { + result = paInternalError; + } goto end; } @@ -3740,6 +3805,7 @@ static PaError PaAlsaStream_WaitForFrames( PaAlsaStream *self, unsigned long *fr Pa_Sleep( 1 ); /* avoid hot loop */ continue; } + result = paInternalError; /* TODO: Add macro for checking system calls */ PA_ENSURE( paInternalError ); @@ -3769,6 +3835,7 @@ static PaError PaAlsaStream_WaitForFrames( PaAlsaStream *self, unsigned long *fr xrun = 1; /* try recovering device */ PA_DEBUG(( "%s: poll timed out\n", __FUNCTION__, timeouts )); + result = paTimedOut; goto end;/*PA_ENSURE( paTimedOut );*/ } } @@ -4144,7 +4211,7 @@ static void *CallbackThreadFunc( void *userData ) int xrun = 0; #ifdef PTHREAD_CANCELED - pthread_testcancel(); + pthread_testcancel(); #endif /* @concern StreamStop if the main thread has requested a stop and the stream has not been effectively @@ -4194,7 +4261,7 @@ static void *CallbackThreadFunc( void *userData ) xrun = 0; #ifdef PTHREAD_CANCELED - pthread_testcancel(); + pthread_testcancel(); #endif /** @concern Xruns Under/overflows are to be reported to the callback */ @@ -4326,9 +4393,24 @@ static PaError ReadStream( PaStream* s, void *buffer, unsigned long frames ) while( frames > 0 ) { int xrun = 0; - PA_ENSURE( PaAlsaStream_WaitForFrames( stream, &framesAvail, &xrun ) ); - framesGot = PA_MIN( framesAvail, frames ); + PA_ENSURE( PaAlsaStream_WaitForFrames( stream, &framesAvail, &xrun ) ); + /* + * In case of overrun WaitForFrames leaves the capture stream in STATE_PREPARED + * most of the time. handleXrun() restarts the ALSA stream only in case + * snd_pcm_recover() fails, which usually does not happen. + * Here we start the pcm stream again and go for another try. Another + * option is: set result to paOverrun and return to caller. Then + * the caller needs to call ReadStream again. This takes more time and + * we lose even more frames. + */ + if (xrun) { /* wd-xxx */ + if( snd_pcm_state( stream->capture.pcm ) == SND_PCM_STATE_PREPARED ) { + ENSURE_( snd_pcm_start( stream->capture.pcm ), paUnanticipatedHostError ); + } + continue; + } + framesGot = PA_MIN( framesAvail, frames ); PA_ENSURE( PaAlsaStream_SetUpBuffers( stream, &framesGot, &xrun ) ); if( framesGot > 0 ) { @@ -4546,3 +4628,75 @@ PaError PaAlsa_SetRetriesBusy( int retries ) busyRetries_ = retries; return paNoError; } + +static PaError ScanDeviceInfos(struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex hostApiIndex, + void **scanResults, int *newDeviceCount) +{ + PaAlsaHostApiRepresentation* alsaHostApi = (PaAlsaHostApiRepresentation*)hostApi; + PaError result = paNoError; + PA_ENSURE(BuildDeviceList( alsaHostApi, scanResults, newDeviceCount )); + + return paNoError; + +error: + return result; +} + +static PaError CommitDeviceInfos(struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index, + void *scanResults, int deviceCount) +{ + PaAlsaHostApiRepresentation* alsaHostApi = (PaAlsaHostApiRepresentation*)hostApi; + PaError result = paNoError; + + /* These two will be set to the first working input and output device, respectively */ + hostApi->info.defaultInputDevice = paNoDevice; + hostApi->info.defaultOutputDevice = paNoDevice; + + /* Free any old memory which might be in the device info */ + if( hostApi->deviceInfos ) + { + /* all device info structs are allocated in a block so we can destroy them here */ + PaUtil_GroupFreeMemory( alsaHostApi->allocations, hostApi->deviceInfos[0] ); + PaUtil_GroupFreeMemory( alsaHostApi->allocations, hostApi->deviceInfos ); + hostApi->deviceInfos = NULL; + } + + if( scanResults != NULL ) + { + PaLinuxScanDeviceInfosResults *scanDeviceInfosResults = ( PaLinuxScanDeviceInfosResults * ) scanResults; + + if( deviceCount > 0 ) + { + /* use the array allocated in ScanDeviceInfos() as our deviceInfos */ + hostApi->deviceInfos = scanDeviceInfosResults->deviceInfos; + hostApi->info.defaultInputDevice = scanDeviceInfosResults->defaultInputDevice; + hostApi->info.defaultOutputDevice = scanDeviceInfosResults->defaultOutputDevice; + hostApi->info.deviceCount = deviceCount; + } + + PaUtil_GroupFreeMemory( alsaHostApi->allocations, scanDeviceInfosResults ); + } + + return result; +} + +static PaError DisposeDeviceInfos(struct PaUtilHostApiRepresentation *hostApi, void *scanResults, int deviceCount) +{ + PaAlsaHostApiRepresentation *alsaHostApi = (PaAlsaHostApiRepresentation*)hostApi; + + if( scanResults != NULL ) + { + PaLinuxScanDeviceInfosResults *scanDeviceInfosResults = ( PaLinuxScanDeviceInfosResults * ) scanResults; + if( scanDeviceInfosResults->deviceInfos ) + { + /* all device info structs are allocated in a block so we can destroy them here */ + PaUtil_GroupFreeMemory( alsaHostApi->allocations, scanDeviceInfosResults->deviceInfos[0] ); + PaUtil_GroupFreeMemory( alsaHostApi->allocations, scanDeviceInfosResults->deviceInfos ); + } + + PaUtil_GroupFreeMemory(alsaHostApi->allocations, scanDeviceInfosResults ); + } + + return paNoError; +} + diff --git a/src/hostapi/asio/pa_asio.cpp b/src/hostapi/asio/pa_asio.cpp index d77c7e7..ff8ea3e 100644 --- a/src/hostapi/asio/pa_asio.cpp +++ b/src/hostapi/asio/pa_asio.cpp @@ -1,5 +1,5 @@ /* - * $Id$ + * $Id: pa_asio.cpp 1661 2011-04-28 18:54:46Z rob_bielik $ * Portable Audio I/O Library for ASIO Drivers * * Author: Stephane Letz @@ -1315,6 +1315,9 @@ PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex } + (*hostApi)->ScanDeviceInfos = NULL; + (*hostApi)->CommitDeviceInfos = NULL; + (*hostApi)->DisposeDeviceInfos = NULL; (*hostApi)->Terminate = Terminate; (*hostApi)->OpenStream = OpenStream; (*hostApi)->IsFormatSupported = IsFormatSupported; diff --git a/src/hostapi/coreaudio/pa_mac_core.c b/src/hostapi/coreaudio/pa_mac_core.c index d1decc9..08a38aa 100644 --- a/src/hostapi/coreaudio/pa_mac_core.c +++ b/src/hostapi/coreaudio/pa_mac_core.c @@ -67,6 +67,8 @@ #include /* strlen(), memcmp() etc. */ #include +#include + #include "pa_mac_core.h" #include "pa_mac_core_utilities.h" #include "pa_mac_core_blocking.h" @@ -80,6 +82,27 @@ extern "C" /* prototypes for functions declared in this file */ PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index ); +static PaError ScanDeviceInfos(struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index, + void **newDeviceInfos, int *newDeviceCount ); +static PaError CommitDeviceInfos(struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index, + void *deviceInfos, int deviceCount); +static PaError DisposeDeviceInfos(struct PaUtilHostApiRepresentation *hostApi, void *deviceInfos, + int deviceCount ); + +/* structures */ + +/* used for tranferring device infos during scanning / rescanning */ +typedef struct PaMacScanDeviceInfosResults +{ + PaDeviceInfo **deviceInfos; + PaDeviceIndex defaultInputDevice; + PaDeviceIndex defaultOutputDevice; + + AudioDeviceID* devIds; + int devCount; + AudioDeviceID devInputDevice; + AudioDeviceID devOutputDevice; +} PaMacScanDeviceInfosResults; /* * Function declared in pa_mac_core.h. Sets up a PaMacCoreStreamInfoStruct @@ -132,7 +155,6 @@ const char *PaMacCore_GetChannelName( int device, int channelIndex, bool input ) return NULL; PaMacAUHAL *macCoreHostApi = (PaMacAUHAL*)hostApi; AudioDeviceID hostApiDevice = macCoreHostApi->devIds[device]; - UInt32 size = 0; error = AudioDeviceGetPropertyInfo( hostApiDevice, @@ -311,46 +333,57 @@ static void startStopCallback( } -/*currently, this is only used in initialization, but it might be modified - to be used when the list of devices changes.*/ -static PaError gatherDeviceInfo(PaMacAUHAL *auhalHostApi) +//static PaError gatherDeviceInfo(PaMacAUHAL *auhalHostApi) +static PaError gatherDeviceInfo(PaMacAUHAL* auhalHostApi, void** scanResults, int* count) { - UInt32 size; - UInt32 propsize; - VVDBUG(("gatherDeviceInfo()\n")); - /* -- free any previous allocations -- */ - if( auhalHostApi->devIds ) - PaUtil_GroupFreeMemory(auhalHostApi->allocations, auhalHostApi->devIds); - auhalHostApi->devIds = NULL; + UInt32 propsize = 0; + UInt32 size = sizeof(AudioDeviceID); + PaMacScanDeviceInfosResults *outArgument = NULL; + PaError result = paNoError; + VVDBUG(("gatherDeviceInfo()\n")); /* -- figure out how many devices there are -- */ AudioHardwareGetPropertyInfo( kAudioHardwarePropertyDevices, &propsize, NULL ); - auhalHostApi->devCount = propsize / sizeof( AudioDeviceID ); + *count = (propsize / sizeof(AudioDeviceID)); - VDBUG( ( "Found %ld device(s).\n", auhalHostApi->devCount ) ); + VDBUG( ( "Found %ld device(s).\n", *count ) ); + + if(*count == 0) + return paNoError; + + /* Allocate the out param for all the info we need */ + outArgument = (PaMacScanDeviceInfosResults *) PaUtil_GroupAllocateMemory( + auhalHostApi->allocations, sizeof(PaMacScanDeviceInfosResults) ); + + if( !outArgument ) + { + result = paInsufficientMemory; + return result; + } + + outArgument->devCount = *count; /* -- copy the device IDs -- */ - auhalHostApi->devIds = (AudioDeviceID *)PaUtil_GroupAllocateMemory( + outArgument->devIds = (AudioDeviceID *)PaUtil_GroupAllocateMemory( auhalHostApi->allocations, propsize ); - if( !auhalHostApi->devIds ) + if( !outArgument->devIds ) return paInsufficientMemory; AudioHardwareGetProperty( kAudioHardwarePropertyDevices, &propsize, - auhalHostApi->devIds ); + outArgument->devIds ); #ifdef MAC_CORE_VERBOSE_DEBUG { int i; - for( i=0; idevCount; ++i ) - printf( "Device %d\t: %ld\n", i, auhalHostApi->devIds[i] ); + for( i=0; idevCount; ++i ) + printf( "Device %d\t: %ld\n", i, outArgument->devIds[i] ); } #endif - size = sizeof(AudioDeviceID); - auhalHostApi->defaultIn = kAudioDeviceUnknown; - auhalHostApi->defaultOut = kAudioDeviceUnknown; + outArgument->devInputDevice = kAudioDeviceUnknown; + outArgument->devOutputDevice = kAudioDeviceUnknown; /* determine the default device. */ /* I am not sure how these calls to AudioHardwareGetProperty() @@ -358,42 +391,44 @@ static PaError gatherDeviceInfo(PaMacAUHAL *auhalHostApi) device as the default. */ if( 0 != AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &size, - &auhalHostApi->defaultIn) ) { + &outArgument->devInputDevice) ) { int i; - auhalHostApi->defaultIn = kAudioDeviceUnknown; + outArgument->devInputDevice = kAudioDeviceUnknown; VDBUG(("Failed to get default input device from OS.")); VDBUG((" I will substitute the first available input Device.")); - for( i=0; idevCount; ++i ) { + + for( i=0; i< outArgument->devCount; ++i ) { PaDeviceInfo devInfo; if( 0 != GetChannelInfo( auhalHostApi, &devInfo, - auhalHostApi->devIds[i], TRUE ) ) + outArgument->devIds[i], TRUE ) ) if( devInfo.maxInputChannels ) { - auhalHostApi->defaultIn = auhalHostApi->devIds[i]; + outArgument->devInputDevice = outArgument->devIds[i]; break; } } } if( 0 != AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &size, - &auhalHostApi->defaultOut) ) { + &outArgument->devOutputDevice) ) { int i; - auhalHostApi->defaultIn = kAudioDeviceUnknown; + outArgument->devOutputDevice = kAudioDeviceUnknown; VDBUG(("Failed to get default output device from OS.")); VDBUG((" I will substitute the first available output Device.")); - for( i=0; idevCount; ++i ) { + for( i=0; idevCount; ++i ) { PaDeviceInfo devInfo; if( 0 != GetChannelInfo( auhalHostApi, &devInfo, - auhalHostApi->devIds[i], FALSE ) ) + outArgument->devIds[i], FALSE ) ) if( devInfo.maxOutputChannels ) { - auhalHostApi->defaultOut = auhalHostApi->devIds[i]; + outArgument->devOutputDevice = outArgument->devIds[i]; break; } } } - VDBUG( ( "Default in : %ld\n", auhalHostApi->defaultIn ) ); - VDBUG( ( "Default out: %ld\n", auhalHostApi->defaultOut ) ); + VDBUG( ( "Default in : %ld\n", outArgument->devInputDevice ) ); + VDBUG( ( "Default out: %ld\n", outArgument->devOutputDevice ) ); + *scanResults = outArgument; return paNoError; } @@ -402,9 +437,9 @@ static PaError GetChannelInfo( PaMacAUHAL *auhalHostApi, AudioDeviceID macCoreDeviceId, int isInput) { - UInt32 propSize; + UInt32 propSize = 0; PaError err = paNoError; - UInt32 i; + UInt32 i = 0; int numChannels = 0; AudioBufferList *buflist = NULL; UInt32 frameLatency; @@ -488,9 +523,111 @@ static PaError InitializeDeviceInfo( PaMacAUHAL *auhalHostApi, memset(deviceInfo, 0, sizeof(deviceInfo)); - deviceInfo->structVersion = 2; + deviceInfo->structVersion = 3; deviceInfo->hostApi = hostApiIndex; + // target device UID property + unsigned long deviceUID = 0; + + AudioObjectPropertyAddress addr; + addr.mSelector = kAudioDevicePropertyDeviceUID; + addr.mScope = kAudioObjectPropertyScopeGlobal; + addr.mElement = kAudioObjectPropertyElementMaster; + + CFStringRef deviceUIDString; + propSize = sizeof(deviceUIDString); + err = ERR(AudioObjectGetPropertyData( + macCoreDeviceId, + &addr, + 0, + NULL, + &propSize, + &deviceUIDString)); + if (err) + return err; + + CFIndex deviceUIDLength = CFStringGetLength(deviceUIDString) + 1; + char *ASCIIDeviceUID + = PaUtil_GroupAllocateMemory(auhalHostApi->allocations,deviceUIDLength); + if ( !ASCIIDeviceUID ) + return paInsufficientMemory; + + deviceInfo->deviceUID = NULL; + if(CFStringGetCString ( + deviceUIDString, + ASCIIDeviceUID, + deviceUIDLength, + kCFStringEncodingASCII)) + { + deviceInfo->deviceUID = ASCIIDeviceUID; + } + + // target device transport type property + addr.mSelector = kAudioDevicePropertyTransportType; + addr.mScope = kAudioObjectPropertyScopeGlobal; + addr.mElement = kAudioObjectPropertyElementMaster; + + unsigned int transportType = 0; + propSize = sizeof(transportType); + err = ERR(AudioObjectGetPropertyData( + macCoreDeviceId, + &addr, + 0, + NULL, + &propSize, + &transportType)); + if (err) + return err; + + switch(transportType) + { + case kAudioDeviceTransportTypeAggregate: + deviceInfo->transportType = "Aggregate"; + break; + case kAudioDeviceTransportTypeAirPlay: + deviceInfo->transportType = "AirPlay"; + break; + case kAudioDeviceTransportTypeAutoAggregate: + deviceInfo->transportType = "Auto aggregate"; + break; + case kAudioDeviceTransportTypeAVB: + deviceInfo->transportType = "AVB"; + break; + case kAudioDeviceTransportTypeBluetooth: + deviceInfo->transportType = "Bluetooth"; + break; + case kAudioDeviceTransportTypeBuiltIn: + deviceInfo->transportType = "Built-in"; + break; + case kAudioDeviceTransportTypeDisplayPort: + deviceInfo->transportType = "DisplayPort"; + break; + case kAudioDeviceTransportTypeFireWire: + deviceInfo->transportType = "FireWire"; + break; + case kAudioDeviceTransportTypeHDMI: + deviceInfo->transportType = "HDMI"; + break; + case kAudioDeviceTransportTypePCI: + deviceInfo->transportType = "PCI"; + break; + case kAudioDeviceTransportTypeThunderbolt: + deviceInfo->transportType = "Thunderbolt"; + break; + case kAudioDeviceTransportTypeUnknown: + deviceInfo->transportType = "Unknown"; + break; + case kAudioDeviceTransportTypeUSB: + deviceInfo->transportType = "USB"; + break; + case kAudioDeviceTransportTypeVirtual: + deviceInfo->transportType = "Virtual"; + break; + default: + deviceInfo->transportType = NULL; + break; + } + /* Get the device name. Fail if we can't get it. */ err = ERR(AudioDeviceGetPropertyInfo(macCoreDeviceId, 0, 0, kAudioDevicePropertyDeviceName, &propSize, NULL)); if (err) @@ -528,10 +665,10 @@ static PaError InitializeDeviceInfo( PaMacAUHAL *auhalHostApi, PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) { PaError result = paNoError; - int i; PaMacAUHAL *auhalHostApi = NULL; - PaDeviceInfo *deviceInfoArray; int unixErr; + void* scanResults = NULL; + int deviceCount = 0; VVDBUG(("PaMacCore_Initialize(): hostApiIndex=%d\n", hostApiIndex)); @@ -572,65 +709,29 @@ PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIn auhalHostApi->devIds = NULL; auhalHostApi->devCount = 0; - /* get the info we need about the devices */ - result = gatherDeviceInfo( auhalHostApi ); - if( result != paNoError ) - goto error; - *hostApi = &auhalHostApi->inheritedHostApiRep; (*hostApi)->info.structVersion = 1; (*hostApi)->info.type = paCoreAudio; (*hostApi)->info.name = "Core Audio"; - + + (*hostApi)->deviceInfos = NULL; + (*hostApi)->info.defaultInputDevice = paNoDevice; (*hostApi)->info.defaultOutputDevice = paNoDevice; - (*hostApi)->info.deviceCount = 0; - if( auhalHostApi->devCount > 0 ) - { - (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( - auhalHostApi->allocations, sizeof(PaDeviceInfo*) * auhalHostApi->devCount); - if( !(*hostApi)->deviceInfos ) - { - result = paInsufficientMemory; - goto error; - } + (*hostApi)->ScanDeviceInfos = ScanDeviceInfos; + (*hostApi)->CommitDeviceInfos = CommitDeviceInfos; + (*hostApi)->DisposeDeviceInfos = DisposeDeviceInfos; - /* allocate all device info structs in a contiguous block */ - deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory( - auhalHostApi->allocations, sizeof(PaDeviceInfo) * auhalHostApi->devCount ); - if( !deviceInfoArray ) - { - result = paInsufficientMemory; - goto error; - } + result = ScanDeviceInfos(&auhalHostApi->inheritedHostApiRep, hostApiIndex, &scanResults, + &deviceCount); - for( i=0; i < auhalHostApi->devCount; ++i ) - { - int err; - err = InitializeDeviceInfo( auhalHostApi, &deviceInfoArray[i], - auhalHostApi->devIds[i], - hostApiIndex ); - if (err == paNoError) - { /* copy some info and set the defaults */ - (*hostApi)->deviceInfos[(*hostApi)->info.deviceCount] = &deviceInfoArray[i]; - if (auhalHostApi->devIds[i] == auhalHostApi->defaultIn) - (*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount; - if (auhalHostApi->devIds[i] == auhalHostApi->defaultOut) - (*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount; - (*hostApi)->info.deviceCount++; - } - else - { /* there was an error. we need to shift the devices down, so we ignore this one */ - int j; - auhalHostApi->devCount--; - for( j=i; jdevCount; ++j ) - auhalHostApi->devIds[j] = auhalHostApi->devIds[j+1]; - i--; - } - } - } + if(result != paNoError) + goto error; + + /* FIXME for now we ignore the result of CommitDeviceInfos(), it should probably be an atomic non-failing operation */ + CommitDeviceInfos( &auhalHostApi->inheritedHostApiRep, hostApiIndex, scanResults, deviceCount ); (*hostApi)->Terminate = Terminate; (*hostApi)->OpenStream = OpenStream; @@ -1340,7 +1441,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, (float) sampleRate, framesPerBuffer )); VDBUG( ("Opening Stream.\n") ); - + /*These first few bits of code are from paSkeleton with few modifications.*/ if( inputParameters ) { @@ -1730,37 +1831,37 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, pthread_mutex_init( &stream->timingInformationMutex, NULL ); stream->timingInformationMutexIsInitialized = 1; - + if( stream->outputUnit ) { UpdateReciprocalOfActualOutputSampleRateFromDeviceProperty( stream ); stream->recipricalOfActualOutputSampleRate_ioProcCopy = stream->recipricalOfActualOutputSampleRate; - + AudioDeviceAddPropertyListener( stream->outputDevice, 0, /* isInput = */ FALSE, kAudioDevicePropertyActualSampleRate, AudioDevicePropertyActualSampleRateListenerProc, stream ); - + UpdateOutputLatencySamplesFromDeviceProperty( stream ); stream->deviceOutputLatencySamples_ioProcCopy = stream->deviceOutputLatencySamples; - + AudioDeviceAddPropertyListener( stream->outputDevice, 0, /* isInput = */ FALSE, kAudioDevicePropertyLatency, AudioDevicePropertyOutputLatencySamplesListenerProc, stream ); - + }else{ stream->recipricalOfActualOutputSampleRate = 1.; stream->recipricalOfActualOutputSampleRate_ioProcCopy = 0.; stream->deviceOutputLatencySamples_ioProcCopy = 0; } - + if( stream->inputUnit ) { UpdateInputLatencySamplesFromDeviceProperty( stream ); stream->deviceInputLatencySamples_ioProcCopy = stream->deviceInputLatencySamples; - + AudioDeviceAddPropertyListener( stream->inputDevice, 0, /* isInput = */ TRUE, kAudioDevicePropertyLatency, AudioDevicePropertyInputLatencySamplesListenerProc, stream ); - }else{ + } else { stream->deviceInputLatencySamples = 0; stream->deviceInputLatencySamples_ioProcCopy = 0; - } - + } + stream->state = STOPPED; stream->xrunFlags = 0; @@ -1862,14 +1963,14 @@ static OSStatus AudioIOProc( void *inRefCon, ----------------------------------------------------------------- */ /* compute PaStreamCallbackTimeInfo */ - + if( pthread_mutex_trylock( &stream->timingInformationMutex ) == 0 ){ /* snapshot the ioproc copy of timing information */ stream->deviceOutputLatencySamples_ioProcCopy = stream->deviceOutputLatencySamples; stream->recipricalOfActualOutputSampleRate_ioProcCopy = stream->recipricalOfActualOutputSampleRate; stream->deviceInputLatencySamples_ioProcCopy = stream->deviceInputLatencySamples; pthread_mutex_unlock( &stream->timingInformationMutex ); - } + } /* For timeInfo.currentTime we could calculate current time backwards from the HAL audio output time to give a more accurate impression of the current timeslice but it doesn't @@ -1899,7 +2000,7 @@ static OSStatus AudioIOProc( void *inRefCon, - stream->deviceInputLatencySamples_ioProcCopy * stream->recipricalOfActualOutputSampleRate_ioProcCopy; // FIXME should be using input sample rate here? timeInfo.outputBufferDacTime = HOST_TIME_TO_PA_TIME(inTimeStamp->mHostTime) + stream->deviceOutputLatencySamples_ioProcCopy * stream->recipricalOfActualOutputSampleRate_ioProcCopy; - } + } else /* full duplex with ring-buffer from a separate input AUHAL ioproc */ { /* FIXME: review. this computation of inputBufferAdcTime is definitely wrong since it doesn't take the ring buffer latency into account */ @@ -1922,7 +2023,7 @@ static OSStatus AudioIOProc( void *inRefCon, - stream->deviceInputLatencySamples_ioProcCopy * stream->recipricalOfActualOutputSampleRate_ioProcCopy; // FIXME should be using input sample rate here? timeInfo.outputBufferDacTime = 0; } - + //printf( "---%g, %g, %g\n", timeInfo.inputBufferAdcTime, timeInfo.currentTime, timeInfo.outputBufferDacTime ); if( isRender && stream->inputUnit == stream->outputUnit @@ -2261,7 +2362,7 @@ static PaError CloseStream( PaStream* s ) if( stream ) { - if( stream->outputUnit ) { + if( stream->outputUnit ) { AudioDeviceRemovePropertyListener( stream->outputDevice, 0, /* isInput = */ FALSE, kAudioDevicePropertyActualSampleRate, AudioDevicePropertyActualSampleRateListenerProc ); AudioDeviceRemovePropertyListener( stream->outputDevice, 0, /* isInput = */ FALSE, kAudioDevicePropertyLatency, @@ -2352,22 +2453,39 @@ static PaError StartStream( PaStream *s ) if( stream->outputUnit && stream->outputUnit != stream->inputUnit ) { ERR_WRAP( AudioOutputUnitStart(stream->outputUnit) ); } - + return paNoError; #undef ERR_WRAP } // it's not clear from appl's docs that this really waits // until all data is flushed. -static ComponentResult BlockWhileAudioUnitIsRunning( AudioUnit audioUnit, AudioUnitElement element ) +static ComponentResult BlockWhileAudioUnitIsRunning( + AudioUnit audioUnit, + AudioUnitElement element) { + long waitTime = 100; + // If PaUtil_GetRingBufferWriteAvailable starts repetitively and + // consecutively returning that there is no data available, do eventually + // give up in order to allow the caller to handle such cases. + long totalTimeout = 0; Boolean isRunning = 1; while( isRunning ) { UInt32 s = sizeof( isRunning ); ComponentResult err = AudioUnitGetProperty( audioUnit, kAudioOutputUnitProperty_IsRunning, kAudioUnitScope_Global, element, &isRunning, &s ); if( err ) return err; - Pa_Sleep( 100 ); + Pa_Sleep( waitTime ); + + // If a timeout is encountered, continue. However, testing has + // shown that it is possible to unplug a device and to wait here + // forever. In order to allow the caller to handle such cases of + // repeated timeouts, do eventually given up. + totalTimeout += waitTime; + if( PA_COREAUDIO_MIN_TIMEOUT_MSEC_ <= totalTimeout) + { + return paTimedOut; + } } return noErr; } @@ -2380,7 +2498,7 @@ static PaError StopStream( PaStream *s ) VVDBUG(("StopStream()\n")); VDBUG( ("Waiting for BLIO.\n") ); - waitUntilBlioWriteBufferIsFlushed( &stream->blio ); + waitUntilBlioWriteBufferIsFlushed( &stream->blio); VDBUG( ( "Stopping stream.\n" ) ); stream->state = STOPPING; @@ -2406,7 +2524,7 @@ static PaError StopStream( PaStream *s ) if( stream->outputUnit ) { ERR_WRAP(AudioOutputUnitStop(stream->outputUnit)); - ERR_WRAP( BlockWhileAudioUnitIsRunning(stream->outputUnit,0) ); + ERR_WRAP( BlockWhileAudioUnitIsRunning(stream->outputUnit,0)); ERR_WRAP(AudioUnitReset(stream->outputUnit,kAudioUnitScope_Global,0)); } } @@ -2468,3 +2586,148 @@ static double GetStreamCpuLoad( PaStream* s ) return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ); } + +static PaError ScanDeviceInfos(struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex hostApiIndex, + void **scanResults, int *newDeviceCount) +{ + PaMacAUHAL* auhalHostApi = (PaMacAUHAL*)hostApi; + PaDeviceInfo *deviceInfoArray = NULL; + PaError result = paNoError; + int i = 0; + PaMacScanDeviceInfosResults* out = NULL; + + /* get the info we need about the devices */ + result = gatherDeviceInfo( auhalHostApi, scanResults, newDeviceCount ); + + if( result != paNoError ) + return result; + + out = (PaMacScanDeviceInfosResults*)*scanResults; + + if( out->devCount > 0 ) + { + int count = 0; + + /* allocate array for pointers to PaDeviceInfo structs */ + out->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( + auhalHostApi->allocations, sizeof(PaDeviceInfo*) * out->devCount); + if( !out->deviceInfos ) + { + result = paInsufficientMemory; + return result; + } + + /* allocate all device info structs in a contiguous block */ + deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory( + auhalHostApi->allocations, sizeof(PaDeviceInfo) * out->devCount ); + if( !deviceInfoArray ) + { + result = paInsufficientMemory; + return result; + } + + for( i=0; i < out->devCount; ++i ) + { + int err; + err = InitializeDeviceInfo( auhalHostApi, &deviceInfoArray[i], + out->devIds[i], + hostApiIndex ); + if (err == paNoError) + { + /* copy some info and set the defaults */ + out->deviceInfos[count] = &deviceInfoArray[i]; + + if (out->devIds[i] == out->devInputDevice) + { + out->defaultInputDevice = count; + } + if (out->devIds[i] == out->devOutputDevice) + { + out->defaultOutputDevice = count; + } + count++; + } + else + { + /* there was an error. we need to shift the devices down, so we ignore this one */ + int j; + out->devCount--; + for( j=i; jdevCount; ++j ) + out->devIds[j] = out->devIds[j+1]; + i--; + } + } + } + *newDeviceCount = out->devCount; + + return paNoError; +} + +static PaError CommitDeviceInfos(struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index, + void *scanResults, int deviceCount) +{ + PaMacAUHAL* auhalHostApi = (PaMacAUHAL*)hostApi; + PaError result = paNoError; + + hostApi->info.deviceCount = 0; + hostApi->info.defaultInputDevice = paNoDevice; + hostApi->info.defaultOutputDevice = paNoDevice; + + /* -- free any previous allocations -- */ + if( auhalHostApi->devIds ) + { + PaUtil_GroupFreeMemory(auhalHostApi->allocations, auhalHostApi->devIds); + } + auhalHostApi->devIds = NULL; + + /* Free any old memory which might be in the device info */ + if( hostApi->deviceInfos ) + { + PaUtil_GroupFreeMemory( auhalHostApi->allocations, hostApi->deviceInfos[0] ); + PaUtil_GroupFreeMemory( auhalHostApi->allocations, hostApi->deviceInfos ); + hostApi->deviceInfos = NULL; + } + + if( scanResults != NULL ) + { + PaMacScanDeviceInfosResults *scanDeviceInfosResults = ( PaMacScanDeviceInfosResults * ) scanResults; + + if( deviceCount > 0 ) + { + /* use the array allocated in ScanDeviceInfos() as our deviceInfos */ + hostApi->deviceInfos = scanDeviceInfosResults->deviceInfos; + hostApi->info.defaultInputDevice = scanDeviceInfosResults->defaultInputDevice; + hostApi->info.defaultOutputDevice = scanDeviceInfosResults->defaultOutputDevice; + hostApi->info.deviceCount = deviceCount; + auhalHostApi->devIds = scanDeviceInfosResults->devIds; + auhalHostApi->devCount = scanDeviceInfosResults->devCount; + auhalHostApi->defaultIn = scanDeviceInfosResults->devInputDevice; + auhalHostApi->defaultOut = scanDeviceInfosResults->devOutputDevice; + } + + PaUtil_GroupFreeMemory( auhalHostApi->allocations, scanDeviceInfosResults ); + } + + return result; +} + +static PaError DisposeDeviceInfos(struct PaUtilHostApiRepresentation *hostApi, void *scanResults, int deviceCount) +{ + PaMacAUHAL *auhalHostApi = (PaMacAUHAL*)hostApi; + + if( scanResults != NULL ) + { + PaMacScanDeviceInfosResults *scanDeviceInfosResults = ( PaMacScanDeviceInfosResults * ) scanResults; + if( scanDeviceInfosResults->deviceInfos ) + { + /* all device info structs are allocated in a block so we can destroy them here */ + PaUtil_GroupFreeMemory( auhalHostApi->allocations, scanDeviceInfosResults->deviceInfos[0] ); + PaUtil_GroupFreeMemory( auhalHostApi->allocations, scanDeviceInfosResults->deviceInfos ); + } + + PaUtil_GroupFreeMemory(auhalHostApi->allocations, scanDeviceInfosResults ); + } + + return paNoError; +} + diff --git a/src/hostapi/coreaudio/pa_mac_core_blocking.c b/src/hostapi/coreaudio/pa_mac_core_blocking.c index 5a98826..c51fd52 100644 --- a/src/hostapi/coreaudio/pa_mac_core_blocking.c +++ b/src/hostapi/coreaudio/pa_mac_core_blocking.c @@ -415,6 +415,10 @@ PaError ReadStream( PaStream* stream, while( frames > 0 ) { long avail; long toRead; + // If PaUtil_GetRingBufferReadAvailable starts repetitively and + // consecutively returning that there is no data available, do eventually + // give up in order to allow the caller to handle such cases. + long totalTimeout = 0; do { avail = PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer ); /* @@ -438,6 +442,16 @@ PaError ReadStream( PaStream* stream, return ret; #else Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL ); + + // If a timeout is encountered, continue. However, testing has + // shown that it is possible to unplug a device and to wait here + // forever. In order to allow the caller to handle such cases of + // repeated timeouts, do eventually given up. + totalTimeout += PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL; + if( PA_COREAUDIO_MAX_TIMEOUT_MSEC_ <= totalTimeout) + { + return paTimedOut; + } #endif } } while( avail == 0 ); @@ -491,6 +505,10 @@ PaError WriteStream( PaStream* stream, while( frames > 0 ) { long avail = 0; long toWrite; + // If PaUtil_GetRingBufferWriteAvailable starts repetitively and + // consecutively returning that there is no data available, do eventually + // give up in order to allow the caller to handle such cases. + long totalTimeout = 0; do { avail = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer ); @@ -515,6 +533,16 @@ PaError WriteStream( PaStream* stream, return ret; #else Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL ); + + // If a timeout is encountered, continue. However, testing has + // shown that it is possible to unplug a device and to wait here + // forever. In order to allow the caller to handle such cases of + // repeated timeouts, do eventually given up. + totalTimeout += PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL; + if( PA_COREAUDIO_MAX_TIMEOUT_MSEC_ <= totalTimeout) + { + return paTimedOut; + } #endif } } while( avail == 0 ); @@ -561,13 +589,30 @@ PaError WriteStream( PaStream* stream, void waitUntilBlioWriteBufferIsFlushed( PaMacBlio *blio ) { if( blio->outputRingBuffer.buffer ) { + // If PaUtil_GetRingBufferWriteAvailable starts repetitively and + // consecutively returning that there is no data available, do eventually + // give up in order to allow the caller to handle such cases. + long totalTimeout = 0; long avail = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer ); while( avail != blio->outputRingBuffer.bufferSize ) { if( avail == 0 ) + { Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL ); + + // If a timeout is encountered, continue. However, testing has + // shown that it is possible to unplug a device and to wait here + // forever. In order to allow the caller to handle such cases of + // repeated timeouts, do eventually given up. + totalTimeout += PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL; + if( PA_COREAUDIO_MIN_TIMEOUT_MSEC_ <= totalTimeout) + { + return paTimedOut; + } + } avail = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer ); } } + return paNoError; } diff --git a/src/hostapi/coreaudio/pa_mac_core_blocking.h b/src/hostapi/coreaudio/pa_mac_core_blocking.h index 971223b..690a5e2 100644 --- a/src/hostapi/coreaudio/pa_mac_core_blocking.h +++ b/src/hostapi/coreaudio/pa_mac_core_blocking.h @@ -76,6 +76,9 @@ #define PA_MAC_BLIO_MUTEX */ +#define PA_COREAUDIO_MIN_TIMEOUT_MSEC_ (1000) +#define PA_COREAUDIO_MAX_TIMEOUT_MSEC_ (2000) + typedef struct { PaUtilRingBuffer inputRingBuffer; PaUtilRingBuffer outputRingBuffer; diff --git a/src/hostapi/dsound/pa_win_ds.c b/src/hostapi/dsound/pa_win_ds.c index ca04614..c1f6651 100644 --- a/src/hostapi/dsound/pa_win_ds.c +++ b/src/hostapi/dsound/pa_win_ds.c @@ -1,5 +1,5 @@ /* - * $Id$ + * $Id: pa_win_ds.c 1672 2011-05-04 20:11:30Z rossb $ * Portable Audio I/O Library DirectSound implementation * * Authors: Phil Burk, Robert Marsanyi & Ross Bencina @@ -75,10 +75,6 @@ #include "pa_win_waveformat.h" #include "pa_win_wdmks_utils.h" -#ifndef PA_USE_WMME -#error "Portaudio internal error: PA_USE_WMME=0/1 not defined. pa_hostapi.h should ensure that it is." -#endif - #if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) /* MSC version 6 and above */ #pragma comment( lib, "dsound.lib" ) #pragma comment( lib, "winmm.lib" ) @@ -141,6 +137,9 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate ); +static PaError ScanDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index, void **newDeviceInfos, int *newDeviceCount ); +static PaError CommitDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index, void *deviceInfos, int deviceCount ); +static PaError DisposeDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, void *deviceInfos, int deviceCount ); static PaError CloseStream( PaStream* stream ); static PaError StartStream( PaStream *stream ); static PaError StopStream( PaStream *stream ); @@ -249,6 +248,12 @@ typedef struct PaWinDsStream volatile int abortProcessing; /* stop thread immediately */ } PaWinDsStream; +typedef struct PaWinDsScanDeviceInfosResults{ /* used for tranferring device infos during scanning / rescanning */ + PaDeviceInfo **deviceInfos; + PaDeviceIndex defaultInputDevice; + PaDeviceIndex defaultOutputDevice; +} PaWinDsScanDeviceInfosResults; + /************************************************************************************ ** Duplicate the input string using the allocations allocator. @@ -293,7 +298,7 @@ typedef struct DSDeviceNameAndGUIDVector{ int count; int free; - DSDeviceNameAndGUID *items; // Allocated using LocalAlloc() + DSDeviceNameAndGUID *items; /* Allocated using LocalAlloc() */ } DSDeviceNameAndGUIDVector; typedef struct DSDeviceNamesAndGUIDs{ @@ -512,11 +517,10 @@ static GUID pawin_IID_IKsPropertySet = static void FindDevicePnpInterfaces( DSDeviceNamesAndGUIDs *deviceNamesAndGUIDs ) { IClassFactory *pClassFactory; - if( paWinDsDSoundEntryPoints.DllGetClassObject(&pawin_CLSID_DirectSoundPrivate, &IID_IClassFactory, (PVOID *) &pClassFactory) == S_OK ){ IKsPropertySet *pPropertySet; if( pClassFactory->lpVtbl->CreateInstance( pClassFactory, NULL, &pawin_IID_IKsPropertySet, (PVOID *) &pPropertySet) == S_OK ){ - + DSPROPERTY_DIRECTSOUNDDEVICE_ENUMERATE_W_DATA data; ULONG bytesReturned; @@ -590,36 +594,23 @@ static double defaultSampleRateSearchOrder_[] = ** The device will not be added to the device list if any errors are encountered. */ static PaError AddOutputDeviceInfoFromDirectSound( - PaWinDsHostApiRepresentation *winDsHostApi, char *name, LPGUID lpGUID, char *pnpInterface ) + PaWinDsDeviceInfo *winDsDeviceInfo, char *name, LPGUID lpGUID, char *pnpInterface, PaUtilAllocationGroup *allocations ) { - PaUtilHostApiRepresentation *hostApi = &winDsHostApi->inheritedHostApiRep; - PaWinDsDeviceInfo *winDsDeviceInfo = (PaWinDsDeviceInfo*) hostApi->deviceInfos[hostApi->info.deviceCount]; PaDeviceInfo *deviceInfo = &winDsDeviceInfo->inheritedDeviceInfo; HRESULT hr; - LPDIRECTSOUND lpDirectSound; + LPDIRECTSOUND lpDirectSound = NULL; DSCAPS caps; - int deviceOK = TRUE; PaError result = paNoError; int i; - /* Copy GUID to the device info structure. Set pointer. */ - if( lpGUID == NULL ) - { - winDsDeviceInfo->lpGUID = NULL; - } - else - { - memcpy( &winDsDeviceInfo->guid, lpGUID, sizeof(GUID) ); - winDsDeviceInfo->lpGUID = &winDsDeviceInfo->guid; - } - + if( lpGUID ) { if (IsEqualGUID (&IID_IRolandVSCEmulated1,lpGUID) || IsEqualGUID (&IID_IRolandVSCEmulated2,lpGUID) ) { PA_DEBUG(("BLACKLISTED: %s \n",name)); - return paNoError; + return paInvalidDevice; } } @@ -627,23 +618,6 @@ static PaError AddOutputDeviceInfoFromDirectSound( Note that using CoCreateInstance doesn't work on windows CE. */ hr = paWinDsDSoundEntryPoints.DirectSoundCreate( lpGUID, &lpDirectSound, NULL ); - - /** try using CoCreateInstance because DirectSoundCreate was hanging under - some circumstances - note this was probably related to the - #define BOOL short bug which has now been fixed - @todo delete this comment and the following code once we've ensured - there is no bug. - */ - /* - hr = CoCreateInstance( &CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER, - &IID_IDirectSound, (void**)&lpDirectSound ); - - if( hr == S_OK ) - { - hr = IDirectSound_Initialize( lpDirectSound, lpGUID ); - } - */ - if( hr != DS_OK ) { if (hr == DSERR_ALLOCATED) @@ -664,7 +638,8 @@ static PaError AddOutputDeviceInfoFromDirectSound( lpGUID->Data4[6], lpGUID->Data4[7])); - deviceOK = FALSE; + result = paUnanticipatedHostError; + goto error; } else { @@ -675,7 +650,9 @@ static PaError AddOutputDeviceInfoFromDirectSound( if( hr != DS_OK ) { DBUG(("Cannot GetCaps() for DirectSound device %s. Result = 0x%x\n", name, hr )); - deviceOK = FALSE; + + result = paUnanticipatedHostError; + goto error; } else { @@ -684,153 +661,171 @@ static PaError AddOutputDeviceInfoFromDirectSound( if( caps.dwFlags & DSCAPS_EMULDRIVER ) { /* If WMME supported, then reject Emulated drivers because they are lousy. */ - deviceOK = FALSE; + result = paInvalidDevice; + goto error; } #endif - if( deviceOK ) + deviceInfo->maxInputChannels = 0; + winDsDeviceInfo->deviceInputChannelCountIsKnown = 1; + + /* DS output capabilities only indicate supported number of channels + using two flags which indicate mono and/or stereo. + We assume that stereo devices may support more than 2 channels + (as is the case with 5.1 devices for example) and so + set deviceOutputChannelCountIsKnown to 0 (unknown). + In this case OpenStream will try to open the device + when the user requests more than 2 channels, rather than + returning an error. + */ + if( caps.dwFlags & DSCAPS_PRIMARYSTEREO ) { - deviceInfo->maxInputChannels = 0; - winDsDeviceInfo->deviceInputChannelCountIsKnown = 1; + deviceInfo->maxOutputChannels = 2; + winDsDeviceInfo->deviceOutputChannelCountIsKnown = 0; + } + else + { + deviceInfo->maxOutputChannels = 1; + winDsDeviceInfo->deviceOutputChannelCountIsKnown = 1; + } - /* DS output capabilities only indicate supported number of channels - using two flags which indicate mono and/or stereo. - We assume that stereo devices may support more than 2 channels - (as is the case with 5.1 devices for example) and so - set deviceOutputChannelCountIsKnown to 0 (unknown). - In this case OpenStream will try to open the device - when the user requests more than 2 channels, rather than - returning an error. - */ - if( caps.dwFlags & DSCAPS_PRIMARYSTEREO ) - { - deviceInfo->maxOutputChannels = 2; - winDsDeviceInfo->deviceOutputChannelCountIsKnown = 0; - } - else - { - deviceInfo->maxOutputChannels = 1; - winDsDeviceInfo->deviceOutputChannelCountIsKnown = 1; - } - - /* Guess channels count from speaker configuration. We do it only when - pnpInterface is NULL or when PAWIN_USE_WDMKS_DEVICE_INFO is undefined. - */ + /* Guess channels count from speaker configuration. We do it only when + pnpInterface is NULL or when PAWIN_USE_WDMKS_DEVICE_INFO is undefined. + */ #ifdef PAWIN_USE_WDMKS_DEVICE_INFO - if( !pnpInterface ) + if( !pnpInterface ) #endif + { + DWORD spkrcfg; + if( SUCCEEDED(IDirectSound_GetSpeakerConfig( lpDirectSound, &spkrcfg )) ) { - DWORD spkrcfg; - if( SUCCEEDED(IDirectSound_GetSpeakerConfig( lpDirectSound, &spkrcfg )) ) + int count = 0; + switch (DSSPEAKER_CONFIG(spkrcfg)) { - int count = 0; - switch (DSSPEAKER_CONFIG(spkrcfg)) - { - case DSSPEAKER_HEADPHONE: count = 2; break; - case DSSPEAKER_MONO: count = 1; break; - case DSSPEAKER_QUAD: count = 4; break; - case DSSPEAKER_STEREO: count = 2; break; - case DSSPEAKER_SURROUND: count = 4; break; - case DSSPEAKER_5POINT1: count = 6; break; - case DSSPEAKER_7POINT1: count = 8; break; + case DSSPEAKER_HEADPHONE: count = 2; break; + case DSSPEAKER_MONO: count = 1; break; + case DSSPEAKER_QUAD: count = 4; break; + case DSSPEAKER_STEREO: count = 2; break; + case DSSPEAKER_SURROUND: count = 4; break; + case DSSPEAKER_5POINT1: count = 6; break; + case DSSPEAKER_7POINT1: count = 8; break; #ifndef DSSPEAKER_7POINT1_SURROUND #define DSSPEAKER_7POINT1_SURROUND 0x00000008 #endif - case DSSPEAKER_7POINT1_SURROUND: count = 8; break; + case DSSPEAKER_7POINT1_SURROUND: count = 8; break; #ifndef DSSPEAKER_5POINT1_SURROUND #define DSSPEAKER_5POINT1_SURROUND 0x00000009 #endif - case DSSPEAKER_5POINT1_SURROUND: count = 6; break; - } - if( count ) - { - deviceInfo->maxOutputChannels = count; - winDsDeviceInfo->deviceOutputChannelCountIsKnown = 1; - } + case DSSPEAKER_5POINT1_SURROUND: count = 6; break; } - } - -#ifdef PAWIN_USE_WDMKS_DEVICE_INFO - if( pnpInterface ) - { - int count = PaWin_WDMKS_QueryFilterMaximumChannelCount( pnpInterface, /* isInput= */ 0 ); - if( count > 0 ) + if( count ) { deviceInfo->maxOutputChannels = count; winDsDeviceInfo->deviceOutputChannelCountIsKnown = 1; } } + } + +#ifdef PAWIN_USE_WDMKS_DEVICE_INFO + if( pnpInterface ) + { + int count = PaWin_WDMKS_QueryFilterMaximumChannelCount( pnpInterface, /* isInput= */ 0 ); + if( count > 0 ) + { + deviceInfo->maxOutputChannels = count; + winDsDeviceInfo->deviceOutputChannelCountIsKnown = 1; + } + } #endif /* PAWIN_USE_WDMKS_DEVICE_INFO */ - deviceInfo->defaultLowInputLatency = 0.; /** @todo IMPLEMENT ME */ - deviceInfo->defaultLowOutputLatency = 0.; /** @todo IMPLEMENT ME */ - deviceInfo->defaultHighInputLatency = 0.; /** @todo IMPLEMENT ME */ - deviceInfo->defaultHighOutputLatency = 0.; /** @todo IMPLEMENT ME */ - - /* initialize defaultSampleRate */ - - if( caps.dwFlags & DSCAPS_CONTINUOUSRATE ) - { - /* initialize to caps.dwMaxSecondarySampleRate incase none of the standard rates match */ - deviceInfo->defaultSampleRate = caps.dwMaxSecondarySampleRate; + deviceInfo->defaultLowInputLatency = 0.; /** @todo IMPLEMENT ME */ + deviceInfo->defaultLowOutputLatency = 0.; /** @todo IMPLEMENT ME */ + deviceInfo->defaultHighInputLatency = 0.; /** @todo IMPLEMENT ME */ + deviceInfo->defaultHighOutputLatency = 0.; /** @todo IMPLEMENT ME */ + + /* initialize defaultSampleRate */ + + if( caps.dwFlags & DSCAPS_CONTINUOUSRATE ) + { + /* initialize to caps.dwMaxSecondarySampleRate incase none of the standard rates match */ + deviceInfo->defaultSampleRate = caps.dwMaxSecondarySampleRate; - for( i = 0; i < PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_; ++i ) + for( i = 0; i < PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_; ++i ) + { + if( defaultSampleRateSearchOrder_[i] >= caps.dwMinSecondarySampleRate + && defaultSampleRateSearchOrder_[i] <= caps.dwMaxSecondarySampleRate ) { - if( defaultSampleRateSearchOrder_[i] >= caps.dwMinSecondarySampleRate - && defaultSampleRateSearchOrder_[i] <= caps.dwMaxSecondarySampleRate ) - { - deviceInfo->defaultSampleRate = defaultSampleRateSearchOrder_[i]; - break; - } + deviceInfo->defaultSampleRate = defaultSampleRateSearchOrder_[i]; + break; } } - else if( caps.dwMinSecondarySampleRate == caps.dwMaxSecondarySampleRate ) - { - if( caps.dwMinSecondarySampleRate == 0 ) - { - /* - ** On my Thinkpad 380Z, DirectSoundV6 returns min-max=0 !! - ** But it supports continuous sampling. - ** So fake range of rates, and hope it really supports it. - */ - deviceInfo->defaultSampleRate = 44100.0f; - - DBUG(("PA - Reported rates both zero. Setting to fake values for device #%s\n", name )); - } - else - { - deviceInfo->defaultSampleRate = caps.dwMaxSecondarySampleRate; - } - } - else if( (caps.dwMinSecondarySampleRate < 1000.0) && (caps.dwMaxSecondarySampleRate > 50000.0) ) - { - /* The EWS88MT drivers lie, lie, lie. The say they only support two rates, 100 & 100000. - ** But we know that they really support a range of rates! - ** So when we see a ridiculous set of rates, assume it is a range. - */ - deviceInfo->defaultSampleRate = 44100.0f; - DBUG(("PA - Sample rate range used instead of two odd values for device #%s\n", name )); - } - else deviceInfo->defaultSampleRate = caps.dwMaxSecondarySampleRate; - - - //printf( "min %d max %d\n", caps.dwMinSecondarySampleRate, caps.dwMaxSecondarySampleRate ); - // dwFlags | DSCAPS_CONTINUOUSRATE } + else if( caps.dwMinSecondarySampleRate == caps.dwMaxSecondarySampleRate ) + { + if( caps.dwMinSecondarySampleRate == 0 ) + { + /* + ** On my Thinkpad 380Z, DirectSoundV6 returns min-max=0 !! + ** But it supports continuous sampling. + ** So fake range of rates, and hope it really supports it. + */ + deviceInfo->defaultSampleRate = 44100.0f; + + DBUG(("PA - Reported rates both zero. Setting to fake values for device #%s\n", name )); + } + else + { + deviceInfo->defaultSampleRate = caps.dwMaxSecondarySampleRate; + } + } + else if( (caps.dwMinSecondarySampleRate < 1000.0) && (caps.dwMaxSecondarySampleRate > 50000.0) ) + { + /* The EWS88MT drivers lie, lie, lie. The say they only support two rates, 100 & 100000. + ** But we know that they really support a range of rates! + ** So when we see a ridiculous set of rates, assume it is a range. + */ + deviceInfo->defaultSampleRate = 44100.0f; + DBUG(("PA - Sample rate range used instead of two odd values for device #%s\n", name )); + } + else deviceInfo->defaultSampleRate = caps.dwMaxSecondarySampleRate; + + + //printf( "min %d max %d\n", caps.dwMinSecondarySampleRate, caps.dwMaxSecondarySampleRate ); + // dwFlags | DSCAPS_CONTINUOUSRATE } IDirectSound_Release( lpDirectSound ); } - if( deviceOK ) + /* Copy GUID to the device info structure. Set pointer. */ + if( lpGUID == NULL ) { - deviceInfo->name = name; - - if( lpGUID == NULL ) - hostApi->info.defaultOutputDevice = hostApi->info.deviceCount; - - hostApi->info.deviceCount++; + winDsDeviceInfo->lpGUID = NULL; } + else + { + // target device UID property + WCHAR duid[39]; + char *deviceUID; + deviceUID = (char *)PaUtil_GroupAllocateMemory(allocations, 39); + + StringFromGUID2(&(*lpGUID), (LPOLESTR) &duid, 39); + wcstombs(deviceUID, duid, sizeof(deviceUID)); + WideCharToMultiByte( CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,\ + duid, -1, deviceUID, 39, NULL, NULL ); + deviceInfo->deviceUID = deviceUID; + + memcpy( &winDsDeviceInfo->guid, lpGUID, sizeof(GUID) ); + winDsDeviceInfo->lpGUID = &winDsDeviceInfo->guid; + } + + deviceInfo->name = name; + + return result; + +error: + if( lpDirectSound ) + IDirectSound_Release( lpDirectSound ); return result; } @@ -844,44 +839,20 @@ static PaError AddOutputDeviceInfoFromDirectSound( ** The device will not be added to the device list if any errors are encountered. */ static PaError AddInputDeviceInfoFromDirectSoundCapture( - PaWinDsHostApiRepresentation *winDsHostApi, char *name, LPGUID lpGUID, char *pnpInterface ) + PaWinDsDeviceInfo *winDsDeviceInfo, char *name, LPGUID lpGUID, char *pnpInterface, PaUtilAllocationGroup *allocations ) { - PaUtilHostApiRepresentation *hostApi = &winDsHostApi->inheritedHostApiRep; - PaWinDsDeviceInfo *winDsDeviceInfo = (PaWinDsDeviceInfo*) hostApi->deviceInfos[hostApi->info.deviceCount]; PaDeviceInfo *deviceInfo = &winDsDeviceInfo->inheritedDeviceInfo; HRESULT hr; - LPDIRECTSOUNDCAPTURE lpDirectSoundCapture; + LPDIRECTSOUNDCAPTURE lpDirectSoundCapture = NULL; DSCCAPS caps; - int deviceOK = TRUE; PaError result = paNoError; - /* Copy GUID to the device info structure. Set pointer. */ - if( lpGUID == NULL ) - { - winDsDeviceInfo->lpGUID = NULL; - } - else - { - winDsDeviceInfo->lpGUID = &winDsDeviceInfo->guid; - memcpy( &winDsDeviceInfo->guid, lpGUID, sizeof(GUID) ); - } - hr = paWinDsDSoundEntryPoints.DirectSoundCaptureCreate( lpGUID, &lpDirectSoundCapture, NULL ); - - /** try using CoCreateInstance because DirectSoundCreate was hanging under - some circumstances - note this was probably related to the - #define BOOL short bug which has now been fixed - @todo delete this comment and the following code once we've ensured - there is no bug. - */ - /* - hr = CoCreateInstance( &CLSID_DirectSoundCapture, NULL, CLSCTX_INPROC_SERVER, - &IID_IDirectSoundCapture, (void**)&lpDirectSoundCapture ); - */ if( hr != DS_OK ) { DBUG(("Cannot create Capture for %s. Result = 0x%x\n", name, hr )); - deviceOK = FALSE; + result = paUnanticipatedHostError; + goto error; } else { @@ -892,7 +863,8 @@ static PaError AddInputDeviceInfoFromDirectSoundCapture( if( hr != DS_OK ) { DBUG(("Cannot GetCaps() for Capture device %s. Result = 0x%x\n", name, hr )); - deviceOK = FALSE; + result = paUnanticipatedHostError; + goto error; } else { @@ -900,50 +872,49 @@ static PaError AddInputDeviceInfoFromDirectSoundCapture( if( caps.dwFlags & DSCAPS_EMULDRIVER ) { /* If WMME supported, then reject Emulated drivers because they are lousy. */ - deviceOK = FALSE; + result = paInvalidDevice; + goto error; } #endif - if( deviceOK ) - { - deviceInfo->maxInputChannels = caps.dwChannels; - winDsDeviceInfo->deviceInputChannelCountIsKnown = 1; + deviceInfo->maxInputChannels = caps.dwChannels; + winDsDeviceInfo->deviceInputChannelCountIsKnown = 1; - deviceInfo->maxOutputChannels = 0; - winDsDeviceInfo->deviceOutputChannelCountIsKnown = 1; + deviceInfo->maxOutputChannels = 0; + winDsDeviceInfo->deviceOutputChannelCountIsKnown = 1; #ifdef PAWIN_USE_WDMKS_DEVICE_INFO - if( pnpInterface ) + if( pnpInterface ) + { + int count = PaWin_WDMKS_QueryFilterMaximumChannelCount( pnpInterface, /* isInput= */ 1 ); + if( count > 0 ) { - int count = PaWin_WDMKS_QueryFilterMaximumChannelCount( pnpInterface, /* isInput= */ 1 ); - if( count > 0 ) - { - deviceInfo->maxInputChannels = count; - winDsDeviceInfo->deviceInputChannelCountIsKnown = 1; - } + deviceInfo->maxInputChannels = count; + winDsDeviceInfo->deviceInputChannelCountIsKnown = 1; } + } #endif /* PAWIN_USE_WDMKS_DEVICE_INFO */ - deviceInfo->defaultLowInputLatency = 0.; /** @todo IMPLEMENT ME */ - deviceInfo->defaultLowOutputLatency = 0.; /** @todo IMPLEMENT ME */ - deviceInfo->defaultHighInputLatency = 0.; /** @todo IMPLEMENT ME */ - deviceInfo->defaultHighOutputLatency = 0.; /** @todo IMPLEMENT ME */ + deviceInfo->defaultLowInputLatency = 0.; /** @todo IMPLEMENT ME */ + deviceInfo->defaultLowOutputLatency = 0.; /** @todo IMPLEMENT ME */ + deviceInfo->defaultHighInputLatency = 0.; /** @todo IMPLEMENT ME */ + deviceInfo->defaultHighOutputLatency = 0.; /** @todo IMPLEMENT ME */ /* constants from a WINE patch by Francois Gouget, see: - http://www.winehq.com/hypermail/wine-patches/2003/01/0290.html +http://www.winehq.com/hypermail/wine-patches/2003/01/0290.html - --- - Date: Fri, 14 May 2004 10:38:12 +0200 (CEST) - From: Francois Gouget - To: Ross Bencina - Subject: Re: Permission to use wine 48/96 wave patch in BSD licensed library +--- +Date: Fri, 14 May 2004 10:38:12 +0200 (CEST) +From: Francois Gouget +To: Ross Bencina +Subject: Re: Permission to use wine 48/96 wave patch in BSD licensed library - [snip] +[snip] - I give you permission to use the patch below under the BSD license. - http://www.winehq.com/hypermail/wine-patches/2003/01/0290.html +I give you permission to use the patch below under the BSD license. +http://www.winehq.com/hypermail/wine-patches/2003/01/0290.html - [snip] +[snip] */ #ifndef WAVE_FORMAT_48M08 #define WAVE_FORMAT_48M08 0x00001000 /* 48 kHz, Mono, 8-bit */ @@ -956,53 +927,73 @@ static PaError AddInputDeviceInfoFromDirectSoundCapture( #define WAVE_FORMAT_96S16 0x00080000 /* 96 kHz, Stereo, 16-bit */ #endif - /* defaultSampleRate */ - if( caps.dwChannels == 2 ) - { - if( caps.dwFormats & WAVE_FORMAT_4S16 ) - deviceInfo->defaultSampleRate = 44100.0; - else if( caps.dwFormats & WAVE_FORMAT_48S16 ) - deviceInfo->defaultSampleRate = 48000.0; - else if( caps.dwFormats & WAVE_FORMAT_2S16 ) - deviceInfo->defaultSampleRate = 22050.0; - else if( caps.dwFormats & WAVE_FORMAT_1S16 ) - deviceInfo->defaultSampleRate = 11025.0; - else if( caps.dwFormats & WAVE_FORMAT_96S16 ) - deviceInfo->defaultSampleRate = 96000.0; - else - deviceInfo->defaultSampleRate = 0.; - } - else if( caps.dwChannels == 1 ) - { - if( caps.dwFormats & WAVE_FORMAT_4M16 ) - deviceInfo->defaultSampleRate = 44100.0; - else if( caps.dwFormats & WAVE_FORMAT_48M16 ) - deviceInfo->defaultSampleRate = 48000.0; - else if( caps.dwFormats & WAVE_FORMAT_2M16 ) - deviceInfo->defaultSampleRate = 22050.0; - else if( caps.dwFormats & WAVE_FORMAT_1M16 ) - deviceInfo->defaultSampleRate = 11025.0; - else if( caps.dwFormats & WAVE_FORMAT_96M16 ) - deviceInfo->defaultSampleRate = 96000.0; - else - deviceInfo->defaultSampleRate = 0.; - } - else deviceInfo->defaultSampleRate = 0.; + /* defaultSampleRate */ + if( caps.dwChannels == 2 ) + { + if( caps.dwFormats & WAVE_FORMAT_4S16 ) + deviceInfo->defaultSampleRate = 44100.0; + else if( caps.dwFormats & WAVE_FORMAT_48S16 ) + deviceInfo->defaultSampleRate = 48000.0; + else if( caps.dwFormats & WAVE_FORMAT_2S16 ) + deviceInfo->defaultSampleRate = 22050.0; + else if( caps.dwFormats & WAVE_FORMAT_1S16 ) + deviceInfo->defaultSampleRate = 11025.0; + else if( caps.dwFormats & WAVE_FORMAT_96S16 ) + deviceInfo->defaultSampleRate = 96000.0; + else + deviceInfo->defaultSampleRate = 0.; } + else if( caps.dwChannels == 1 ) + { + if( caps.dwFormats & WAVE_FORMAT_4M16 ) + deviceInfo->defaultSampleRate = 44100.0; + else if( caps.dwFormats & WAVE_FORMAT_48M16 ) + deviceInfo->defaultSampleRate = 48000.0; + else if( caps.dwFormats & WAVE_FORMAT_2M16 ) + deviceInfo->defaultSampleRate = 22050.0; + else if( caps.dwFormats & WAVE_FORMAT_1M16 ) + deviceInfo->defaultSampleRate = 11025.0; + else if( caps.dwFormats & WAVE_FORMAT_96M16 ) + deviceInfo->defaultSampleRate = 96000.0; + else + deviceInfo->defaultSampleRate = 0.; + } + else deviceInfo->defaultSampleRate = 0.; } IDirectSoundCapture_Release( lpDirectSoundCapture ); } - if( deviceOK ) + + /* Copy GUID to the device info structure. Set pointer. */ + if( lpGUID == NULL ) { - deviceInfo->name = name; - - if( lpGUID == NULL ) - hostApi->info.defaultInputDevice = hostApi->info.deviceCount; - - hostApi->info.deviceCount++; + winDsDeviceInfo->lpGUID = NULL; } + else + { + // target device UID property + WCHAR duid[39]; + char *deviceUID; + deviceUID = (char *)PaUtil_GroupAllocateMemory(allocations, 39); + + StringFromGUID2(&(*lpGUID), (LPOLESTR) &duid, 39); + wcstombs(deviceUID, duid, sizeof(deviceUID)); + WideCharToMultiByte( CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,\ + duid, -1, deviceUID, 39, NULL, NULL ); + deviceInfo->deviceUID = deviceUID; + + winDsDeviceInfo->lpGUID = &winDsDeviceInfo->guid; + memcpy( &winDsDeviceInfo->guid, lpGUID, sizeof(GUID) ); + } + + deviceInfo->name = name; + + return result; + +error: + if( lpDirectSoundCapture ) + IDirectSoundCapture_Release( lpDirectSoundCapture ); return result; } @@ -1012,12 +1003,10 @@ static PaError AddInputDeviceInfoFromDirectSoundCapture( PaError PaWinDs_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) { PaError result = paNoError; - int i, deviceCount; + int deviceCount; PaWinDsHostApiRepresentation *winDsHostApi; - DSDeviceNamesAndGUIDs deviceNamesAndGUIDs; - - PaWinDsDeviceInfo *deviceInfoArray; char comWasInitialized = 0; + void *scanResults = 0; /* If COM is already initialized CoInitialize will either return @@ -1034,11 +1023,6 @@ PaError PaWinDs_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInde if( hr != RPC_E_CHANGED_MODE ) comWasInitialized = 1; - /* initialise guid vectors so they can be safely deleted on error */ - deviceNamesAndGUIDs.winDsHostApi = NULL; - deviceNamesAndGUIDs.inputNamesAndGUIDs.items = NULL; - deviceNamesAndGUIDs.outputNamesAndGUIDs.items = NULL; - PaWinDs_InitializeDSoundEntryPoints(); winDsHostApi = (PaWinDsHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaWinDsHostApiRepresentation) ); @@ -1062,109 +1046,25 @@ PaError PaWinDs_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInde (*hostApi)->info.type = paDirectSound; (*hostApi)->info.name = "Windows DirectSound"; + /* these are all updated by CommitDeviceInfos() */ (*hostApi)->info.deviceCount = 0; (*hostApi)->info.defaultInputDevice = paNoDevice; (*hostApi)->info.defaultOutputDevice = paNoDevice; + (*hostApi)->deviceInfos = 0; - -/* DSound - enumerate devices to count them and to gather their GUIDs */ - - result = InitializeDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.inputNamesAndGUIDs, winDsHostApi->allocations ); + result = ScanDeviceInfos( &winDsHostApi->inheritedHostApiRep, hostApiIndex, &scanResults, &deviceCount ); if( result != paNoError ) goto error; - result = InitializeDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.outputNamesAndGUIDs, winDsHostApi->allocations ); - if( result != paNoError ) - goto error; + /* FIXME for now we ignore the result of CommitDeviceInfos(), it should probably be an atomic non-failing operation */ + CommitDeviceInfos( &winDsHostApi->inheritedHostApiRep, hostApiIndex, scanResults, deviceCount ); - paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateA( (LPDSENUMCALLBACK)CollectGUIDsProc, (void *)&deviceNamesAndGUIDs.inputNamesAndGUIDs ); - - paWinDsDSoundEntryPoints.DirectSoundEnumerateA( (LPDSENUMCALLBACK)CollectGUIDsProc, (void *)&deviceNamesAndGUIDs.outputNamesAndGUIDs ); - - if( deviceNamesAndGUIDs.inputNamesAndGUIDs.enumerationError != paNoError ) - { - result = deviceNamesAndGUIDs.inputNamesAndGUIDs.enumerationError; - goto error; - } - - if( deviceNamesAndGUIDs.outputNamesAndGUIDs.enumerationError != paNoError ) - { - result = deviceNamesAndGUIDs.outputNamesAndGUIDs.enumerationError; - goto error; - } - - deviceCount = deviceNamesAndGUIDs.inputNamesAndGUIDs.count + deviceNamesAndGUIDs.outputNamesAndGUIDs.count; - -#ifdef PAWIN_USE_WDMKS_DEVICE_INFO - if( deviceCount > 0 ) - { - deviceNamesAndGUIDs.winDsHostApi = winDsHostApi; - FindDevicePnpInterfaces( &deviceNamesAndGUIDs ); - } -#endif /* PAWIN_USE_WDMKS_DEVICE_INFO */ - - if( deviceCount > 0 ) - { - /* allocate array for pointers to PaDeviceInfo structs */ - (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( - winDsHostApi->allocations, sizeof(PaDeviceInfo*) * deviceCount ); - if( !(*hostApi)->deviceInfos ) - { - result = paInsufficientMemory; - goto error; - } - - /* allocate all PaDeviceInfo structs in a contiguous block */ - deviceInfoArray = (PaWinDsDeviceInfo*)PaUtil_GroupAllocateMemory( - winDsHostApi->allocations, sizeof(PaWinDsDeviceInfo) * deviceCount ); - if( !deviceInfoArray ) - { - result = paInsufficientMemory; - goto error; - } - - for( i=0; i < deviceCount; ++i ) - { - PaDeviceInfo *deviceInfo = &deviceInfoArray[i].inheritedDeviceInfo; - deviceInfo->structVersion = 2; - deviceInfo->hostApi = hostApiIndex; - deviceInfo->name = 0; - (*hostApi)->deviceInfos[i] = deviceInfo; - } - - for( i=0; i < deviceNamesAndGUIDs.inputNamesAndGUIDs.count; ++i ) - { - result = AddInputDeviceInfoFromDirectSoundCapture( winDsHostApi, - deviceNamesAndGUIDs.inputNamesAndGUIDs.items[i].name, - deviceNamesAndGUIDs.inputNamesAndGUIDs.items[i].lpGUID, - deviceNamesAndGUIDs.inputNamesAndGUIDs.items[i].pnpInterface ); - if( result != paNoError ) - goto error; - } - - for( i=0; i < deviceNamesAndGUIDs.outputNamesAndGUIDs.count; ++i ) - { - result = AddOutputDeviceInfoFromDirectSound( winDsHostApi, - deviceNamesAndGUIDs.outputNamesAndGUIDs.items[i].name, - deviceNamesAndGUIDs.outputNamesAndGUIDs.items[i].lpGUID, - deviceNamesAndGUIDs.outputNamesAndGUIDs.items[i].pnpInterface ); - if( result != paNoError ) - goto error; - } - } - - result = TerminateDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.inputNamesAndGUIDs ); - if( result != paNoError ) - goto error; - - result = TerminateDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.outputNamesAndGUIDs ); - if( result != paNoError ) - goto error; - - (*hostApi)->Terminate = Terminate; (*hostApi)->OpenStream = OpenStream; (*hostApi)->IsFormatSupported = IsFormatSupported; + (*hostApi)->ScanDeviceInfos = ScanDeviceInfos; + (*hostApi)->CommitDeviceInfos = CommitDeviceInfos; + (*hostApi)->DisposeDeviceInfos = DisposeDeviceInfos; PaUtil_InitializeStreamInterface( &winDsHostApi->callbackStreamInterface, CloseStream, StartStream, StopStream, AbortStream, IsStreamStopped, IsStreamActive, @@ -1187,12 +1087,11 @@ error: PaUtil_FreeAllAllocations( winDsHostApi->allocations ); PaUtil_DestroyAllocationGroup( winDsHostApi->allocations ); } - + PaUtil_FreeMemory( winDsHostApi ); } - TerminateDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.inputNamesAndGUIDs ); - TerminateDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.outputNamesAndGUIDs ); + if( comWasInitialized ) CoUninitialize(); @@ -1369,6 +1268,233 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, return paFormatIsSupported; } +/***********************************************************************************/ +static PaError ScanDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex hostApiIndex, void **scanResults, int *newDeviceCount ) +{ + PaWinDsHostApiRepresentation *winDsHostApi = (PaWinDsHostApiRepresentation*)hostApi; + PaWinDsDeviceInfo *deviceInfoArray; + char comWasInitialized = winDsHostApi->comWasInitialized; + PaError result = paNoError; + PaWinDsScanDeviceInfosResults *outArgument = 0; + DSDeviceNamesAndGUIDs deviceNamesAndGUIDs; + int i = 0; + int maximumNewDeviceCount = 0; + + /* Check preconditions */ + if( !comWasInitialized || scanResults == NULL || newDeviceCount == NULL ) + return paInternalError; + + /* initialize the out params */ + *scanResults = NULL; + *newDeviceCount = 0; + + /* initialise guid vectors so they can be safely deleted on error */ + deviceNamesAndGUIDs.winDsHostApi = NULL; + deviceNamesAndGUIDs.inputNamesAndGUIDs.items = NULL; + deviceNamesAndGUIDs.outputNamesAndGUIDs.items = NULL; + + result = InitializeDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.inputNamesAndGUIDs, winDsHostApi->allocations ); + if( result != paNoError ) + goto error; + + result = InitializeDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.outputNamesAndGUIDs, winDsHostApi->allocations ); + if( result != paNoError ) + goto error; + + deviceNamesAndGUIDs.winDsHostApi = winDsHostApi; + + /* DSound - enumerate devices to count them and to gather their GUIDs and device names */ + + paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateA( (LPDSENUMCALLBACK)CollectGUIDsProc, (void *)&deviceNamesAndGUIDs.inputNamesAndGUIDs ); + + if( deviceNamesAndGUIDs.inputNamesAndGUIDs.enumerationError != paNoError ) + { + result = deviceNamesAndGUIDs.inputNamesAndGUIDs.enumerationError; + goto error; + } + + paWinDsDSoundEntryPoints.DirectSoundEnumerateA( (LPDSENUMCALLBACK)CollectGUIDsProc, (void *)&deviceNamesAndGUIDs.outputNamesAndGUIDs ); + + if( deviceNamesAndGUIDs.outputNamesAndGUIDs.enumerationError != paNoError ) + { + result = deviceNamesAndGUIDs.outputNamesAndGUIDs.enumerationError; + goto error; + } + + maximumNewDeviceCount = deviceNamesAndGUIDs.inputNamesAndGUIDs.count + + deviceNamesAndGUIDs.outputNamesAndGUIDs.count; + +#ifdef PAWIN_USE_WDMKS_DEVICE_INFO + if( maximumNewDeviceCount > 0 ) + { + FindDevicePnpInterfaces( &deviceNamesAndGUIDs ); + } +#endif /* PAWIN_USE_WDMKS_DEVICE_INFO */ + + if( maximumNewDeviceCount > 0 ) + { + /* Allocate the out param for all the info we need */ + outArgument = (PaWinDsScanDeviceInfosResults *) PaUtil_GroupAllocateMemory( + winDsHostApi->allocations, sizeof(PaWinDsScanDeviceInfosResults) ); + if( !outArgument ) + { + result = paInsufficientMemory; + goto error; + } + + /* allocate array for pointers to PaDeviceInfo structs */ + outArgument->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( + winDsHostApi->allocations, sizeof(PaDeviceInfo*) * maximumNewDeviceCount ); + if( !outArgument->deviceInfos ) + { + result = paInsufficientMemory; + goto error; + } + + /* allocate all PaDeviceInfo structs in a contiguous block */ + deviceInfoArray = (PaWinDsDeviceInfo*)PaUtil_GroupAllocateMemory( + winDsHostApi->allocations, sizeof(PaWinDsDeviceInfo) * maximumNewDeviceCount ); + if( !deviceInfoArray ) + { + result = paInsufficientMemory; + goto error; + } + + for( i = 0 ; i < maximumNewDeviceCount; ++i ) + { + PaDeviceInfo *deviceInfo = &deviceInfoArray[i].inheritedDeviceInfo; + deviceInfo->structVersion = 3; + deviceInfo->hostApi = hostApiIndex; + deviceInfo->name = 0; + + outArgument->deviceInfos[ i ] = deviceInfo; + } + + for( i = 0 ; i < deviceNamesAndGUIDs.inputNamesAndGUIDs.count ; ++i ) + { + PaWinDsDeviceInfo *winDsDeviceInfo = (PaWinDsDeviceInfo*)outArgument->deviceInfos[*newDeviceCount]; + + result = AddInputDeviceInfoFromDirectSoundCapture( winDsDeviceInfo, + deviceNamesAndGUIDs.inputNamesAndGUIDs.items[i].name, + deviceNamesAndGUIDs.inputNamesAndGUIDs.items[i].lpGUID, + deviceNamesAndGUIDs.inputNamesAndGUIDs.items[i].pnpInterface, + winDsHostApi->allocations ); + if( result == paNoError ) + { + if( deviceNamesAndGUIDs.inputNamesAndGUIDs.items[i].lpGUID == NULL ) + outArgument->defaultInputDevice = *newDeviceCount; + (*newDeviceCount)++; + } + /* ignore error results here and just skip the device */ + } + + for( i = 0 ; i < deviceNamesAndGUIDs.outputNamesAndGUIDs.count ; ++i ) + { + PaWinDsDeviceInfo *winDsDeviceInfo = (PaWinDsDeviceInfo*)outArgument->deviceInfos[*newDeviceCount]; + + result = AddOutputDeviceInfoFromDirectSound( winDsDeviceInfo, + deviceNamesAndGUIDs.outputNamesAndGUIDs.items[i].name, + deviceNamesAndGUIDs.outputNamesAndGUIDs.items[i].lpGUID, + deviceNamesAndGUIDs.outputNamesAndGUIDs.items[i].pnpInterface, + winDsHostApi->allocations ); + if( result == paNoError ) + { + if( deviceNamesAndGUIDs.outputNamesAndGUIDs.items[i].lpGUID == NULL ) + outArgument->defaultOutputDevice = *newDeviceCount; + (*newDeviceCount)++; + } + /* ignore error results here and just skip the device */ + } + } + + result = TerminateDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.inputNamesAndGUIDs ); + if( result != paNoError ) + goto error; + + result = TerminateDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.outputNamesAndGUIDs ); + if( result != paNoError ) + goto error; + + *scanResults = outArgument; + return result; + +error: + TerminateDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.inputNamesAndGUIDs ); + TerminateDSDeviceNameAndGUIDVector( &deviceNamesAndGUIDs.outputNamesAndGUIDs ); + + if( outArgument ) + { + if( outArgument->deviceInfos ) + { + if( outArgument->deviceInfos[0] ) + { + PaUtil_GroupFreeMemory( winDsHostApi->allocations, outArgument->deviceInfos[0] ); + } + + PaUtil_GroupFreeMemory( winDsHostApi->allocations, outArgument->deviceInfos ); + } + } + return result; +} + +static PaError CommitDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index, void *scanResults, int deviceCount ) +{ + PaWinDsHostApiRepresentation *winDsHostApi = (PaWinDsHostApiRepresentation*)hostApi; + PaError result = paNoError; + int i = 0; + + hostApi->info.deviceCount = 0; + hostApi->info.defaultInputDevice = paNoDevice; + hostApi->info.defaultOutputDevice = paNoDevice; + + /* Free any old memory which might be in the device info */ + if( hostApi->deviceInfos ) + { + PaUtil_GroupFreeMemory( winDsHostApi->allocations, hostApi->deviceInfos[0] ); + PaUtil_GroupFreeMemory( winDsHostApi->allocations, hostApi->deviceInfos ); + hostApi->deviceInfos = NULL; + } + + if( scanResults != NULL ) + { + PaWinDsScanDeviceInfosResults *scanDeviceInfosResults = ( PaWinDsScanDeviceInfosResults * ) scanResults; + + if( deviceCount > 0 ) + { + /* use the array allocated in ScanDeviceInfos() as our deviceInfos */ + hostApi->deviceInfos = scanDeviceInfosResults->deviceInfos; + + hostApi->info.defaultInputDevice = scanDeviceInfosResults->defaultInputDevice; + hostApi->info.defaultOutputDevice = scanDeviceInfosResults->defaultOutputDevice; + + hostApi->info.deviceCount = deviceCount; + } + + PaUtil_GroupFreeMemory( winDsHostApi->allocations, scanDeviceInfosResults ); + } + + return result; +} + +static PaError DisposeDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, void *scanResults, int deviceCount ) +{ + PaWinDsHostApiRepresentation *winDsHostApi = (PaWinDsHostApiRepresentation*)hostApi; + + if( scanResults != NULL ) + { + PaWinDsScanDeviceInfosResults *scanDeviceInfosResults = ( PaWinDsScanDeviceInfosResults * ) scanResults; + + if( scanDeviceInfosResults->deviceInfos ) + { + PaUtil_GroupFreeMemory( winDsHostApi->allocations, scanDeviceInfosResults->deviceInfos[0] ); /* all device info structs are allocated in a block so we can destroy them here */ + PaUtil_GroupFreeMemory( winDsHostApi->allocations, scanDeviceInfosResults->deviceInfos ); + } + + PaUtil_GroupFreeMemory( winDsHostApi->allocations, scanDeviceInfosResults ); + } + + return paNoError; +} /************************************************************************* ** Determine minimum number of buffers required for this host based diff --git a/src/hostapi/jack/pa_jack.c b/src/hostapi/jack/pa_jack.c index 24a56d9..fd78e8b 100644 --- a/src/hostapi/jack/pa_jack.c +++ b/src/hostapi/jack/pa_jack.c @@ -1,5 +1,5 @@ /* - * $Id$ + * $Id: pa_jack.c 1661 2011-04-28 18:54:46Z rob_bielik $ * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com * JACK Implementation by Joshua Haberman @@ -749,6 +749,9 @@ PaError PaJack_Initialize( PaUtilHostApiRepresentation **hostApi, /* Register functions */ + (*hostApi)->ScanDeviceInfos = NULL; + (*hostApi)->CommitDeviceInfos = NULL; + (*hostApi)->DisposeDeviceInfos = NULL; (*hostApi)->Terminate = Terminate; (*hostApi)->OpenStream = OpenStream; (*hostApi)->IsFormatSupported = IsFormatSupported; @@ -1181,7 +1184,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, minimum_buffer_frames = jackHostApi->jack_buffer_size * 3; /* setup blocking API data structures (FIXME: can fail) */ - BlockingBegin( stream, minimum_buffer_frames ); + BlockingBegin( stream, minimum_buffer_frames ); /* install our own callback for the blocking API */ streamCallback = BlockingCallback; diff --git a/src/hostapi/oss/pa_unix_oss.c b/src/hostapi/oss/pa_unix_oss.c index b523746..5da34c1 100644 --- a/src/hostapi/oss/pa_unix_oss.c +++ b/src/hostapi/oss/pa_unix_oss.c @@ -1,5 +1,5 @@ /* - * $Id$ + * $Id: pa_unix_oss.c 1661 2011-04-28 18:54:46Z rob_bielik $ * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com * OSS implementation by: @@ -256,6 +256,9 @@ PaError PaOSS_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex (*hostApi)->Terminate = Terminate; (*hostApi)->OpenStream = OpenStream; (*hostApi)->IsFormatSupported = IsFormatSupported; + (*hostApi)->ScanDeviceInfos = NULL; + (*hostApi)->CommitDeviceInfos = NULL; + (*hostApi)->DisposeDeviceInfos = NULL; PA_ENSURE( BuildDeviceList( ossHostApi ) ); diff --git a/src/hostapi/skeleton/pa_hostapi_skeleton.c b/src/hostapi/skeleton/pa_hostapi_skeleton.c index 84f73c7..726c407 100644 --- a/src/hostapi/skeleton/pa_hostapi_skeleton.c +++ b/src/hostapi/skeleton/pa_hostapi_skeleton.c @@ -1,5 +1,5 @@ /* - * $Id$ + * $Id: pa_hostapi_skeleton.c 1661 2011-04-28 18:54:46Z rob_bielik $ * Portable Audio I/O Library skeleton implementation * demonstrates how to use the common functions to implement support * for a host API @@ -206,9 +206,15 @@ PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiI } } + (*hostApi)->ScanDeviceInfos = NULL; + (*hostApi)->CommitDeviceInfos = NULL; + (*hostApi)->DisposeDeviceInfos = NULL; (*hostApi)->Terminate = Terminate; (*hostApi)->OpenStream = OpenStream; (*hostApi)->IsFormatSupported = IsFormatSupported; + (*hostApi)->ScanDeviceInfos = NULL; + (*hostApi)->CommitDeviceInfos = NULL; + (*hostApi)->DisposeDeviceInfos = NULL; PaUtil_InitializeStreamInterface( &skeletonHostApi->callbackStreamInterface, CloseStream, StartStream, StopStream, AbortStream, IsStreamStopped, IsStreamActive, diff --git a/src/hostapi/wasapi/pa_win_wasapi.c b/src/hostapi/wasapi/pa_win_wasapi.c index b8fda8f..0310151 100644 --- a/src/hostapi/wasapi/pa_win_wasapi.c +++ b/src/hostapi/wasapi/pa_win_wasapi.c @@ -76,20 +76,20 @@ #include "pa_ringbuffer.h" #ifndef NTDDI_VERSION - + #undef WINVER #undef _WIN32_WINNT #define WINVER 0x0600 // VISTA #define _WIN32_WINNT WINVER #ifndef _AVRT_ //<< fix MinGW dummy compile by defining missing type: AVRT_PRIORITY - typedef enum _AVRT_PRIORITY - { - AVRT_PRIORITY_LOW = -1, - AVRT_PRIORITY_NORMAL, - AVRT_PRIORITY_HIGH, - AVRT_PRIORITY_CRITICAL - } AVRT_PRIORITY, *PAVRT_PRIORITY; + typedef enum _AVRT_PRIORITY + { + AVRT_PRIORITY_LOW = -1, + AVRT_PRIORITY_NORMAL, + AVRT_PRIORITY_HIGH, + AVRT_PRIORITY_CRITICAL + } AVRT_PRIORITY, *PAVRT_PRIORITY; #endif #include // << for IID/CLSID @@ -132,7 +132,7 @@ typedef LONGLONG REFERENCE_TIME; #define NONAMELESSUNION #endif - + #ifndef WAVE_FORMAT_IEEE_FLOAT #define WAVE_FORMAT_IEEE_FLOAT 0x0003 // 32-bit floating-point #endif @@ -363,10 +363,10 @@ PaWasapiDeviceInfo; typedef struct { PaUtilHostApiRepresentation inheritedHostApiRep; - PaUtilStreamInterface callbackStreamInterface; - PaUtilStreamInterface blockingStreamInterface; + PaUtilStreamInterface callbackStreamInterface; + PaUtilStreamInterface blockingStreamInterface; - PaUtilAllocationGroup *allocations; + PaUtilAllocationGroup *allocations; /* implementation specific data goes here */ @@ -450,22 +450,22 @@ typedef struct PaWasapiStream { /* IMPLEMENT ME: rename this */ PaUtilStreamRepresentation streamRepresentation; - PaUtilCpuLoadMeasurer cpuLoadMeasurer; - PaUtilBufferProcessor bufferProcessor; + PaUtilCpuLoadMeasurer cpuLoadMeasurer; + PaUtilBufferProcessor bufferProcessor; // input - PaWasapiSubStream in; + PaWasapiSubStream in; IAudioCaptureClient *captureClientParent; IStream *captureClientStream; IAudioCaptureClient *captureClient; - IAudioEndpointVolume *inVol; + IAudioEndpointVolume *inVol; // output - PaWasapiSubStream out; + PaWasapiSubStream out; IAudioRenderClient *renderClientParent; IStream *renderClientStream; IAudioRenderClient *renderClient; - IAudioEndpointVolume *outVol; + IAudioEndpointVolume *outVol; // event handles for event-driven processing mode HANDLE event[S_COUNT]; @@ -731,7 +731,7 @@ UINT32 ALIGN_NEXT_POW2(UINT32 v) // Aligns WASAPI buffer to 128 byte packet boundary. HD Audio will fail to play if buffer // is misaligned. This problem was solved in Windows 7 were AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED // is thrown although we must align for Vista anyway. -static UINT32 AlignFramesPerBuffer(UINT32 nFrames, UINT32 nSamplesPerSec, UINT32 nBlockAlign, +static UINT32 AlignFramesPerBuffer(UINT32 nFrames, UINT32 nSamplesPerSec, UINT32 nBlockAlign, ALIGN_FUNC pAlignFunc) { #define HDA_PACKET_SIZE (128) @@ -751,7 +751,7 @@ static UINT32 AlignFramesPerBuffer(UINT32 nFrames, UINT32 nSamplesPerSec, UINT32 frame_bytes = packets * HDA_PACKET_SIZE; nFrames = frame_bytes / nBlockAlign; - + return nFrames; #undef HDA_PACKET_SIZE @@ -1034,7 +1034,7 @@ static MixMonoToStereoF _GetMonoToStereoMixer(PaSampleFormat format, EMixerDir d case paInt24: return _MixMonoToStereo_2TO1_24_L; case paInt32: return _MixMonoToStereo_2TO1_32_L; case paFloat32: return _MixMonoToStereo_2TO1_32f_L; - } + } break; } @@ -1061,7 +1061,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd If COM is already initialized CoInitialize will either return FALSE, or RPC_E_CHANGED_MODE if it was initialised in a different threading mode. In either case we shouldn't consider it an error - but we need to be careful to not call CoUninitialize() if + but we need to be careful to not call CoUninitialize() if RPC_E_CHANGED_MODE was returned. */ hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); @@ -1102,7 +1102,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd paWasapi->enumerator = NULL; hr = CoCreateInstance(&pa_CLSID_IMMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &pa_IID_IMMDeviceEnumerator, (void **)&paWasapi->enumerator); - + // We need to set the result to a value otherwise we will return paNoError // [IF_FAILED_JUMP(hResult, error);] IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error); @@ -1118,7 +1118,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd // We need to set the result to a value otherwise we will return paNoError // [IF_FAILED_JUMP(hResult, error);] IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error); - } + } } else { @@ -1142,7 +1142,7 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd // We need to set the result to a value otherwise we will return paNoError // [IF_FAILED_JUMP(hResult, error);] IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error); - } + } } else { @@ -1386,6 +1386,9 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd } } + (*hostApi)->ScanDeviceInfos = NULL; + (*hostApi)->CommitDeviceInfos = NULL; + (*hostApi)->DisposeDeviceInfos = NULL; (*hostApi)->Terminate = Terminate; (*hostApi)->OpenStream = OpenStream; (*hostApi)->IsFormatSupported = IsFormatSupported; @@ -1466,7 +1469,7 @@ static void Terminate( PaUtilHostApiRepresentation *hostApi ) DWORD calling_thread_id = GetCurrentThreadId(); if (g_WasapiInitThread != calling_thread_id) { - PRINT(("WASAPI: failed CoUninitializes calling thread[%d] does not match initializing thread[%d]\n", + PRINT(("WASAPI: failed CoUninitializes calling thread[%d] does not match initializing thread[%d]\n", calling_thread_id, g_WasapiInitThread)); } else @@ -1572,20 +1575,20 @@ static void LogWAVEFORMATEXTENSIBLE(const WAVEFORMATEXTENSIBLE *in) { case WAVE_FORMAT_EXTENSIBLE: { - PRINT(("wFormatTag =WAVE_FORMAT_EXTENSIBLE\n")); + PRINT(("wFormatTag=WAVE_FORMAT_EXTENSIBLE\n")); if (IsEqualGUID(&in->SubFormat, &pa_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) { - PRINT(("SubFormat =KSDATAFORMAT_SUBTYPE_IEEE_FLOAT\n")); + PRINT(("SubFormat=KSDATAFORMAT_SUBTYPE_IEEE_FLOAT\n")); } else if (IsEqualGUID(&in->SubFormat, &pa_KSDATAFORMAT_SUBTYPE_PCM)) { - PRINT(("SubFormat =KSDATAFORMAT_SUBTYPE_PCM\n")); + PRINT(("SubFormat=KSDATAFORMAT_SUBTYPE_PCM\n")); } else { - PRINT(("SubFormat =CUSTOM GUID{%d:%d:%d:%d%d%d%d%d%d%d%d}\n", + PRINT(("SubFormat=CUSTOM GUID{%d:%d:%d:%d%d%d%d%d%d%d%d}\n", in->SubFormat.Data1, in->SubFormat.Data2, in->SubFormat.Data3, @@ -1598,13 +1601,13 @@ static void LogWAVEFORMATEXTENSIBLE(const WAVEFORMATEXTENSIBLE *in) (int)in->SubFormat.Data4[6], (int)in->SubFormat.Data4[7])); } - PRINT(("Samples.wValidBitsPerSample =%d\n", in->Samples.wValidBitsPerSample)); + PRINT(("Samples.wValidBitsPerSample=%d\n", in->Samples.wValidBitsPerSample)); PRINT(("dwChannelMask =0x%X\n",in->dwChannelMask)); break; } - case WAVE_FORMAT_PCM: PRINT(("wFormatTag =WAVE_FORMAT_PCM\n")); break; - case WAVE_FORMAT_IEEE_FLOAT: PRINT(("wFormatTag =WAVE_FORMAT_IEEE_FLOAT\n")); break; + case WAVE_FORMAT_PCM: PRINT(("wFormatTag=WAVE_FORMAT_PCM\n")); break; + case WAVE_FORMAT_IEEE_FLOAT: PRINT(("wFormatTag=WAVE_FORMAT_IEEE_FLOAT\n")); break; default: PRINT(("wFormatTag =UNKNOWN(%d)\n",old->wFormatTag)); break; } @@ -1642,8 +1645,8 @@ static PaSampleFormat WaveToPaFormat(const WAVEFORMATEXTENSIBLE *in) } } break; } - - case WAVE_FORMAT_IEEE_FLOAT: + + case WAVE_FORMAT_IEEE_FLOAT: return paFloat32; case WAVE_FORMAT_PCM: { @@ -1689,13 +1692,13 @@ static PaError MakeWaveFormatFromParams(WAVEFORMATEXTENSIBLE *wavex, const PaStr old->nBlockAlign = (old->nChannels * (old->wBitsPerSample/8)); old->nAvgBytesPerSec = (old->nSamplesPerSec * old->nBlockAlign); - // WAVEFORMATEX + //WAVEFORMATEX if ((params->channelCount <= 2) && ((bitsPerSample == 16) || (bitsPerSample == 8))) { old->cbSize = 0; old->wFormatTag = WAVE_FORMAT_PCM; } - // WAVEFORMATEXTENSIBLE + //WAVEFORMATEXTENSIBLE else { old->wFormatTag = WAVE_FORMAT_EXTENSIBLE; @@ -1894,7 +1897,7 @@ static PaError GetClosestFormat(IAudioClient *myClient, double sampleRate, // Try selecting suitable sample type for (i = 0; i < STATIC_ARRAY_SIZE(BestToWorst); ++i) - { + { WAVEFORMATEXTENSIBLE sample = { 0 }; PaStreamParameters sample_params = stereo_params; @@ -1904,7 +1907,7 @@ static PaError GetClosestFormat(IAudioClient *myClient, double sampleRate, hr = IAudioClient_IsFormatSupported(myClient, shareMode, &sample.Format, (shareMode == AUDCLNT_SHAREMODE_SHARED ? &sharedClosestMatch : NULL)); if (hr == S_OK) - { + { memcpy(outWavex, &sample, sizeof(WAVEFORMATEXTENSIBLE)); CoTaskMemFree(sharedClosestMatch); return (answer = paFormatIsSupported); @@ -1923,14 +1926,14 @@ static PaError GetClosestFormat(IAudioClient *myClient, double sampleRate, MakeWaveFormatFromParams(&spfmt, &spfmt_params, sampleRate); hr = IAudioClient_IsFormatSupported(myClient, shareMode, &spfmt.Format, (shareMode == AUDCLNT_SHAREMODE_SHARED ? &sharedClosestMatch : NULL)); - if (hr == S_OK) - { + if (hr == S_OK) + { memcpy(outWavex, &spfmt, sizeof(WAVEFORMATEXTENSIBLE)); CoTaskMemFree(sharedClosestMatch); - answer = paFormatIsSupported; + answer = paFormatIsSupported; break; + } } - } // Nothing helped LogHostError(hr); @@ -2107,11 +2110,11 @@ static void _RecalculateBuffersCount(PaWasapiSubStream *sub, UINT32 userFramesPe // - For Shared mode we use double buffering. if ((sub->shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE) || fullDuplex) { - // Exclusive mode does not allow >1 buffers be used for Event interface, e.g. GetBuffer + // Exclusive mode does not allow >1 buffers be used for Event interface, e.g. GetBuffer // call must acquire max buffer size and it all must be processed. if (sub->streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) sub->userBufferAndHostMatch = 1; - + // Use paUtilBoundedHostBufferSize because exclusive mode will starve and produce // bad quality of audio sub->buffers = 1; @@ -2119,7 +2122,7 @@ static void _RecalculateBuffersCount(PaWasapiSubStream *sub, UINT32 userFramesPe } // ------------------------------------------------------------------------------------------ -static void _CalculateAlignedPeriod(PaWasapiSubStream *pSub, UINT32 *nFramesPerLatency, +static void _CalculateAlignedPeriod(PaWasapiSubStream *pSub, UINT32 *nFramesPerLatency, ALIGN_FUNC pAlignFunc) { // Align frames to HD Audio packet size of 128 bytes for Exclusive mode only. @@ -2199,10 +2202,10 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu framesPerLatency += MakeFramesFromHns(SecondsTonano100(params->suggestedLatency), pSub->wavex.Format.nSamplesPerSec); #else // Calculate host buffer size - if ((pSub->shareMode != AUDCLNT_SHAREMODE_EXCLUSIVE) && + if ((pSub->shareMode != AUDCLNT_SHAREMODE_EXCLUSIVE) && (!pSub->streamFlags || ((pSub->streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) == 0))) { - framesPerLatency = PaUtil_GetFramesPerHostBuffer(userFramesPerBuffer, + framesPerLatency = PaUtil_GetFramesPerHostBuffer(userFramesPerBuffer, params->suggestedLatency, pSub->wavex.Format.nSamplesPerSec, 0/*, (pSub->streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK ? 0 : 1)*/); } @@ -2212,13 +2215,13 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu // Work 1:1 with user buffer (only polling allows to use >1) framesPerLatency += MakeFramesFromHns(SecondsTonano100(params->suggestedLatency), pSub->wavex.Format.nSamplesPerSec); - + // Use Polling if overall latency is > 5ms as it allows to use 100% CPU in a callback, // or user specified latency parameter overall = MakeHnsPeriod(framesPerLatency, pSub->wavex.Format.nSamplesPerSec); if ((overall >= (106667*2)/*21.33ms*/) || ((INT32)(params->suggestedLatency*100000.0) != 0/*0.01 msec granularity*/)) { - framesPerLatency = PaUtil_GetFramesPerHostBuffer(userFramesPerBuffer, + framesPerLatency = PaUtil_GetFramesPerHostBuffer(userFramesPerBuffer, params->suggestedLatency, pSub->wavex.Format.nSamplesPerSec, 0/*, (streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK ? 0 : 1)*/); @@ -2258,7 +2261,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu // Recalculate aligned period framesPerLatency = MakeFramesFromHns(pSub->period, pSub->wavex.Format.nSamplesPerSec); _CalculateAlignedPeriod(pSub, &framesPerLatency, ALIGN_BWD); - } + } } else { @@ -2268,7 +2271,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu // Recalculate aligned period framesPerLatency = MakeFramesFromHns(pSub->period, pSub->wavex.Format.nSamplesPerSec); _CalculateAlignedPeriod(pSub, &framesPerLatency, ALIGN_FWD); - } + } } /*! Windows 7 does not allow to set latency lower than minimal device period and will @@ -2277,8 +2280,8 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu */ { /*! AUDCLNT_E_BUFFER_SIZE_ERROR: Applies to Windows 7 and later. - Indicates that the buffer duration value requested by an exclusive-mode client is - out of range. The requested duration value for pull mode must not be greater than + Indicates that the buffer duration value requested by an exclusive-mode client is + out of range. The requested duration value for pull mode must not be greater than 500 milliseconds; for push mode the duration value must not be greater than 2 seconds. */ if (pSub->shareMode == AUDCLNT_SHAREMODE_EXCLUSIVE) @@ -2319,7 +2322,7 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu NULL); /*! WASAPI is tricky on large device buffer, sometimes 2000ms can be allocated sometimes - less. There is no known guaranteed level thus we make subsequent tries by decreasing + less. There is no known guaranteed level thus we make subsequent tries by decreasing buffer by 100ms per try. */ while ((hr == E_OUTOFMEMORY) && (pSub->period > (100 * 10000))) @@ -2469,9 +2472,9 @@ static HRESULT CreateAudioClient(PaWasapiStream *pStream, PaWasapiSubStream *pSu IAudioClient_AddRef(pSub->clientParent); // Recalculate buffers count - _RecalculateBuffersCount(pSub, - userFramesPerBuffer, - MakeFramesFromHns(pSub->period, pSub->wavex.Format.nSamplesPerSec), + _RecalculateBuffersCount(pSub, + userFramesPerBuffer, + MakeFramesFromHns(pSub->period, pSub->wavex.Format.nSamplesPerSec), fullDuplex); done: @@ -2766,7 +2769,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, // Only get IAudioCaptureClient input once here instead of getting it at multiple places based on the use hr = IAudioClient_GetService(stream->in.clientParent, &pa_IID_IAudioCaptureClient, (void **)&stream->captureClientParent); - if (hr != S_OK) + if (hr != S_OK) { LogHostError(hr); LogPaError(result = paUnanticipatedHostError); @@ -2782,10 +2785,10 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, // buffer if ((stream->in.tailBuffer = PaUtil_AllocateMemory(sizeof(PaUtilRingBuffer))) == NULL) - { + { LogPaError(result = paInsufficientMemory); - goto error; - } + goto error; + } memset(stream->in.tailBuffer, 0, sizeof(PaUtilRingBuffer)); // buffer memory region @@ -2801,7 +2804,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, { LogPaError(result = paInternalError); goto error; - } + } } } else @@ -2873,10 +2876,10 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, goto error; } - // Get closest format + // Get closest format hostOutputSampleFormat = PaUtil_SelectClosestAvailableFormat( WaveToPaFormat(&stream->out.wavex), outputSampleFormat ); - // Set user-side custom host processor + // Set user-side custom host processor if ((outputStreamInfo != NULL) && (outputStreamInfo->flags & paWinWasapiRedirectHostProcessor)) { @@ -2886,13 +2889,13 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, // Only get IAudioCaptureClient output once here instead of getting it at multiple places based on the use hr = IAudioClient_GetService(stream->out.clientParent, &pa_IID_IAudioRenderClient, (void **)&stream->renderClientParent); - if (hr != S_OK) + if (hr != S_OK) { LogHostError(hr); LogPaError(result = paUnanticipatedHostError); goto error; } - } + } else { outputChannelCount = 0; @@ -2974,7 +2977,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, else if (outputParameters) { - if ((stream->out.buffers == 1) && + if ((stream->out.buffers == 1) && (!stream->out.streamFlags || ((stream->out.streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK) == 0))) bufferMode = paUtilBoundedHostBufferSize; } @@ -3263,30 +3266,30 @@ static PaError StartStream( PaStream *s ) if ((stream->in.clientParent && (stream->in.streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK)) || (stream->out.clientParent && (stream->out.streamFlags & AUDCLNT_STREAMFLAGS_EVENTCALLBACK))) { - if ((stream->hThread = CREATE_THREAD(ProcThreadEvent)) == NULL) + if ((stream->hThread = CREATE_THREAD(ProcThreadEvent)) == NULL) { PRINT(("Failed creating thread: ProcThreadEvent.")); result = paUnanticipatedHostError; goto nonblocking_start_error; - } + } } else { - if ((stream->hThread = CREATE_THREAD(ProcThreadPoll)) == NULL) + if ((stream->hThread = CREATE_THREAD(ProcThreadPoll)) == NULL) { PRINT(("Failed creating thread: ProcThreadPoll.")); result = paUnanticipatedHostError; goto nonblocking_start_error; - } + } } // Wait for thread to start - if (WaitForSingleObject(stream->hThreadStart, 60*1000) == WAIT_TIMEOUT) + if (WaitForSingleObject(stream->hThreadStart, 60*1000) == WAIT_TIMEOUT) { PRINT(("Failed starting thread: timeout.")); result = paUnanticipatedHostError; goto nonblocking_start_error; - } + } } else { @@ -3300,7 +3303,7 @@ static PaError StartStream( PaStream *s ) } } if (stream->in.clientParent != NULL) - { + { if ((stream->hBlockingOpStreamRD = CreateEvent(NULL, TRUE, TRUE, NULL)) == NULL) { result = paInsufficientMemory; @@ -3506,7 +3509,7 @@ static PaError ReadStream( PaStream* s, void *_buffer, unsigned long frames ) } if (buf2 != NULL) - { + { // Register available frames to processor PaUtil_SetInputFrameCount(&stream->bufferProcessor, buf2_size); @@ -3525,9 +3528,9 @@ static PaError ReadStream( PaStream* s, void *_buffer, unsigned long frames ) // Read hardware while (frames != 0) { - // Check if blocking call must be interrupted + // Check if blocking call must be interrupted if (WaitForSingleObject(stream->hCloseRequest, sleep) != WAIT_TIMEOUT) - break; + break; // Get available frames (must be finding out available frames before call to IAudioCaptureClient_GetBuffer // othervise audio glitches will occur inExclusive mode as it seems that WASAPI has some scheduling/ @@ -3536,7 +3539,7 @@ static PaError ReadStream( PaStream* s, void *_buffer, unsigned long frames ) { LogHostError(hr); return paUnanticipatedHostError; - } + } // Wait for more frames to become available if (available == 0) @@ -3558,7 +3561,7 @@ static PaError ReadStream( PaStream* s, void *_buffer, unsigned long frames ) // Avoid busy waiting, schedule next 1 millesecond wait if (sleep == 0) sleep = ThreadIdleScheduler_NextSleep(&sched); - } + } else { if ((sleep = ThreadIdleScheduler_NextSleep(&sched)) != 0) @@ -3586,10 +3589,10 @@ static PaError ReadStream( PaStream* s, void *_buffer, unsigned long frames ) // Register available frames to processor PaUtil_SetInputFrameCount(&stream->bufferProcessor, available); - + // Register host buffer pointer to processor - PaUtil_SetInterleavedInputChannels(&stream->bufferProcessor, 0, wasapi_buffer, stream->bufferProcessor.inputChannelCount); - + PaUtil_SetInterleavedInputChannels(&stream->bufferProcessor, 0, wasapi_buffer, stream->bufferProcessor.inputChannelCount); + // Copy user data to host buffer (with conversion if applicable) processed = PaUtil_CopyInput(&stream->bufferProcessor, (void **)&user_buffer, frames); frames -= processed; @@ -3658,18 +3661,18 @@ static PaError WriteStream( PaStream* s, const void *_buffer, unsigned long fram } // Blocking (potentially, untill 'frames' are consumed) loop - while (frames != 0) - { - // Check if blocking call must be interrupted + while (frames != 0) + { + // Check if blocking call must be interrupted if (WaitForSingleObject(stream->hCloseRequest, sleep) != WAIT_TIMEOUT) - break; + break; // Get frames available if ((hr = _PollGetOutputFramesAvailable(stream, &available)) != S_OK) - { - LogHostError(hr); + { + LogHostError(hr); goto end; - } + } // Wait for more frames to become available if (available == 0) @@ -3688,42 +3691,42 @@ static PaError WriteStream( PaStream* s, const void *_buffer, unsigned long fram // Keep in 'frmaes' range if (available > frames) - available = frames; + available = frames; - // Get pointer to host buffer + // Get pointer to host buffer if ((hr = IAudioRenderClient_GetBuffer(stream->renderClient, available, &wasapi_buffer)) != S_OK) - { - // Buffer size is too big, waiting - if (hr == AUDCLNT_E_BUFFER_TOO_LARGE) - continue; + { + // Buffer size is too big, waiting + if (hr == AUDCLNT_E_BUFFER_TOO_LARGE) + continue; - LogHostError(hr); + LogHostError(hr); goto end; - } + } // Keep waiting again (on Vista it was noticed that WASAPI could SOMETIMES return NULL pointer // to buffer without returning AUDCLNT_E_BUFFER_TOO_LARGE instead) if (wasapi_buffer == NULL) continue; - // Register available frames to processor - PaUtil_SetOutputFrameCount(&stream->bufferProcessor, available); - - // Register host buffer pointer to processor - PaUtil_SetInterleavedOutputChannels(&stream->bufferProcessor, 0, wasapi_buffer, stream->bufferProcessor.outputChannelCount); - + // Register available frames to processor + PaUtil_SetOutputFrameCount(&stream->bufferProcessor, available); + + // Register host buffer pointer to processor + PaUtil_SetInterleavedOutputChannels(&stream->bufferProcessor, 0, wasapi_buffer, stream->bufferProcessor.outputChannelCount); + // Copy user data to host buffer (with conversion if applicable), this call will advance // pointer 'user_buffer' to consumed portion of data processed = PaUtil_CopyOutput(&stream->bufferProcessor, (const void **)&user_buffer, frames); frames -= processed; - // Release host buffer + // Release host buffer if ((hr = IAudioRenderClient_ReleaseBuffer(stream->renderClient, available, 0)) != S_OK) - { - LogHostError(hr); + { + LogHostError(hr); goto end; + } } - } end: @@ -4631,7 +4634,7 @@ PA_THREAD_FUNC ProcThreadPoll(void *param) DWORD sleep_ms = 0; DWORD sleep_ms_in; DWORD sleep_ms_out; - + BOOL bThreadComInitialized = FALSE; /* @@ -4675,7 +4678,7 @@ PA_THREAD_FUNC ProcThreadPoll(void *param) sleep_ms_out = GetFramesSleepTime(stream->bufferProcessor.framesPerUserBuffer, stream->out.wavex.Format.nSamplesPerSec); } - // Choose smallest + // Choose smallest if ((sleep_ms_in != 0) && (sleep_ms_out != 0)) sleep_ms = min(sleep_ms_in, sleep_ms_out); else @@ -4715,14 +4718,14 @@ PA_THREAD_FUNC ProcThreadPoll(void *param) { if ((hr = IAudioClient_Start(stream->in.clientProc)) != S_OK) { - LogHostError(hr); - goto thread_error; + LogHostError(hr); + goto thread_error; + } } - } // Initialize event & start OUTPUT stream if (stream->out.clientProc) - { + { // Preload buffer (obligatory, othervise ->Start() will fail), avoid processing // when in full-duplex mode as it requires input processing as well if (!PA_WASAPI__IS_FULLDUPLEX(stream)) @@ -4739,22 +4742,22 @@ PA_THREAD_FUNC ProcThreadPoll(void *param) if ((hr = ProcessOutputBuffer(stream, processor, frames)) != S_OK) { LogHostError(hr); // not fatal, just log - } - } + } + } } else - { + { if (frames != 0) - { + { if ((hr = ProcessOutputBuffer(stream, processor, frames)) != S_OK) - { + { LogHostError(hr); // not fatal, just log - } - } + } + } } } else - { + { LogHostError(hr); // not fatal, just log } } @@ -4817,7 +4820,7 @@ PA_THREAD_FUNC ProcThreadPoll(void *param) LogHostError(hr); goto thread_error; } - + // output if (stream->bufferMode == paUtilFixedHostBufferSize) { @@ -4827,7 +4830,7 @@ PA_THREAD_FUNC ProcThreadPoll(void *param) { LogHostError(hr); goto thread_error; - } + } } } else @@ -4838,7 +4841,7 @@ PA_THREAD_FUNC ProcThreadPoll(void *param) { LogHostError(hr); goto thread_error; - } + } } } @@ -4908,7 +4911,7 @@ PA_THREAD_FUNC ProcThreadPoll(void *param) LogPaError(paInsufficientMemory); break; - } + } } // replace buffer pointer @@ -4981,7 +4984,7 @@ PA_THREAD_FUNC ProcThreadPoll(void *param) if (sleep_ms == 0) { next_sleep = ThreadIdleScheduler_NextSleep(&scheduler); - } + } // get available frames if ((hr = _PollGetOutputFramesAvailable(stream, &o_frames)) != S_OK) diff --git a/src/hostapi/wdmks/pa_win_wdmks.c b/src/hostapi/wdmks/pa_win_wdmks.c index 8070dbf..3c21570 100644 --- a/src/hostapi/wdmks/pa_win_wdmks.c +++ b/src/hostapi/wdmks/pa_win_wdmks.c @@ -1,5 +1,5 @@ /* - * $Id$ + * $Id: pa_win_wdmks.c 1661 2011-04-28 18:54:46Z rob_bielik $ * PortAudio Windows WDM-KS interface * * Author: Andrew Baldwin @@ -59,8 +59,12 @@ #ifdef __GNUC__ #include - #define _WIN32_WINNT 0x0501 - #define WINVER 0x0501 + #ifndef _WIN32_WINNT + #define _WIN32_WINNT 0x0501 + #endif /* #ifndef _WIN32_WINNT */ + #ifndef WINVER + #define WINVER 0x0501 + #endif /* #ifndef WINVER */ #endif #include /* strlen() */ @@ -76,7 +80,7 @@ #include "pa_debugprint.h" #include -#include +/* #include MinGW-w64 4.7.1 from TDM-GCC throws multiple redefinition errors. */ #include #ifdef __GNUC__ @@ -1885,6 +1889,9 @@ PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd (*hostApi)->info.deviceCount = deviceCount; + (*hostApi)->ScanDeviceInfos = NULL; + (*hostApi)->CommitDeviceInfos = NULL; + (*hostApi)->DisposeDeviceInfos = NULL; (*hostApi)->Terminate = Terminate; (*hostApi)->OpenStream = OpenStream; (*hostApi)->IsFormatSupported = IsFormatSupported; @@ -3305,4 +3312,4 @@ static signed long GetStreamWriteAvailable( PaStream* s ) /* IMPLEMENT ME, see portaudio.h for required behavior*/ PA_LOGL_; return 0; -} \ No newline at end of file +} diff --git a/src/hostapi/wmme/pa_win_wmme.c b/src/hostapi/wmme/pa_win_wmme.c index 2979940..ad6ebc5 100644 --- a/src/hostapi/wmme/pa_win_wmme.c +++ b/src/hostapi/wmme/pa_win_wmme.c @@ -1,5 +1,5 @@ /* - * $Id$ + * $Id: pa_win_wmme.c 1663 2011-05-01 13:21:43Z rossb $ * pa_win_wmme.c * Implementation of PortAudio for Windows MultiMedia Extensions (WMME) * @@ -153,6 +153,9 @@ #define PA_MME_USE_HIGH_DEFAULT_LATENCY_ (0) /* For debugging glitches. */ +#define DRV_QUERYFUNCTIONINSTANCEID (DRV_RESERVED + 17) +#define DRV_QUERYFUNCTIONINSTANCEIDSIZE (DRV_RESERVED + 18) + #if PA_MME_USE_HIGH_DEFAULT_LATENCY_ #define PA_MME_WIN_9X_DEFAULT_LATENCY_ (0.4) #define PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_ (4) @@ -177,7 +180,7 @@ #define PA_MME_WIN_NT_DEFAULT_LATENCY_ (PA_MME_WIN_9X_DEFAULT_LATENCY_ * 2) #define PA_MME_WIN_WDM_DEFAULT_LATENCY_ (PA_MME_WIN_9X_DEFAULT_LATENCY_) - +#define PA_MME_MAX_TIMEOUT_MSEC_ (2000) #define PA_MME_MIN_TIMEOUT_MSEC_ (1000) static const char constInputMapperSuffix_[] = " - Input"; @@ -242,6 +245,9 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate ); +static PaError ScanDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index, void **newDeviceInfos, int *newDeviceCount ); +static PaError CommitDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index, void *deviceInfos, int deviceCount ); +static PaError DisposeDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, void *deviceInfos, int deviceCount ); static PaError CloseStream( PaStream* stream ); static PaError StartStream( PaStream *stream ); static PaError StopStream( PaStream *stream ); @@ -377,6 +383,92 @@ static PaError CloseHandleWithPaError( HANDLE handle ) return result; } +/** + * Sets the transportType of a specific PaDeviceInfo. + * + * @param winMmeDeviceId + * @param deviceInfo the PaDeviceInfo to set the transportType + * of + */ +static void +SetDeviceInfoTransportType(UINT winMmeDeviceId, PaDeviceInfo *deviceInfo) +{ + deviceInfo->transportType = NULL; + +#ifdef PAWIN_USE_WDMKS_DEVICE_INFO + if (!(deviceInfo->transportType)) + { + DWORD deviceInterfaceSize; + LPWSTR deviceInterface = NULL; + + if (deviceInfo->maxInputChannels > 0) + { + if (waveInMessage( + (HWAVEIN)winMmeDeviceId, + DRV_QUERYDEVICEINTERFACESIZE, + (DWORD_PTR)&deviceInterfaceSize, + 0) + == MMSYSERR_NOERROR) + { + deviceInterface = PaUtil_AllocateMemory(deviceInterfaceSize); + if (deviceInterface + && (waveInMessage( + (HWAVEIN)winMmeDeviceId, + DRV_QUERYDEVICEINTERFACE, + (DWORD_PTR)deviceInterface, + deviceInterfaceSize) + != MMSYSERR_NOERROR)) + { + PaUtil_FreeMemory(deviceInterface); + deviceInterface = NULL; + } + } + } + else if (deviceInfo->maxOutputChannels > 0) + { + if (waveOutMessage( + (HWAVEOUT)winMmeDeviceId, + DRV_QUERYDEVICEINTERFACESIZE, + (DWORD_PTR)&deviceInterfaceSize, + 0) + == MMSYSERR_NOERROR) + { + deviceInterface = PaUtil_AllocateMemory(deviceInterfaceSize); + if (deviceInterface + && (waveOutMessage( + (HWAVEOUT)winMmeDeviceId, + DRV_QUERYDEVICEINTERFACE, + (DWORD_PTR)deviceInterface, + deviceInterfaceSize) + != MMSYSERR_NOERROR)) + { + PaUtil_FreeMemory(deviceInterface); + deviceInterface = NULL; + } + } + } + if (deviceInterface) + { + if (wcsstr(deviceInterface, L"\\usb#") + || wcsstr(deviceInterface, L"\\USB#")) + deviceInfo->transportType = "USB"; + PaUtil_FreeMemory(deviceInterface); + } + } +#endif /* #ifdef PAWIN_USE_WDMKS_DEVICE_INFO */ + + /* + * As a last resort, attempt to make a decision about the transportType + * based on the name of the specified deviceInfo. + */ + if (!(deviceInfo->transportType)) + { + const char *s = deviceInfo->name; + + if (s && (s = strrchr(s,'(')) && (s = strstr(s,"USB")) && strchr(s,')')) + deviceInfo->transportType = "USB"; + } +} /* PaWinMmeHostApiRepresentation - host api datastructure specific to this implementation */ @@ -396,6 +488,8 @@ typedef struct device ids. */ UINT *winMmeDeviceIds; + + //char comWasInitialized; } PaWinMmeHostApiRepresentation; @@ -409,6 +503,14 @@ typedef struct } PaWinMmeDeviceInfo; +typedef struct PaWinMmeScanDeviceInfosResults{ /* used for tranferring device infos during scanning / rescanning */ + PaDeviceInfo **deviceInfos; + PaDeviceIndex defaultInputDevice; + PaDeviceIndex defaultOutputDevice; + + int inputDeviceCount, outputDeviceCount; + +} PaWinMmeScanDeviceInfosResults; /************************************************************************* * Returns recommended device ID. @@ -665,12 +767,19 @@ static PaError InitializeInputDeviceInfo( PaWinMmeHostApiRepresentation *winMmeH { PaError result = paNoError; char *deviceName; /* non-const ptr */ + char *deviceUID; MMRESULT mmresult; WAVEINCAPS wic; PaDeviceInfo *deviceInfo = &winMmeDeviceInfo->inheritedDeviceInfo; *success = 0; + /* We do not want Microsoft's Sound Mapper because it is a virtual device + * and we want the real (hardware) devices only. + */ + if (WAVE_MAPPER == winMmeInputDeviceId) + return paNoError; + mmresult = waveInGetDevCaps( winMmeInputDeviceId, &wic, sizeof( WAVEINCAPS ) ); if( mmresult == MMSYSERR_NOMEM ) { @@ -737,6 +846,51 @@ static PaError InitializeInputDeviceInfo( PaWinMmeHostApiRepresentation *winMmeH QueryWaveInKSFilterMaxChannels( winMmeInputDeviceId, &deviceInfo->maxInputChannels ); #endif /* PAWIN_USE_WDMKS_DEVICE_INFO */ + /* transportType */ + SetDeviceInfoTransportType(winMmeInputDeviceId, deviceInfo); + + MMRESULT mmr; + size_t cbEndpointIdSize; + // Get the size (including the terminating null) of + // the endpoint ID string of the waveOut device. + mmr = waveInMessage( + winMmeInputDeviceId, + DRV_QUERYFUNCTIONINSTANCEIDSIZE, + (DWORD_PTR)&cbEndpointIdSize, NULL); + + if (mmr == MMSYSERR_NOERROR) // do sizes match? + { + WCHAR *pstrEndpointId = NULL; + pstrEndpointId = (WCHAR *)PaUtil_GroupAllocateMemory(winMmeHostApi->allocations, cbEndpointIdSize); + + // Get the endpoint ID string for this waveOut device. + mmr = waveInMessage( + winMmeInputDeviceId, + DRV_QUERYFUNCTIONINSTANCEID, + (DWORD_PTR)pstrEndpointId, + cbEndpointIdSize); + + if (mmr == MMSYSERR_NOERROR) + { + deviceUID = (char *)PaUtil_GroupAllocateMemory(winMmeHostApi->allocations, wcslen(pstrEndpointId)); + if( !deviceUID ) + { + result = paInsufficientMemory; + goto error; + } + wcstombs(deviceUID, pstrEndpointId, sizeof(deviceUID)); + WideCharToMultiByte( CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,\ + pstrEndpointId, -1, deviceUID, wcslen(pstrEndpointId), NULL, NULL ); + deviceInfo->deviceUID = deviceUID; + } + /*else + { + char mmeErrorText[ MAXERRORLENGTH ]; + waveOutGetErrorText( mmr, mmeErrorText, MAXERRORLENGTH ); + PA_DEBUG(("Error %i: %s\n", mmr ,mmeErrorText)); + }*/ + } + winMmeDeviceInfo->dwFormats = wic.dwFormats; DetectDefaultSampleRate( winMmeDeviceInfo, winMmeInputDeviceId, @@ -788,6 +942,7 @@ static PaError InitializeOutputDeviceInfo( PaWinMmeHostApiRepresentation *winMme { PaError result = paNoError; char *deviceName; /* non-const ptr */ + char *deviceUID; MMRESULT mmresult; WAVEOUTCAPS woc; PaDeviceInfo *deviceInfo = &winMmeDeviceInfo->inheritedDeviceInfo; @@ -795,6 +950,12 @@ static PaError InitializeOutputDeviceInfo( PaWinMmeHostApiRepresentation *winMme *success = 0; + /* We do not want Microsoft's Sound Mapper because it is a virtual device + * and we want the real (hardware) devices only. + */ + if (WAVE_MAPPER == winMmeOutputDeviceId) + return paNoError; + mmresult = waveOutGetDevCaps( winMmeOutputDeviceId, &woc, sizeof( WAVEOUTCAPS ) ); if( mmresult == MMSYSERR_NOMEM ) { @@ -863,6 +1024,52 @@ static PaError InitializeOutputDeviceInfo( PaWinMmeHostApiRepresentation *winMme winMmeDeviceInfo->deviceOutputChannelCountIsKnown = 1; #endif /* PAWIN_USE_WDMKS_DEVICE_INFO */ + /* transportType */ + SetDeviceInfoTransportType(winMmeOutputDeviceId, deviceInfo); + + MMRESULT mmr; + size_t cbEndpointIdSize; + // Get the size (including the terminating null) of + // the endpoint ID string of the waveOut device. + mmr = waveOutMessage( + winMmeOutputDeviceId, + DRV_QUERYFUNCTIONINSTANCEIDSIZE, + (DWORD_PTR)&cbEndpointIdSize, NULL); + + if (mmr == MMSYSERR_NOERROR) // do sizes match? + { + WCHAR *pstrEndpointId = NULL; + pstrEndpointId = (WCHAR *)PaUtil_GroupAllocateMemory(winMmeHostApi->allocations, cbEndpointIdSize); + + // Get the endpoint ID string for this waveOut device. + mmr = waveOutMessage( + winMmeOutputDeviceId, + DRV_QUERYFUNCTIONINSTANCEID, + (DWORD_PTR)pstrEndpointId, + cbEndpointIdSize); + + if (mmr == MMSYSERR_NOERROR) + { + deviceUID = (char *)PaUtil_GroupAllocateMemory(winMmeHostApi->allocations, wcslen(pstrEndpointId)); + if( !deviceUID ) + { + result = paInsufficientMemory; + goto error; + } + wcstombs(deviceUID, pstrEndpointId, sizeof(deviceUID)); + + WideCharToMultiByte( CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,\ + pstrEndpointId, -1, deviceUID, wcslen(pstrEndpointId), NULL, NULL ); + deviceInfo->deviceUID = deviceUID; + } + /*else + { + char mmeErrorText[ MAXERRORLENGTH ]; + waveOutGetErrorText( mmr, mmeErrorText, MAXERRORLENGTH ); + PA_DEBUG(("Error %i: %s\n", mmr ,mmeErrorText)); + }*/ + } + winMmeDeviceInfo->dwFormats = woc.dwFormats; DetectDefaultSampleRate( winMmeDeviceInfo, winMmeOutputDeviceId, @@ -902,14 +1109,10 @@ static void GetDefaultLatencies( PaTime *defaultLowLatency, PaTime *defaultHighL PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) { PaError result = paNoError; - int i; + int deviceCount; PaWinMmeHostApiRepresentation *winMmeHostApi; - int inputDeviceCount, outputDeviceCount, maximumPossibleDeviceCount; - PaWinMmeDeviceInfo *deviceInfoArray; - int deviceInfoInitializationSucceeded; - PaTime defaultLowLatency, defaultHighLatency; - DWORD waveInPreferredDevice, waveOutPreferredDevice; - DWORD preferredDeviceStatusFlags; + //char comWasInitialized = 1; + void *scanResults = 0; winMmeHostApi = (PaWinMmeHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaWinMmeHostApiRepresentation) ); if( !winMmeHostApi ) @@ -918,6 +1121,8 @@ PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd goto error; } + //winMmeHostApi->comWasInitialized = comWasInitialized; + winMmeHostApi->allocations = PaUtil_CreateAllocationGroup(); if( !winMmeHostApi->allocations ) { @@ -930,163 +1135,32 @@ PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd (*hostApi)->info.type = paMME; (*hostApi)->info.name = "MME"; - /* initialise device counts and default devices under the assumption that there are no devices. These values are incremented below if and when devices are successfully initialized. */ + /* these are all updated by CommitDeviceInfos() */ (*hostApi)->info.deviceCount = 0; (*hostApi)->info.defaultInputDevice = paNoDevice; (*hostApi)->info.defaultOutputDevice = paNoDevice; winMmeHostApi->inputDeviceCount = 0; winMmeHostApi->outputDeviceCount = 0; -#if !defined(DRVM_MAPPER_PREFERRED_GET) -/* DRVM_MAPPER_PREFERRED_GET is defined in mmddk.h but we avoid a dependency on the DDK by defining it here */ -#define DRVM_MAPPER_PREFERRED_GET (0x2000+21) -#endif - - /* the following calls assume that if wave*Message fails the preferred device parameter won't be modified */ - preferredDeviceStatusFlags = 0; - waveInPreferredDevice = -1; - waveInMessage( (HWAVEIN)WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET, (DWORD_PTR)&waveInPreferredDevice, (DWORD_PTR)&preferredDeviceStatusFlags ); - - preferredDeviceStatusFlags = 0; - waveOutPreferredDevice = -1; - waveOutMessage( (HWAVEOUT)WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET, (DWORD_PTR)&waveOutPreferredDevice, (DWORD_PTR)&preferredDeviceStatusFlags ); - - maximumPossibleDeviceCount = 0; - - inputDeviceCount = waveInGetNumDevs(); - if( inputDeviceCount > 0 ) - maximumPossibleDeviceCount += inputDeviceCount + 1; /* assume there is a WAVE_MAPPER */ - - outputDeviceCount = waveOutGetNumDevs(); - if( outputDeviceCount > 0 ) - maximumPossibleDeviceCount += outputDeviceCount + 1; /* assume there is a WAVE_MAPPER */ - - - if( maximumPossibleDeviceCount > 0 ){ - - (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( - winMmeHostApi->allocations, sizeof(PaDeviceInfo*) * maximumPossibleDeviceCount ); - if( !(*hostApi)->deviceInfos ) - { - result = paInsufficientMemory; - goto error; - } - - /* allocate all device info structs in a contiguous block */ - deviceInfoArray = (PaWinMmeDeviceInfo*)PaUtil_GroupAllocateMemory( - winMmeHostApi->allocations, sizeof(PaWinMmeDeviceInfo) * maximumPossibleDeviceCount ); - if( !deviceInfoArray ) - { - result = paInsufficientMemory; - goto error; - } - - winMmeHostApi->winMmeDeviceIds = (UINT*)PaUtil_GroupAllocateMemory( - winMmeHostApi->allocations, sizeof(int) * maximumPossibleDeviceCount ); - if( !winMmeHostApi->winMmeDeviceIds ) - { - result = paInsufficientMemory; - goto error; - } - - GetDefaultLatencies( &defaultLowLatency, &defaultHighLatency ); - - if( inputDeviceCount > 0 ){ - /* -1 is the WAVE_MAPPER */ - for( i = -1; i < inputDeviceCount; ++i ){ - UINT winMmeDeviceId = (UINT)((i==-1) ? WAVE_MAPPER : i); - PaWinMmeDeviceInfo *wmmeDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ]; - PaDeviceInfo *deviceInfo = &wmmeDeviceInfo->inheritedDeviceInfo; - deviceInfo->structVersion = 2; - deviceInfo->hostApi = hostApiIndex; - - deviceInfo->maxInputChannels = 0; - wmmeDeviceInfo->deviceInputChannelCountIsKnown = 1; - deviceInfo->maxOutputChannels = 0; - wmmeDeviceInfo->deviceOutputChannelCountIsKnown = 1; - - deviceInfo->defaultLowInputLatency = defaultLowLatency; - deviceInfo->defaultLowOutputLatency = defaultLowLatency; - deviceInfo->defaultHighInputLatency = defaultHighLatency; - deviceInfo->defaultHighOutputLatency = defaultHighLatency; - - result = InitializeInputDeviceInfo( winMmeHostApi, wmmeDeviceInfo, - winMmeDeviceId, &deviceInfoInitializationSucceeded ); - if( result != paNoError ) - goto error; - - if( deviceInfoInitializationSucceeded ){ - if( (*hostApi)->info.defaultInputDevice == paNoDevice ){ - /* if there is currently no default device, use the first one available */ - (*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount; - - }else if( winMmeDeviceId == waveInPreferredDevice ){ - /* set the default device to the system preferred device */ - (*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount; - } - - winMmeHostApi->winMmeDeviceIds[ (*hostApi)->info.deviceCount ] = winMmeDeviceId; - (*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo; - - winMmeHostApi->inputDeviceCount++; - (*hostApi)->info.deviceCount++; - } - } - } - - if( outputDeviceCount > 0 ){ - /* -1 is the WAVE_MAPPER */ - for( i = -1; i < outputDeviceCount; ++i ){ - UINT winMmeDeviceId = (UINT)((i==-1) ? WAVE_MAPPER : i); - PaWinMmeDeviceInfo *wmmeDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ]; - PaDeviceInfo *deviceInfo = &wmmeDeviceInfo->inheritedDeviceInfo; - deviceInfo->structVersion = 2; - deviceInfo->hostApi = hostApiIndex; - - deviceInfo->maxInputChannels = 0; - wmmeDeviceInfo->deviceInputChannelCountIsKnown = 1; - deviceInfo->maxOutputChannels = 0; - wmmeDeviceInfo->deviceOutputChannelCountIsKnown = 1; - - deviceInfo->defaultLowInputLatency = defaultLowLatency; - deviceInfo->defaultLowOutputLatency = defaultLowLatency; - deviceInfo->defaultHighInputLatency = defaultHighLatency; - deviceInfo->defaultHighOutputLatency = defaultHighLatency; - - result = InitializeOutputDeviceInfo( winMmeHostApi, wmmeDeviceInfo, - winMmeDeviceId, &deviceInfoInitializationSucceeded ); - if( result != paNoError ) - goto error; - - if( deviceInfoInitializationSucceeded ){ - if( (*hostApi)->info.defaultOutputDevice == paNoDevice ){ - /* if there is currently no default device, use the first one available */ - (*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount; - - }else if( winMmeDeviceId == waveOutPreferredDevice ){ - /* set the default device to the system preferred device */ - (*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount; - } - - winMmeHostApi->winMmeDeviceIds[ (*hostApi)->info.deviceCount ] = winMmeDeviceId; - (*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo; - - winMmeHostApi->outputDeviceCount++; - (*hostApi)->info.deviceCount++; - } - } - } + result = ScanDeviceInfos( &winMmeHostApi->inheritedHostApiRep, hostApiIndex, &scanResults, &deviceCount ); + if( result != paNoError ) + { + goto error; } - - InitializeDefaultDeviceIdsFromEnv( winMmeHostApi ); + + /* FIXME for now we ignore the result of CommitDeviceInfos(), it should probably be an atomic non-failing operation */ + CommitDeviceInfos( &winMmeHostApi->inheritedHostApiRep, hostApiIndex, scanResults, deviceCount ); (*hostApi)->Terminate = Terminate; (*hostApi)->OpenStream = OpenStream; (*hostApi)->IsFormatSupported = IsFormatSupported; + (*hostApi)->ScanDeviceInfos = ScanDeviceInfos; + (*hostApi)->CommitDeviceInfos = CommitDeviceInfos; + (*hostApi)->DisposeDeviceInfos = DisposeDeviceInfos; PaUtil_InitializeStreamInterface( &winMmeHostApi->callbackStreamInterface, CloseStream, StartStream, StopStream, AbortStream, IsStreamStopped, IsStreamActive, @@ -1283,7 +1357,7 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, if( paerror != paNoError ) return paInvalidSampleRate; } - + if( outputMultipleDeviceChannelCount != outputChannelCount ) return paIncompatibleHostApiSpecificStreamInfo; } @@ -1323,7 +1397,298 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, return paFormatIsSupported; } +/***********************************************************************************/ +static PaError ScanDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex hostApiIndex, void **scanResults, int *newDeviceCount ) +{ + PaWinMmeHostApiRepresentation *winMmeHostApi = (PaWinMmeHostApiRepresentation*)hostApi; + PaWinMmeDeviceInfo *deviceInfoArray; + //char comWasInitialized = winMmeHostApi->comWasInitialized; + PaError result = paNoError; + PaWinMmeScanDeviceInfosResults *outArgument = 0; + //DSDeviceNamesAndGUIDs deviceNamesAndGUIDs; + int i = 0; + int maximumPossibleDeviceCount = 0; + int inputDeviceCount, outputDeviceCount; + int deviceInfoInitializationSucceeded; + PaTime defaultLowLatency, defaultHighLatency; + + DWORD waveInPreferredDevice, waveOutPreferredDevice; + DWORD preferredDeviceStatusFlags; + + // Check preconditions + if( /*!comWasInitialized ||*/ scanResults == NULL || newDeviceCount == NULL ) + return paInternalError; + + /* initialize the out params */ + *scanResults = NULL; + *newDeviceCount = 0; + +#if !defined(DRVM_MAPPER_PREFERRED_GET) +/* DRVM_MAPPER_PREFERRED_GET is defined in mmddk.h but we avoid a dependency on the DDK by defining it here */ +#define DRVM_MAPPER_PREFERRED_GET (0x2000+21) +#endif + + /* the following calls assume that if wave*Message fails the preferred device parameter won't be modified */ + preferredDeviceStatusFlags = 0; + waveInPreferredDevice = -1; + waveInMessage( (HWAVEIN)WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET, (DWORD_PTR)&waveInPreferredDevice, (DWORD_PTR)&preferredDeviceStatusFlags ); + + preferredDeviceStatusFlags = 0; + waveOutPreferredDevice = -1; + waveOutMessage( (HWAVEOUT)WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET, (DWORD_PTR)&waveOutPreferredDevice, (DWORD_PTR)&preferredDeviceStatusFlags ); + + maximumPossibleDeviceCount = 0; + + inputDeviceCount = waveInGetNumDevs(); + if( inputDeviceCount > 0 ) + maximumPossibleDeviceCount += inputDeviceCount + 1; // assume there is a WAVE_MAPPER + + outputDeviceCount = waveOutGetNumDevs(); + if( outputDeviceCount > 0 ) + maximumPossibleDeviceCount += outputDeviceCount + 1;// assume there is a WAVE_MAPPER + + if( maximumPossibleDeviceCount > 0 ) + { + /* Allocate the out param for all the info we need */ + outArgument = (PaWinMmeScanDeviceInfosResults *) PaUtil_GroupAllocateMemory( + winMmeHostApi->allocations, sizeof(PaWinMmeScanDeviceInfosResults) ); + if( !outArgument ) + { + result = paInsufficientMemory; + goto error; + } + + /* allocate array for pointers to PaDeviceInfo structs */ + outArgument->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( + winMmeHostApi->allocations, sizeof(PaDeviceInfo*) * maximumPossibleDeviceCount ); + if( !outArgument->deviceInfos ) + { + result = paInsufficientMemory; + goto error; + } + + // allocate all device info structs in a contiguous block + deviceInfoArray = (PaWinMmeDeviceInfo*)PaUtil_GroupAllocateMemory( + winMmeHostApi->allocations, sizeof(PaWinMmeDeviceInfo) * maximumPossibleDeviceCount ); + if( !deviceInfoArray ) + { + result = paInsufficientMemory; + goto error; + } + + winMmeHostApi->winMmeDeviceIds = (UINT*)PaUtil_GroupAllocateMemory( + winMmeHostApi->allocations, sizeof(int) * maximumPossibleDeviceCount ); + if( !winMmeHostApi->winMmeDeviceIds ) + { + result = paInsufficientMemory; + goto error; + } + + for( i = 0 ; i < maximumPossibleDeviceCount; ++i ) + { + PaWinMmeDeviceInfo *wmmeDeviceInfo = &deviceInfoArray[i]; + PaDeviceInfo *deviceInfo = &wmmeDeviceInfo->inheritedDeviceInfo; + + deviceInfo->structVersion = 3; + deviceInfo->hostApi = hostApiIndex; + deviceInfo->name = 0; + /* + * The fields maxInputChannels and maxOutputChannels used to be + * initialized in each of the loops bellow to the effect of the + * second loop overwriting/throwing away the results of the first + * loop. In order to resolve the described issue, the initialization + * of the two fields in question has been moved here. + */ + deviceInfo->maxInputChannels = 0; + deviceInfo->maxOutputChannels = 0; + /* + * The fields defaultLowInputLatency, defaultLowOutputLatency, + * defaultHighInputLatency and defaultHighOutputLatency used to be + * initialized in each of the loops bellow. For the sake of clarity, + * their initialization has been moved here. + */ + deviceInfo->defaultLowInputLatency = defaultLowLatency; + deviceInfo->defaultLowOutputLatency = defaultLowLatency; + deviceInfo->defaultHighInputLatency = defaultHighLatency; + deviceInfo->defaultHighOutputLatency = defaultHighLatency; + + /* + * The fields deviceInputChannelCountIsKnown and + * deviceOutputChannelCountIsKnown used to be initialized in each of + * the loops bellow to the effect of the second loop + * overwriting/throwing away the results of the first loop. In order + * to resolve the described issue, the initialization of the two + * fields in question has been moved here. + */ + wmmeDeviceInfo->deviceInputChannelCountIsKnown = 0; + wmmeDeviceInfo->deviceOutputChannelCountIsKnown = 0; + + outArgument->deviceInfos[ i ] = deviceInfo; + } + outArgument->inputDeviceCount = 0; + outArgument->outputDeviceCount = 0; + + GetDefaultLatencies( &defaultLowLatency, &defaultHighLatency ); + + if( inputDeviceCount > 0 ) + { + // -1 is the WAVE_MAPPER + for( i = -1; i < inputDeviceCount; ++i ) + { + UINT winMmeDeviceId = (UINT)((i==-1) ? WAVE_MAPPER : i); + PaWinMmeDeviceInfo *wmmeDeviceInfo = (PaWinMmeDeviceInfo*)outArgument->deviceInfos[*newDeviceCount]; + PaDeviceInfo *deviceInfo = &wmmeDeviceInfo->inheritedDeviceInfo; + + result = InitializeInputDeviceInfo( winMmeHostApi, wmmeDeviceInfo, + winMmeDeviceId, &deviceInfoInitializationSucceeded ); + /* ignore error results here and just skip the device */ + if( result != paNoError ) + continue; + + if( deviceInfoInitializationSucceeded ) + { + if( outArgument->defaultInputDevice == paNoDevice ) + { + // if there is currently no default device, use the first one available + outArgument->defaultInputDevice = *newDeviceCount; + + } + else if( winMmeDeviceId == waveInPreferredDevice ) + { + // set the default device to the system preferred device + outArgument->defaultInputDevice = *newDeviceCount; + } + + winMmeHostApi->winMmeDeviceIds[ *newDeviceCount ] = winMmeDeviceId; + outArgument->inputDeviceCount++; + (*newDeviceCount)++; + } + } + } + + if( outputDeviceCount > 0 ) + { + // -1 is the WAVE_MAPPER + for( i = -1; i < outputDeviceCount; ++i ) + { + UINT winMmeDeviceId = (UINT)((i==-1) ? WAVE_MAPPER : i); + PaWinMmeDeviceInfo *wmmeDeviceInfo = (PaWinMmeDeviceInfo*)outArgument->deviceInfos[*newDeviceCount]; + PaDeviceInfo *deviceInfo = &wmmeDeviceInfo->inheritedDeviceInfo; + + result = InitializeOutputDeviceInfo( winMmeHostApi, wmmeDeviceInfo, + winMmeDeviceId, &deviceInfoInitializationSucceeded ); + /* ignore error results here and just skip the device */ + if( result != paNoError ) + continue; + + if( deviceInfoInitializationSucceeded ) + { + if( outArgument->defaultOutputDevice == paNoDevice ) + { + // if there is currently no default device, use the first one available + outArgument->defaultOutputDevice = *newDeviceCount; + + } + else if( winMmeDeviceId == waveOutPreferredDevice ) + { + // set the default device to the system preferred device + outArgument->defaultOutputDevice = *newDeviceCount; + } + + winMmeHostApi->winMmeDeviceIds[ *newDeviceCount ] = winMmeDeviceId; + outArgument->outputDeviceCount++; + (*newDeviceCount)++; + } + } + } + } + + InitializeDefaultDeviceIdsFromEnv( winMmeHostApi ); + *scanResults = outArgument; + + return result; +error: + + if( outArgument ) + { + if( outArgument->deviceInfos ) + { + if( outArgument->deviceInfos[0] ) + { + PaUtil_GroupFreeMemory( winMmeHostApi->allocations, outArgument->deviceInfos[0] ); + } + + PaUtil_GroupFreeMemory( winMmeHostApi->allocations, outArgument->deviceInfos ); + } + } + + return result; +} + +static PaError CommitDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaHostApiIndex index, void *scanResults, int deviceCount ) +{ + PaWinMmeHostApiRepresentation *winMmeHostApi = (PaWinMmeHostApiRepresentation*)hostApi; + PaError result = paNoError; + int i = 0; + + hostApi->info.deviceCount = 0; + hostApi->info.defaultInputDevice = paNoDevice; + hostApi->info.defaultOutputDevice = paNoDevice; + + /* Free any old memory which might be in the device info */ + if( hostApi->deviceInfos ) + { + PaUtil_GroupFreeMemory( winMmeHostApi->allocations, hostApi->deviceInfos[0] ); + PaUtil_GroupFreeMemory( winMmeHostApi->allocations, hostApi->deviceInfos ); + hostApi->deviceInfos = NULL; + } + + if( scanResults != NULL ) + { + PaWinMmeScanDeviceInfosResults *scanDeviceInfosResults = ( PaWinMmeScanDeviceInfosResults * ) scanResults; + + if( deviceCount > 0 ) + { + // use the array allocated in ScanDeviceInfos() as our deviceInfos + hostApi->deviceInfos = scanDeviceInfosResults->deviceInfos; + + hostApi->info.defaultInputDevice = scanDeviceInfosResults->defaultInputDevice; + hostApi->info.defaultOutputDevice = scanDeviceInfosResults->defaultOutputDevice; + + hostApi->info.deviceCount = deviceCount; + + winMmeHostApi->inputDeviceCount = scanDeviceInfosResults->inputDeviceCount; + winMmeHostApi->outputDeviceCount = scanDeviceInfosResults->outputDeviceCount; + } + + PaUtil_GroupFreeMemory( winMmeHostApi->allocations, scanDeviceInfosResults ); + } + + return result; +} + +static PaError DisposeDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, void *scanResults, int deviceCount ) +{ + PaWinMmeHostApiRepresentation *winMmeHostApi = (PaWinMmeHostApiRepresentation*)hostApi; + + if( scanResults != NULL ) + { + PaWinMmeScanDeviceInfosResults *scanDeviceInfosResults = ( PaWinMmeScanDeviceInfosResults * ) scanResults; + + if( scanDeviceInfosResults->deviceInfos ) + { + PaUtil_GroupFreeMemory( winMmeHostApi->allocations, scanDeviceInfosResults->deviceInfos[0] ); // all device info structs are allocated in a block so we can destroy them here + PaUtil_GroupFreeMemory( winMmeHostApi->allocations, scanDeviceInfosResults->deviceInfos ); + } + + PaUtil_GroupFreeMemory( winMmeHostApi->allocations, scanDeviceInfosResults ); + } + + return paNoError; +} + +/***********************************************************************************/ static void SelectBufferSizeAndCount( unsigned long baseBufferSize, unsigned long requestedLatency, @@ -1805,18 +2170,18 @@ static PaError InitializeWaveHandles( PaWinMmeHostApiRepresentation *winMmeHostA { switch(j){ case 0: - /* first, attempt to open the device using WAVEFORMATEXTENSIBLE, - if this fails we fall back to WAVEFORMATEX */ + /* first, attempt to open the device using WAVEFORMATEXTENSIBLE, + if this fails we fall back to WAVEFORMATEX */ - PaWin_InitializeWaveFormatExtensible( &waveFormat, devices[i].channelCount, - sampleFormat, waveFormatTag, sampleRate, channelMask ); + PaWin_InitializeWaveFormatExtensible( &waveFormat, devices[i].channelCount, + sampleFormat, waveFormatTag, sampleRate, channelMask ); break; - - case 1: - /* retry with WAVEFORMATEX */ - PaWin_InitializeWaveFormatEx( &waveFormat, devices[i].channelCount, - sampleFormat, waveFormatTag, sampleRate ); + case 1: + /* retry with WAVEFORMATEX */ + + PaWin_InitializeWaveFormatEx( &waveFormat, devices[i].channelCount, + sampleFormat, waveFormatTag, sampleRate ); break; } @@ -3391,7 +3756,7 @@ static PaError StopStream( PaStream *s ) { PaError result = paNoError; PaWinMmeStream *stream = (PaWinMmeStream*)s; - int timeout; + DWORD timeout; DWORD waitResult; MMRESULT mmresult; signed int hostOutputBufferIndex; @@ -3412,7 +3777,7 @@ static PaError StopStream( PaStream *s ) stream->stopProcessing = 1; /* Calculate timeOut longer than longest time it could take to return all buffers. */ - timeout = (int)(stream->allBuffersDurationMs * 1.5); + timeout = (DWORD)(stream->allBuffersDurationMs * 1.5); if( timeout < PA_MME_MIN_TIMEOUT_MSEC_ ) timeout = PA_MME_MIN_TIMEOUT_MSEC_; @@ -3441,6 +3806,12 @@ static PaError StopStream( PaStream *s ) if( PA_IS_OUTPUT_STREAM_(stream) ) { + /* If WaitForSingleObject starts repetitively and consecutively + returning WAIT_TIMEOUT, do eventually give up. Otherwise, the + method may never return. + */ + DWORD totalTimeout; + if( stream->output.framesUsedInCurrentBuffer > 0 ) { /* there are still unqueued frames in the current buffer, so flush them */ @@ -3481,6 +3852,7 @@ static PaError StopStream( PaStream *s ) timeout = PA_MME_MIN_TIMEOUT_MSEC_; waitCount = 0; + totalTimeout = 0; while( !NoBuffersAreQueued( &stream->output ) && waitCount <= stream->output.bufferCount ) { /* wait for MME to signal that a buffer is available */ @@ -3491,8 +3863,19 @@ static PaError StopStream( PaStream *s ) } else if( waitResult == WAIT_TIMEOUT ) { - /* keep waiting */ + /* Keep waiting. However, testing has shown that it is + possible to unplug a device and to wait here forever. In + order to prevent such a scenario, do eventually given up. + */ + totalTimeout += timeout; + if( PA_MME_MAX_TIMEOUT_MSEC_ <= totalTimeout) + { + result = paTimedOut; + break; + } } + else + totalTimeout = 0; ++waitCount; } @@ -3668,6 +4051,12 @@ static PaError ReadStream( PaStream* s, if( PA_IS_INPUT_STREAM_(stream) ) { + /* If WaitForSingleObject starts repetitively and consecutively + returning WAIT_TIMEOUT, do eventually give up in order to allow the + caller to handle such cases. + */ + DWORD totalTimeout = 0; + /* make a local copy of the user buffer pointer(s). this is necessary because PaUtil_CopyInput() advances these pointers every time it is called. @@ -3688,6 +4077,8 @@ static PaError ReadStream( PaStream* s, do{ if( CurrentInputBuffersAreDone( stream ) ) { + totalTimeout = 0; + if( NoBuffersAreQueued( &stream->input ) ) { /** @todo REVIEW: consider what to do if the input overflows. @@ -3741,9 +4132,17 @@ static PaError ReadStream( PaStream* s, } else if( waitResult == WAIT_TIMEOUT ) { - /* if a timeout is encountered, continue, - perhaps we should give up eventually + /* If a timeout is encountered, continue. However, testing + has shown that it is possible to unplug a device and to + wait here forever. In order to allow the caller to handle + such cases of repeated timeouts, do eventually given up. */ + totalTimeout += timeout; + if( PA_MME_MAX_TIMEOUT_MSEC_ <= totalTimeout) + { + result = paTimedOut; + break; + } } } }while( framesRead < frames ); @@ -3774,6 +4173,12 @@ static PaError WriteStream( PaStream* s, if( PA_IS_OUTPUT_STREAM_(stream) ) { + /* If WaitForSingleObject starts repetitively and consecutively + returning WAIT_TIMEOUT, do eventually give up in order to allow the + caller to handle such cases. + */ + DWORD totalTimeout = 0; + /* make a local copy of the user buffer pointer(s). this is necessary because PaUtil_CopyOutput() advances these pointers every time it is called. @@ -3794,6 +4199,8 @@ static PaError WriteStream( PaStream* s, do{ if( CurrentOutputBuffersAreDone( stream ) ) { + totalTimeout = 0; + if( NoBuffersAreQueued( &stream->output ) ) { /** @todo REVIEW: consider what to do if the output @@ -3849,9 +4256,17 @@ static PaError WriteStream( PaStream* s, } else if( waitResult == WAIT_TIMEOUT ) { - /* if a timeout is encountered, continue, - perhaps we should give up eventually + /* If a timeout is encountered, continue. However, testing + has shown that it is possible to unplug a device and to + wait here forever. In order to allow the caller to handle + such cases of repeated timeouts, do eventually given up. */ + totalTimeout += timeout; + if( PA_MME_MAX_TIMEOUT_MSEC_ <= totalTimeout) + { + result = paTimedOut; + break; + } } } }while( framesWritten < frames ); diff --git a/src/os/mac_osx/pa_osx_hotplug.c b/src/os/mac_osx/pa_osx_hotplug.c new file mode 100644 index 0000000..22e7471 --- /dev/null +++ b/src/os/mac_osx/pa_osx_hotplug.c @@ -0,0 +1,76 @@ + +#include "pa_util.h" +#include "pa_debugprint.h" +#include "pa_allocation.h" + +#include + +#include +#include + +/* Implemented in pa_front.c + @param first 0 = unknown, 1 = insertion, 2 = removal + @param second Host specific device change info (in windows it is the (unicode) device path) +*/ +extern void PaUtil_DevicesChanged(unsigned, void*); + +/* Callback for audio hardware property changes. */ +static OSStatus audioPropertyCallback(AudioHardwarePropertyID inPropertyID, + void *refCon) +{ + (void)refCon; + switch (inPropertyID) + { + /* + * These are the other types of notifications we might receive, however, they are beyond + * the scope of this sample and we ignore them. + */ + case kAudioHardwarePropertyDefaultInputDevice: + PA_DEBUG(("audioPropertyCallback: default input device changed\n")); + break; + case kAudioHardwarePropertyDefaultOutputDevice: + PA_DEBUG(("audioPropertyCallback: default output device changed\n")); + break; + case kAudioHardwarePropertyDefaultSystemOutputDevice: + PA_DEBUG(("audioPropertyCallback: default system output device changed\n")); + break; + case kAudioHardwarePropertyDevices: + PA_DEBUG(("audioPropertyCallback: device list changed\n")); + PaUtil_DevicesChanged(1, NULL); + break; + default: + PA_DEBUG(("audioPropertyCallback: unknown message id=%08lx\n", inPropertyID)); + break; + } + + return noErr; +} + +void PaUtil_InitializeHotPlug() +{ + AudioHardwareAddPropertyListener(kAudioHardwarePropertyDevices, + audioPropertyCallback, NULL); + AudioHardwareAddPropertyListener(kAudioHardwarePropertyDefaultInputDevice, + audioPropertyCallback, NULL); + AudioHardwareAddPropertyListener(kAudioHardwarePropertyDefaultOutputDevice, + audioPropertyCallback, NULL); +} + +void PaUtil_TerminateHotPlug() +{ + AudioHardwareRemovePropertyListener(kAudioHardwarePropertyDevices, + audioPropertyCallback); + AudioHardwareRemovePropertyListener(kAudioHardwarePropertyDefaultInputDevice, + audioPropertyCallback); + AudioHardwareRemovePropertyListener(kAudioHardwarePropertyDefaultOutputDevice, + audioPropertyCallback); +} + +void PaUtil_LockHotPlug() +{ +} + +void PaUtil_UnlockHotPlug() +{ +} + diff --git a/src/os/unix/pa_linux_hotplug.c b/src/os/unix/pa_linux_hotplug.c new file mode 100644 index 0000000..ba6eb19 --- /dev/null +++ b/src/os/unix/pa_linux_hotplug.c @@ -0,0 +1,147 @@ + +#include "pa_util.h" +#include "pa_debugprint.h" +#include "pa_allocation.h" +#include "pa_linux_alsa.h" +#include "pa_hostapi.h" + +#include + +#include +#include +#include + +/* Implemented in pa_front.c + @param first 0 = unknown, 1 = insertion, 2 = removal + @param second Host specific device change info (in windows it is the (unicode) device path) +*/ +extern void PaUtil_DevicesChanged(unsigned, void*); + +static pthread_t g_thread_id; +static pthread_mutex_t g_mutex; +static volatile sig_atomic_t g_run = 0; + +static int device_list_size(void) +{ + snd_ctl_t *handle; + int card, err, dev, idx; + int nb = 0; + snd_ctl_card_info_t *info; + snd_pcm_info_t *pcminfo; + snd_ctl_card_info_alloca(&info); + snd_pcm_info_alloca(&pcminfo); + + card = -1; + if (snd_card_next(&card) < 0 || card < 0) + { + return nb; + } + + while (card >= 0) + { + char name[32]; + + sprintf(name, "hw:%d", card); + if ((err = snd_ctl_open(&handle, name, 0)) < 0) + { + goto next_card; + } + if ((err = snd_ctl_card_info(handle, info)) < 0) + { + snd_ctl_close(handle); + goto next_card; + } + dev = -1; + while (1) + { + unsigned int count; + int hasPlayback = 0; + int hasCapture = 0; + + snd_ctl_pcm_next_device(handle, &dev); + + if (dev < 0) + break; + snd_pcm_info_set_device(pcminfo, dev); + snd_pcm_info_set_subdevice(pcminfo, 0); + snd_pcm_info_set_stream(pcminfo, SND_PCM_STREAM_CAPTURE); + if ((err = snd_ctl_pcm_info(handle, pcminfo)) >= 0) + { + hasCapture = 1; + } + + snd_pcm_info_set_stream(pcminfo, SND_PCM_STREAM_PLAYBACK); + if ((err = snd_ctl_pcm_info(handle, pcminfo)) >= 0) + { + hasPlayback = 1; + + count = snd_pcm_info_get_subdevices_count(pcminfo); + } + + if(hasPlayback == 0 && hasCapture == 0) + continue; + + nb++; + } + snd_ctl_close(handle); +next_card: + if (snd_card_next(&card) < 0) + { + break; + } + } + return nb; +} + +static void* thread_fcn(void* data) +{ + int currentDevices = 0; + + currentDevices = device_list_size(); + + while(g_run) + { + int count = 0; + + sleep(1); + count = device_list_size(); + if(count != currentDevices) + { + /* 1 = add device, 2 = remove device */ + int add = (count > currentDevices) ? 1 : 2; + + currentDevices = count; + + PaUtil_DevicesChanged(add, NULL); + } + } + + return NULL; +} + +void PaUtil_InitializeHotPlug() +{ + pthread_mutex_init(&g_mutex, NULL); + g_run = 1; + pthread_create(&g_thread_id, NULL, thread_fcn, NULL); +} + +void PaUtil_TerminateHotPlug() +{ + void* ret = NULL; + + g_run = 0; + pthread_join(g_thread_id, &ret); + pthread_mutex_destroy(&g_mutex); +} + +void PaUtil_LockHotPlug() +{ + pthread_mutex_lock(&g_mutex); +} + +void PaUtil_UnlockHotPlug() +{ + pthread_mutex_unlock(&g_mutex); +} + diff --git a/src/os/win/pa_win_hostapis.c b/src/os/win/pa_win_hostapis.c index 7db5503..b1c6cbf 100644 --- a/src/os/win/pa_win_hostapis.c +++ b/src/os/win/pa_win_hostapis.c @@ -1,5 +1,5 @@ /* - * $Id$ + * $Id: pa_win_hostapis.c 1661 2011-04-28 18:54:46Z rob_bielik $ * Portable Audio I/O Library Windows initialization table * * Based on the Open Source API proposed by Ross Bencina @@ -81,7 +81,7 @@ PaUtilHostApiInitializer *paHostApiInitializers[] = #endif #if PA_USE_WDMKS - PaWinWdm_Initialize, + //PaWinWdm_Initialize, #endif #if PA_USE_SKELETON diff --git a/src/os/win/pa_win_hotplug.c b/src/os/win/pa_win_hotplug.c new file mode 100644 index 0000000..f259583 --- /dev/null +++ b/src/os/win/pa_win_hotplug.c @@ -0,0 +1,318 @@ + +#include "pa_util.h" +#include "pa_debugprint.h" +#include "pa_allocation.h" + +#include "pa_win_wdmks_utils.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) /* MSC version 6 and above */ +#pragma comment( lib, "setupapi.lib" ) +#endif + + +/* Implemented in pa_front.c + @param first 0 = unknown, 1 = insertion, 2 = removal + @param second Host specific device change info (in windows it is the (unicode) device path) +*/ +extern void PaUtil_DevicesChanged(unsigned, void*); + +/* use CreateThread for CYGWIN/Windows Mobile, _beginthreadex for all others */ +#if !defined(__CYGWIN__) && !defined(_WIN32_WCE) +#define CREATE_THREAD_FUNCTION (HANDLE)_beginthreadex +#define PA_THREAD_FUNC static unsigned WINAPI +#else +#define CREATE_THREAD_FUNCTION CreateThread +#define PA_THREAD_FUNC static DWORD WINAPI +#endif + +typedef struct PaHotPlugDeviceInfo +{ + wchar_t name[MAX_PATH]; + struct PaHotPlugDeviceInfo* next; +} PaHotPlugDeviceInfo; + +typedef struct PaHotPlugDeviceEventHandlerInfo +{ + HANDLE hWnd; + HANDLE hMsgThread; + HANDLE hNotify; + CRITICAL_SECTION lock; + PaUtilAllocationGroup* cacheAllocGroup; + PaHotPlugDeviceInfo* cache; + +} PaHotPlugDeviceEventHandlerInfo; + + +static BOOL RemoveDeviceFromCache(PaHotPlugDeviceEventHandlerInfo* pInfo, const wchar_t* name) +{ + if (pInfo->cache != NULL) + { + PaHotPlugDeviceInfo* lastEntry = 0; + PaHotPlugDeviceInfo* entry = pInfo->cache; + while (entry != NULL) + { + if (_wcsicmp(entry->name, name) == 0) + { + if (lastEntry) + { + lastEntry->next = entry->next; + } + else + { + pInfo->cache = NULL; + } + PaUtil_GroupFreeMemory(pInfo->cacheAllocGroup, entry); + return TRUE; + } + + lastEntry = entry; + entry = entry->next; + } + } + return FALSE; +} + +static void InsertDeviceIntoCache(PaHotPlugDeviceEventHandlerInfo* pInfo, const wchar_t* name) +{ + PaHotPlugDeviceInfo** ppEntry = NULL; + + /* Remove it first (if possible) so we don't accidentally get duplicates */ + RemoveDeviceFromCache(pInfo, name); + + if (pInfo->cache == NULL) + { + ppEntry = &pInfo->cache; + } + else + { + PaHotPlugDeviceInfo* entry = pInfo->cache; + while (entry->next != NULL) + { + entry = entry->next; + } + ppEntry = &entry->next; + } + + *ppEntry = (PaHotPlugDeviceInfo*)PaUtil_GroupAllocateMemory(pInfo->cacheAllocGroup, sizeof(PaHotPlugDeviceInfo)); + wcsncpy((*ppEntry)->name, name, MAX_PATH-1); + (*ppEntry)->next = NULL; +} + +static BOOL IsDeviceAudio(const wchar_t* deviceName) +{ + int channelCnt = 0; + channelCnt += PaWin_WDMKS_QueryFilterMaximumChannelCount((void*)deviceName, 1); + channelCnt += PaWin_WDMKS_QueryFilterMaximumChannelCount((void*)deviceName, 0); + return (channelCnt > 0); +} + +static void PopulateCacheWithAvailableAudioDevices(PaHotPlugDeviceEventHandlerInfo* pInfo) +{ + HDEVINFO handle = NULL; + const int sizeInterface = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + (MAX_PATH * sizeof(WCHAR)); + SP_DEVICE_INTERFACE_DETAIL_DATA_W* devInterfaceDetails = (SP_DEVICE_INTERFACE_DETAIL_DATA_W*)PaUtil_AllocateMemory(sizeInterface); + + if (devInterfaceDetails) + { + devInterfaceDetails->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W); + + /* Open a handle to search for devices (filters) */ + handle = SetupDiGetClassDevsW(&KSCATEGORY_AUDIO,NULL,NULL,DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + if( handle != NULL ) + { + int device; + + /* Iterate through the devices */ + for( device = 0;;device++ ) + { + SP_DEVICE_INTERFACE_DATA interfaceData; + SP_DEVINFO_DATA devInfoData; + int noError; + + interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + interfaceData.Reserved = 0; + devInfoData.cbSize = sizeof(SP_DEVINFO_DATA); + devInfoData.Reserved = 0; + + noError = SetupDiEnumDeviceInterfaces(handle,NULL,&KSCATEGORY_AUDIO,device,&interfaceData); + if( !noError ) + break; /* No more devices */ + + noError = SetupDiGetDeviceInterfaceDetailW(handle,&interfaceData,devInterfaceDetails,sizeInterface,NULL,&devInfoData); + if( noError ) + { + if (IsDeviceAudio(devInterfaceDetails->DevicePath)) + { + PA_DEBUG(("Hotplug cache populated with: '%S'\n", devInterfaceDetails->DevicePath)); + InsertDeviceIntoCache(pInfo, devInterfaceDetails->DevicePath); + } + } + } + SetupDiDestroyDeviceInfoList(handle); + } + PaUtil_FreeMemory(devInterfaceDetails); + } +} + +static LRESULT CALLBACK PaMsgWinProcW(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + PaHotPlugDeviceEventHandlerInfo* pInfo = (PaHotPlugDeviceEventHandlerInfo*)( GetWindowLongPtr(hWnd, GWLP_USERDATA) ); + switch(msg) + { + case WM_DEVICECHANGE: + switch(wParam) + { + case DBT_DEVICEARRIVAL: + { + PDEV_BROADCAST_DEVICEINTERFACE_W ptr = (PDEV_BROADCAST_DEVICEINTERFACE_W)lParam; + if (ptr->dbcc_devicetype != DBT_DEVTYP_DEVICEINTERFACE) + break; + + if (!IsEqualGUID(&ptr->dbcc_classguid, &KSCATEGORY_AUDIO)) + break; + + if (IsDeviceAudio(ptr->dbcc_name)) + { + PA_DEBUG(("Device inserted : %S\n", ptr->dbcc_name)); + InsertDeviceIntoCache(pInfo, ptr->dbcc_name); + /* yield some seconds because added device may not be completely configured */ + Sleep(2000); + PaUtil_DevicesChanged(1, ptr->dbcc_name); + } + } + break; + case DBT_DEVICEREMOVECOMPLETE: + { + PDEV_BROADCAST_DEVICEINTERFACE_W ptr = (PDEV_BROADCAST_DEVICEINTERFACE_W)lParam; + if (ptr->dbcc_devicetype != DBT_DEVTYP_DEVICEINTERFACE) + break; + + if (!IsEqualGUID(&ptr->dbcc_classguid, &KSCATEGORY_AUDIO)) + break; + + if (RemoveDeviceFromCache(pInfo, ptr->dbcc_name)) + { + PA_DEBUG(("Device removed : %S\n", ptr->dbcc_name)); + Sleep(2000); + PaUtil_DevicesChanged(2, ptr->dbcc_name); + } + } + break; + default: + break; + } + break; + } + return DefWindowProcW(hWnd, msg, wParam, lParam); +} + +PA_THREAD_FUNC PaRunMessageLoop(void* ptr) +{ + PaHotPlugDeviceEventHandlerInfo* pInfo = (PaHotPlugDeviceEventHandlerInfo*)ptr; + WNDCLASSW wnd = { 0 }; + HMODULE hInstance = GetModuleHandleW(NULL); + + wnd.lpfnWndProc = PaMsgWinProcW; + wnd.hInstance = hInstance; + wnd.lpszClassName = L"{1E0D4F5A-B31F-4dcc-AE3C-4F30A47BD521}"; /* Using a GUID as class name */ + pInfo->hWnd = CreateWindowW((LPCWSTR)MAKEINTATOM(RegisterClassW(&wnd)), NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, hInstance, NULL); + if (pInfo->hWnd) + { + DEV_BROADCAST_DEVICEINTERFACE_W NotificationFilter = { sizeof(DEV_BROADCAST_DEVICEINTERFACE_W) }; + NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; + +#ifndef DEVICE_NOTIFY_ALL_INTERFACE_CLASSES +#define DEVICE_NOTIFY_ALL_INTERFACE_CLASSES 0x00000004 +#endif + + pInfo->hNotify = RegisterDeviceNotificationW( + pInfo->hWnd, + &NotificationFilter, + DEVICE_NOTIFY_WINDOW_HANDLE|DEVICE_NOTIFY_ALL_INTERFACE_CLASSES + ); + + assert(pInfo->hNotify); + + SetWindowLongPtr(pInfo->hWnd, GWLP_USERDATA, (LONG_PTR)pInfo); + + if (pInfo->hNotify) + { + MSG msg; + BOOL result; + while((result = GetMessageW(&msg, pInfo->hWnd, 0, 0)) != 0) + { + if (result == -1) + { + break; + } + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + UnregisterDeviceNotification(pInfo->hNotify); + pInfo->hNotify = 0; + } + DestroyWindow(pInfo->hWnd); + pInfo->hWnd = 0; + } + return 0; +} + +static PaHotPlugDeviceEventHandlerInfo* s_handler = 0; + +void PaUtil_InitializeHotPlug() +{ + if (s_handler == 0) + { + s_handler = (PaHotPlugDeviceEventHandlerInfo*)PaUtil_AllocateMemory(sizeof(PaHotPlugDeviceEventHandlerInfo)); + if (s_handler) + { + s_handler->cacheAllocGroup = PaUtil_CreateAllocationGroup(); + InitializeCriticalSection(&s_handler->lock); + PopulateCacheWithAvailableAudioDevices(s_handler); + /* Start message thread */ + s_handler->hMsgThread = CREATE_THREAD_FUNCTION(NULL, 0, PaRunMessageLoop, s_handler, 0, NULL); + assert(s_handler->hMsgThread != 0); + } + } +} + +void PaUtil_TerminateHotPlug() +{ + if (s_handler != 0) + { + if (s_handler->hWnd) + { + PostMessage(s_handler->hWnd, WM_QUIT, 0, 0); + if (WaitForSingleObject(s_handler->hMsgThread, 1000) == WAIT_TIMEOUT) + { + TerminateThread(s_handler->hMsgThread, -1); + } + } + DeleteCriticalSection(&s_handler->lock); + PaUtil_FreeAllAllocations( s_handler->cacheAllocGroup ); + PaUtil_DestroyAllocationGroup( s_handler->cacheAllocGroup ); + PaUtil_FreeMemory( s_handler ); + s_handler = 0; + } +} + +void PaUtil_LockHotPlug() +{ + EnterCriticalSection(&s_handler->lock); +} + +void PaUtil_UnlockHotPlug() +{ + LeaveCriticalSection(&s_handler->lock); +} diff --git a/src/os/win/pa_win_wdmks_utils.c b/src/os/win/pa_win_wdmks_utils.c index a830f76..0eafbaa 100644 --- a/src/os/win/pa_win_wdmks_utils.c +++ b/src/os/win/pa_win_wdmks_utils.c @@ -49,31 +49,31 @@ #include // MinGW32 does not define this automatically #include #include -#include // just for some development printfs +#include // just for some development printfs #include "portaudio.h" #include "pa_util.h" #include "pa_win_wdmks_utils.h" #if !defined(PA_WDMKS_NO_KSGUID_LIB) && !defined(PAWIN_WDMKS_NO_KSGUID_LIB) - #if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) /* MSC version 6 and above */ - #pragma comment( lib, "ksguid.lib" ) - #endif - #define pa_KSDATAFORMAT_TYPE_AUDIO KSDATAFORMAT_TYPE_AUDIO - #define pa_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT KSDATAFORMAT_SUBTYPE_IEEE_FLOAT - #define pa_KSDATAFORMAT_SUBTYPE_PCM KSDATAFORMAT_SUBTYPE_PCM - #define pa_KSDATAFORMAT_SUBTYPE_WAVEFORMATEX KSDATAFORMAT_SUBTYPE_WAVEFORMATEX - #define pa_KSMEDIUMSETID_Standard KSMEDIUMSETID_Standard - #define pa_KSINTERFACESETID_Standard KSINTERFACESETID_Standard - #define pa_KSPROPSETID_Pin KSPROPSETID_Pin +#if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) /* MSC version 6 and above */ +#pragma comment( lib, "ksguid.lib" ) +#endif +#define pa_KSDATAFORMAT_TYPE_AUDIO KSDATAFORMAT_TYPE_AUDIO +#define pa_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT KSDATAFORMAT_SUBTYPE_IEEE_FLOAT +#define pa_KSDATAFORMAT_SUBTYPE_PCM KSDATAFORMAT_SUBTYPE_PCM +#define pa_KSDATAFORMAT_SUBTYPE_WAVEFORMATEX KSDATAFORMAT_SUBTYPE_WAVEFORMATEX +#define pa_KSMEDIUMSETID_Standard KSMEDIUMSETID_Standard +#define pa_KSINTERFACESETID_Standard KSINTERFACESETID_Standard +#define pa_KSPROPSETID_Pin KSPROPSETID_Pin #else - static const GUID pa_KSDATAFORMAT_TYPE_AUDIO = { STATIC_KSDATAFORMAT_TYPE_AUDIO }; - static const GUID pa_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = { STATIC_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT }; - static const GUID pa_KSDATAFORMAT_SUBTYPE_PCM = { STATIC_KSDATAFORMAT_SUBTYPE_PCM }; - static const GUID pa_KSDATAFORMAT_SUBTYPE_WAVEFORMATEX = { STATIC_KSDATAFORMAT_SUBTYPE_WAVEFORMATEX }; - static const GUID pa_KSMEDIUMSETID_Standard = { STATIC_KSMEDIUMSETID_Standard }; - static const GUID pa_KSINTERFACESETID_Standard = { STATIC_KSINTERFACESETID_Standard }; - static const GUID pa_KSPROPSETID_Pin = { STATIC_KSPROPSETID_Pin }; +static const GUID pa_KSDATAFORMAT_TYPE_AUDIO = { STATIC_KSDATAFORMAT_TYPE_AUDIO }; +static const GUID pa_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = { STATIC_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT }; +static const GUID pa_KSDATAFORMAT_SUBTYPE_PCM = { STATIC_KSDATAFORMAT_SUBTYPE_PCM }; +static const GUID pa_KSDATAFORMAT_SUBTYPE_WAVEFORMATEX = { STATIC_KSDATAFORMAT_SUBTYPE_WAVEFORMATEX }; +static const GUID pa_KSMEDIUMSETID_Standard = { STATIC_KSMEDIUMSETID_Standard }; +static const GUID pa_KSINTERFACESETID_Standard = { STATIC_KSINTERFACESETID_Standard }; +static const GUID pa_KSPROPSETID_Pin = { STATIC_KSPROPSETID_Pin }; #endif diff --git a/test/patest_leftright.c b/test/patest_leftright.c index 33ccf12..c235dcf 100644 --- a/test/patest_leftright.c +++ b/test/patest_leftright.c @@ -9,7 +9,7 @@ @author Phil Burk */ /* - * $Id$ + * $Id: patest_leftright.c 1661 2011-04-28 18:54:46Z rob_bielik $ * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.portaudio.com @@ -90,17 +90,17 @@ static int patestCallback( const void *inputBuffer, { // Smoothly pan between left and right. if( data->currentBalance < data->targetBalance ) - { + { data->currentBalance += BALANCE_DELTA; - } + } else if( data->currentBalance > data->targetBalance ) - { + { data->currentBalance -= BALANCE_DELTA; - } + } // Apply left/right balance. *out++ = data->sine[data->left_phase] * (1.0f - data->currentBalance); /* left */ *out++ = data->sine[data->right_phase] * data->currentBalance; /* right */ - + data->left_phase += 1; if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE; data->right_phase += 3; /* higher pitch so we can distinguish left and right. */ @@ -118,7 +118,7 @@ int main(void) PaStreamParameters outputParameters; PaError err; paTestData data; - int i; + int i; printf("Play different tone sine waves that alternate between left and right channel.\n"); printf("The low tone should be on the left channel.\n"); @@ -159,7 +159,7 @@ int main(void) printf("Play for several seconds.\n"); for( i=0; i<4; i++ ) - { + { printf("Hear low sound on left side.\n"); data.targetBalance = 0.01; Pa_Sleep( 1000 ); @@ -167,7 +167,7 @@ int main(void) printf("Hear high sound on right side.\n"); data.targetBalance = 0.99; Pa_Sleep( 1000 ); - } + } err = Pa_StopStream( stream ); if( err != paNoError ) goto error; diff --git a/test/patest_out_underflow.c b/test/patest_out_underflow.c index e69def3..7872425 100644 --- a/test/patest_out_underflow.c +++ b/test/patest_out_underflow.c @@ -6,7 +6,7 @@ @author Phil Burk */ /* - * $Id$ + * $Id: patest_out_underflow.c 1661 2011-04-28 18:54:46Z rob_bielik $ * * This program uses the PortAudio Portable Audio Library. * For more information see: http://www.portaudio.com @@ -159,8 +159,8 @@ int main(void) /* Determine number of sines required to get to 50% */ do - { - Pa_Sleep( 100 ); + { + Pa_Sleep( 100 ); load = Pa_GetStreamCpuLoad( stream ); printf("sineCount = %d, CPU load = %f\n", data.sineCount, load ); @@ -168,7 +168,7 @@ int main(void) if( load < 0.3 ) { data.sineCount += 10; - } + } else if( load < 0.4 ) { data.sineCount += 2; diff --git a/test/patest_timing.c b/test/patest_timing.c index f224bfe..438ea6a 100644 --- a/test/patest_timing.c +++ b/test/patest_timing.c @@ -89,7 +89,7 @@ static int patestCallback( const void *inputBuffer, void *outputBuffer, timeInfo->currentTime, timeInfo->outputBufferDacTime ); - printf( "getStreamTime() returns: %g\n", Pa_GetStreamTime(data->stream) - data->start ); + printf( "getStreamTime() returns: %g\n", Pa_GetStreamTime(data->stream)-data->start ); for( i=0; i */ /* - * $Id$ + * $Id: patest_two_rates.c 1661 2011-04-28 18:54:46Z rob_bielik $ * * Author: Phil Burk http://www.softsynth.com * @@ -64,11 +64,11 @@ typedef struct } paTestData; /* This routine will be called by the PortAudio engine when audio is needed. - ** It may called at interrupt level on some machines so don't do anything - ** that could mess up the system like calling malloc() or free(). - */ +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ static int patestCallback( const void *inputBuffer, void *outputBuffer, - unsigned long framesPerBuffer, + unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void *userData ) @@ -119,17 +119,17 @@ int main(void) outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency; outputParameters.hostApiSpecificStreamInfo = NULL; - /* Start first stream. **********************/ + /* Start first stream. **********************/ err = Pa_OpenStream( - &stream1, + &stream1, NULL, /* no input */ &outputParameters, - SAMPLE_RATE_1, + SAMPLE_RATE_1, FRAMES_PER_BUFFER, - paClipOff, /* we won't output out of range samples so don't bother clipping them */ - patestCallback, - &data1 ); - if( err != paNoError ) goto error; + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data1 ); + if( err != paNoError ) goto error; err = Pa_StartStream( stream1 ); if( err != paNoError ) goto error; @@ -138,14 +138,14 @@ int main(void) /* Start second stream. **********************/ err = Pa_OpenStream( - &stream2, + &stream2, NULL, /* no input */ &outputParameters, - SAMPLE_RATE_2, + SAMPLE_RATE_2, FRAMES_PER_BUFFER, - paClipOff, /* we won't output out of range samples so don't bother clipping them */ - patestCallback, - &data2 ); + paClipOff, /* we won't output out of range samples so don't bother clipping them */ + patestCallback, + &data2 ); if( err != paNoError ) goto error; err = Pa_StartStream( stream2 ); diff --git a/test/patest_update_available_device_list.c b/test/patest_update_available_device_list.c new file mode 100644 index 0000000..9e901e0 --- /dev/null +++ b/test/patest_update_available_device_list.c @@ -0,0 +1,50 @@ +#include +#include +#include + +#include "portaudio.h" + +void printDevices() +{ + int deviceCount = Pa_GetDeviceCount(); + int i; + + for( i=0; i < deviceCount; ++i ){ + const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo(i); + const PaHostApiInfo *hostApiInfo = Pa_GetHostApiInfo( deviceInfo->hostApi ); + + assert( deviceInfo != 0 ); + + printf( "%d %s (%s)\n", i, deviceInfo->name, hostApiInfo->name ); + } +} + +static void devicesChangedCallback(void* p) +{ + (void)p; + + printf( "Portaudio device list have changed!\n" ); +} + +int main(int argc, char* argv[]) +{ + Pa_Initialize(); + + Pa_SetDevicesChangedCallback(NULL, devicesChangedCallback); + + for(;;){ + printDevices(); + + printf( "press [enter] to update the device list. or q + [enter] to quit.\n" ); + char ch = getchar(); + if( ch == 'q' ) + break; + + Pa_UpdateAvailableDeviceList(); + } + + Pa_Terminate(); + + return 0; +} +