--- /dev/null
+# make sure that .gitignore, .travis.yml,... are not part of a
+# source-package generated via 'git archive'
+.git* export-ignore
+/.* export-ignore
Makefile
*.o
+build
/config
/configure
/Makefile.in
--- /dev/null
+language: cpp
+sudo: false # docker VM
+matrix:
+ include:
+ - os: linux
+ env: HOST="" API="alsa"
+ compiler: gcc
+ - os: linux
+ env: HOST="" API="alsa"
+ compiler: clang
+ - os: linux
+ env: HOST="" API="jack"
+ compiler: gcc
+ - os: linux
+ env: HOST="" API="jack"
+ compiler: clang
+ - os: linux
+ env: HOST="" API="pulse"
+ compiler: gcc
+ - os: linux
+ env: HOST="" API="pulse"
+ compiler: clang
+ - os: linux
+ env: HOST="" API="oss"
+ compiler: gcc
+ - os: linux
+ env: HOST="" API="oss"
+ compiler: clang
+ - os: linux
+ env: HOST="--host=i686-w64-mingw32" API="dsound" CPPFLAGS="-Wno-unused-function"
+ compiler: gcc
+ - os: linux
+ env: HOST="--host=x86_64-w64-mingw32" API="dsound" CPPFLAGS="-Wno-unused-function"
+ compiler: gcc
+ - os: linux
+ env: HOST="--host=i686-w64-mingw32" API="asio" CPPFLAGS="-Wno-unused-function -Wno-unused-but-set-variable"
+ compiler: gcc
+ - os: linux
+ env: HOST="--host=x86_64-w64-mingw32" API="asio" CPPFLAGS="-Wno-unused-function -Wno-unused-but-set-variable"
+ compiler: gcc
+ - os: linux
+ env: HOST="--host=i686-w64-mingw32" API="wasapi" CPPFLAGS="-Wno-unused-function"
+ compiler: gcc
+ - os: linux
+ env: HOST="--host=x86_64-w64-mingw32" API="wasapi" CPPFLAGS="-Wno-unused-function"
+ compiler: gcc
+ # jack and asound not found on ARM gnueabihf
+ # - os: linux
+ # env: HOST="--host=arm-linux-gnueabihf" API="alsa"
+ # compiler: gcc
+ # - os: linux
+ # env: HOST="--host=arm-linux-gnueabihf" API="jack"
+ # compiler: gcc
+ - os: osx
+ env: HOST="" API="core"
+ compiler: gcc
+ - os: osx
+ env: HOST="" API="core"
+ compiler: clang
+install:
+- if [ $TRAVIS_OS_NAME = linux ]; then sudo apt-get install libasound2-dev libjack-dev libpulse-dev doxygen g++-mingw-w64-i686 g++-mingw-w64-x86-64 g++-arm-linux-gnueabihf oss4-dev; fi
+- if [ $TRAVIS_OS_NAME = osx ]; then brew install doxygen || (brew update && brew install doxygen); fi
+- if [ -n "$HOST" ]; then unset CXX; unset CC; fi
+script: ./autogen.sh --enable-debug --with-$API $HOST && make
+after_script:
+- make check
+- make distcheck
+- make install
+# ALSA: no access to /dev/snd/seq
+# JACK: Jack server not running
+# - tests/midiprobe
+notifications:
+ email:
+ recipients:
+ - radarsat1@gmail.com
+ on_success: never
+ on_failure: change
-cmake_minimum_required(VERSION 2.8.10)
-project(RtAudio)
+# Set minimum CMake required version for this project.
+cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
-include(CTest)
-include(CheckFunctionExists)
+# Define a C++ project.
+project(RtAudio LANGUAGES CXX)
+
+# Check for Jack (any OS)
+find_library(JACK_LIB jack)
+find_package(PkgConfig)
+pkg_check_modules(jack jack)
+if(JACK_LIB OR jack_FOUND)
+ set(HAVE_JACK TRUE)
+endif()
+
+# Check for Pulse (any OS)
+pkg_check_modules(pulse libpulse-simple)
+
+# Check for known non-Linux unix-likes
+if (CMAKE_SYSTEM_NAME MATCHES "kNetBSD.*|NetBSD.*")
+ message(STATUS "NetBSD detected, using OSS")
+ set(xBSD ON)
+elseif(UNIX AND NOT APPLE)
+ set(LINUX ON)
+endif()
+
+# Necessary for Windows
+if(WIN32)
+ set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
+ set(CMAKE_DEBUG_POSTFIX "d")
+endif()
+# Build Options
+option(BUILD_SHARED_LIBS "Compile library shared lib." TRUE)
+option(BUILD_STATIC_LIBS "Compile library static lib." TRUE)
+option(BUILD_TESTING "Compile test programs." TRUE)
option(BUILD_PYTHON "Build PyRtAudio python bindings" OFF)
-option(AUDIO_WINDOWS_DS "Build Windows DirectSound API" OFF)
-option(AUDIO_WINDOWS_ASIO "Build Windows ASIO API" OFF)
-option(AUDIO_WINDOWS_WASAPI "Build Windows WASAPI API" OFF)
-option(AUDIO_LINUX_OSS "Build Linux OSS API" OFF)
-option(AUDIO_LINUX_ALSA "Build Linux ALSA API" OFF)
-option(AUDIO_LINUX_PULSE "Build Linux PulseAudio API" OFF)
-option(AUDIO_UNIX_JACK "Build Unix JACK audio server API" OFF)
-option(AUDIO_OSX_CORE "Build Mac OSX CoreAudio API" OFF)
+set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type (Release,Debug)")
-if (CMAKE_BUILD_TYPE STREQUAL "Debug")
- add_definitions(-D__RTAUDIO_DEBUG__)
-endif ()
+# API Options
+option(RTAUDIO_API_DS "Build DirectSound API" OFF)
+option(RTAUDIO_API_ASIO "Build ASIO API" OFF)
+option(RTAUDIO_API_WASAPI "Build WASAPI API" ${WIN32})
+option(RTAUDIO_API_OSS "Build OSS4 API" ${xBSD})
+option(RTAUDIO_API_ALSA "Build ALSA API" ${LINUX})
+option(RTAUDIO_API_PULSE "Build PulseAudio API" ${pulse_FOUND})
+option(RTAUDIO_API_JACK "Build JACK audio server API" ${HAVE_JACK})
+option(RTAUDIO_API_CORE "Build CoreAudio API" ${APPLE})
+# Check for functions
+include(CheckFunctionExists)
check_function_exists(gettimeofday HAVE_GETTIMEOFDAY)
-
if (HAVE_GETTIMEOFDAY)
add_definitions(-DHAVE_GETTIMEOFDAY)
endif ()
+# Add -Wall if possible
if (CMAKE_COMPILER_IS_GNUCXX)
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
endif (CMAKE_COMPILER_IS_GNUCXX)
-set(rtaudio_SOURCES RtAudio.cpp)
+# Add debug flags
+if (CMAKE_BUILD_TYPE STREQUAL "Debug")
+ add_definitions(-D__RTAUDIO_DEBUG__)
+ if (CMAKE_COMPILER_IS_GNUCXX)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
+ endif (CMAKE_COMPILER_IS_GNUCXX)
+endif ()
+# Read libtool version info from configure.ac
+set(R "m4_define\\(\\[lt_([a-z]+)\\], ([0-9]+)\\)")
+file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/configure.ac" CONFIGAC
+ REGEX ${R})
+foreach(_S ${CONFIGAC})
+ string(REGEX REPLACE ${R} "\\1" k ${_S})
+ string(REGEX REPLACE ${R} "\\2" v ${_S})
+ set(SO_${k} ${v})
+endforeach()
+math(EXPR SO_current_minus_age "${SO_current} - ${SO_age}")
+set(SO_VER "${SO_current_minus_age}")
+set(FULL_VER "${SO_current_minus_age}.${SO_revision}.${SO_age}")
+
+# Read package version info from configure.ac
+set(R "AC_INIT\\(RtAudio, ([0-9\\.]+),.*\\)")
+file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/configure.ac" CONFIGAC
+ REGEX ${R})
+string(REGEX REPLACE ${R} "\\1" PACKAGE_VERSION ${CONFIGAC})
+
+# Init variables
+set(rtaudio_SOURCES RtAudio.cpp RtAudio.h rtaudio_c.cpp rtaudio_c.h)
set(LINKLIBS)
-if (CMAKE_SYSTEM_NAME MATCHES "kNetBSD.*|NetBSD.*")
- message(STATUS "NetBSD detected, using OSS")
- find_package(Threads REQUIRED CMAKE_THREAD_PREFER_PTHREAD)
- list(APPEND LINKLIBS ossaudio ${CMAKE_THREAD_LIBS_INIT})
- set(AUDIO_LINUX_OSS ON)
-elseif (UNIX AND NOT APPLE)
- if (NOT AUDIO_LINUX_PULSE AND NOT AUDIO_LINUX_ALSA AND NOT AUDIO_LINUX_OSS AND NOT AUDIO_UNIX_JACK)
- set(AUDIO_LINUX_ALSA ON)
- endif()
-
- if (AUDIO_LINUX_PULSE)
- find_library(PULSE_LIB pulse)
- find_library(PULSESIMPLE_LIB pulse-simple)
- find_package(Threads REQUIRED CMAKE_THREAD_PREFER_PTHREAD)
- list(APPEND LINKLIBS ${PULSE_LIB} ${PULSESIMPLE_LIB} ${CMAKE_THREAD_LIBS_INIT})
- add_definitions(-D__LINUX_PULSE__)
- message(STATUS "Using Linux PulseAudio")
- endif (AUDIO_LINUX_PULSE)
- if (AUDIO_LINUX_ALSA)
- find_package(ALSA)
- find_package(Threads REQUIRED CMAKE_THREAD_PREFER_PTHREAD)
- if (NOT ALSA_FOUND)
- message(FATAL_ERROR "ALSA API requested but no ALSA dev libraries found")
- endif()
- include_directories(${ALSA_INCLUDE_DIR})
- list(APPEND LINKLIBS ${ALSA_LIBRARY} ${CMAKE_THREAD_LIBS_INIT})
- add_definitions(-D__LINUX_ALSA__)
- message(STATUS "Using Linux ALSA")
- endif (AUDIO_LINUX_ALSA)
-endif ()
+set(PKGCONFIG_REQUIRES)
+set(API_DEFS)
+set(API_LIST)
+
+# Tweak API-specific configuration.
+
+# Jack
+if (RTAUDIO_API_JACK AND jack_FOUND)
+ set(NEED_PTHREAD ON)
+ list(APPEND PKGCONFIG_REQUIRES "jack")
+ list(APPEND API_DEFS "-D__UNIX_JACK__")
+ list(APPEND API_LIST "jack")
+ if(jack_FOUND)
+ list(APPEND LINKLIBS ${jack_LIBRARIES})
+ list(APPEND INCDIRS ${jack_INCLUDEDIR})
+ else()
+ list(APPEND LINKLIBS ${JACK_LIB})
+ endif()
+endif()
+
+# ALSA
+if (RTAUDIO_API_ALSA)
+ set(NEED_PTHREAD ON)
+ find_package(ALSA)
+ if (NOT ALSA_FOUND)
+ message(FATAL_ERROR "ALSA API requested but no ALSA dev libraries found")
+ endif()
+ list(APPEND INCDIRS ${ALSA_INCLUDE_DIR})
+ list(APPEND LINKLIBS ${ALSA_LIBRARY})
+ list(APPEND PKGCONFIG_REQUIRES "alsa")
+ list(APPEND API_DEFS "-D__LINUX_ALSA__")
+ list(APPEND API_LIST "alsa")
+endif()
+
+# OSS
+if (RTAUDIO_OSS)
+ set(NEED_PTHREAD ON)
+ find_library(OSSAUDIO_LIB ossaudio)
+ if (OSSAUDIO_LIB)
+ list(APPEND LINKLIBS ossaudio)
+ # Note: not an error on some systems
+ endif()
+ list(APPEND API_DEFS "-D__LINUX_OSS__")
+ list(APPEND API_LIST "oss")
+endif()
+
+# Pulse
+if (RTAUDIO_API_PULSE)
+ set(NEED_PTHREAD ON)
+ find_library(PULSE_LIB pulse)
+ find_library(PULSESIMPLE_LIB pulse-simple)
+ list(APPEND LINKLIBS ${PULSE_LIB} ${PULSESIMPLE_LIB})
+ list(APPEND PKGCONFIG_REQUIRES "libpulse-simple")
+ list(APPEND API_DEFS "-D__LINUX_PULSE__")
+ list(APPEND API_LIST "pulse")
+endif()
+
+# CoreAudio
+if (RTAUDIO_API_CORE)
+ find_library(COREAUDIO_LIB CoreAudio)
+ find_library(COREFOUNDATION_LIB CoreFoundation)
+ list(APPEND LINKLIBS ${COREAUDIO_LIB} ${COREFOUNDATION_LIB})
+ list(APPEND API_DEFS "-D__MACOSX_CORE__")
+ list(APPEND API_LIST "core")
+endif()
+
+# ASIO
+if (RTAUDIO_API_ASIO)
+ set(NEED_WIN32LIBS ON)
+ include_directories(include)
+ list(APPEND rtaudio_SOURCES
+ include/asio.cpp
+ include/asiodrivers.cpp
+ include/asiolist.cpp
+ include/iasiothiscallresolver.cpp)
+ list(APPEND API_DEFS "-D__WINDOWS_ASIO__")
+ list(APPEND API_LIST "asio")
+endif()
-if (APPLE)
- if (NOT AUDIO_OSX_CORE AND NOT AUDIO_UNIX_JACK)
- set(AUDIO_OSX_CORE ON)
- endif()
-
- if (AUDIO_OSX_CORE)
- find_library(COREAUDIO_LIB CoreAudio)
- find_library(COREFOUNDATION_LIB CoreFoundation)
- list(APPEND LINKLIBS ${COREAUDIO_LIB} ${COREFOUNDATION_LIB})
- add_definitions(-D__MACOSX_CORE__)
- message(STATUS "Using OSX CoreAudio")
- endif (AUDIO_OSX_CORE)
-endif (APPLE)
-
-# JACK supported on many Unices
-if (UNIX)
- if (AUDIO_UNIX_JACK)
- find_library(JACK_LIB jack)
- list(APPEND LINKLIBS ${JACK_LIB})
- add_definitions(-D__UNIX_JACK__)
- message(STATUS "Using JACK")
- endif (AUDIO_UNIX_JACK)
-endif (UNIX)
-
-if (WIN32)
- if (NOT AUDIO_WINDOWS_DS AND NOT AUDIO_WINDOWS_ASIO AND NOT AUDIO_WINDOWS_WASAPI)
- set(AUDIO_WINDOWS_WASAPI ON)
- endif()
-
- include_directories(include)
- list(APPEND LINKLIBS winmm ole32)
-
- if (AUDIO_WINDOWS_DS)
- add_definitions(-D__WINDOWS_DS__)
- message(STATUS "Using Windows DirectSound")
- list(APPEND LINKLIBS dsound)
- endif (AUDIO_WINDOWS_DS)
- if (AUDIO_WINDOWS_WASAPI)
- add_definitions(-D__WINDOWS_WASAPI__)
- message(STATUS "Using Windows WASAPI")
- list(APPEND LINKLIBS uuid ksuser)
- endif (AUDIO_WINDOWS_WASAPI)
- if (AUDIO_WINDOWS_ASIO)
- list(APPEND rtaudio_SOURCES
- include/asio.cpp
- include/asiodrivers.cpp
- include/asiolist.cpp
- include/iasiothiscallresolver.cpp)
- add_definitions(-D__WINDOWS_ASIO__)
- message(STATUS "Using Windows ASIO")
- endif (AUDIO_WINDOWS_ASIO)
-endif (WIN32)
+# DSound
+if (RTAUDIO_API_DS)
+ set(NEED_WIN32LIBS ON)
+ list(APPEND LINKLIBS dsound)
+ list(APPEND API_DEFS "-D__WINDOWS_DS__")
+ list(APPEND API_LIST "ds")
+endif()
+# WASAPI
+if (RTAUDIO_API_WASAPI)
+ include_directories(include)
+ set(NEED_WIN32LIBS ON)
+ list(APPEND LINKLIBS ksuser mfplat mfuuid wmcodecdspuuid)
+ list(APPEND API_DEFS "-D__WINDOWS_WASAPI__")
+ list(APPEND API_LIST "wasapi")
+endif()
+
+# Windows libs
+if (NEED_WIN32LIBS)
+ list(APPEND LINKLIBS winmm ole32)
+endif()
+
+# pthread
+if (NEED_PTHREAD)
+ find_package(Threads REQUIRED
+ CMAKE_THREAD_PREFER_PTHREAD
+ THREADS_PREFER_PTHREAD_FLAG)
+ list(APPEND LINKLIBS Threads::Threads)
+endif()
+
+# Create library targets.
cmake_policy(SET CMP0042 OLD)
-add_library(rtaudio SHARED ${rtaudio_SOURCES})
-add_library(rtaudio_static STATIC ${rtaudio_SOURCES})
+set(LIB_TARGETS)
+if(BUILD_SHARED_LIBS)
+ add_library(rtaudio SHARED ${rtaudio_SOURCES})
+ list(APPEND LIB_TARGETS rtaudio)
+
+ # Add headers destination for install rule.
+ set_target_properties(rtaudio PROPERTIES PUBLIC_HEADER RtAudio.h
+ SOVERSION ${SO_VER}
+ VERSION ${FULL_VER})
+
+ # Set include paths, populate target interface.
+ target_include_directories(rtaudio PRIVATE
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+ ${INCDIRS})
+
+ # Set compile-time definitions
+ target_compile_definitions(rtaudio PRIVATE ${API_DEFS})
+ target_compile_definitions(rtaudio PRIVATE RTAUDIO_EXPORT)
+
+ target_link_libraries(rtaudio ${LINKLIBS})
+endif()
+
+if(BUILD_STATIC_LIBS)
+ add_library(rtaudio_static STATIC ${rtaudio_SOURCES})
+ list(APPEND LIB_TARGETS rtaudio_static)
+
+ # Add headers destination for install rule.
+ set_target_properties(rtaudio_static PROPERTIES PUBLIC_HEADER RtAudio.h
+ SOVERSION ${SO_VER}
+ VERSION ${FULL_VER})
+
+ # Set include paths, populate target interface.
+ target_include_directories(rtaudio_static PRIVATE
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+ ${INCDIRS})
+
+ # Set compile-time definitions
+ target_compile_definitions(rtaudio_static PRIVATE ${API_DEFS})
-target_link_libraries(rtaudio ${LINKLIBS})
+ target_link_libraries(rtaudio_static ${LINKLIBS})
+endif()
+# Set standard installation directories.
+include(GNUInstallDirs)
+
+# Subdirs
if (BUILD_TESTING)
- add_subdirectory(tests)
+ include(CTest)
+ add_subdirectory(tests)
endif (BUILD_TESTING)
-install(TARGETS rtaudio
- LIBRARY DESTINATION lib
- ARCHIVE DESTINATION lib
- RUNTIME DESTINATION bin)
+# Message
+string(REPLACE ";" " " apilist "${API_LIST}")
+message(STATUS "Compiling with support for: ${apilist}")
-install(
- FILES RtAudio.h
- DESTINATION include)
+# PkgConfig file
+string(REPLACE ";" " " req "${PKGCONFIG_REQUIRES}")
+string(REPLACE ";" " " api "${API_DEFS}")
+set(prefix ${CMAKE_INSTALL_PREFIX})
+configure_file("rtaudio.pc.in" "rtaudio.pc" @ONLY)
+
+# Add install rule.
+install(TARGETS ${LIB_TARGETS}
+ EXPORT RtAudioTargets
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
+
+# Store the package in the user registry.
+export(PACKAGE RtAudio)
+
+# Set installation path for CMake files.
+if(WIN32)
+ set(RTAUDIO_CMAKE_DESTINATION cmake)
+else()
+ set(RTAUDIO_CMAKE_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/RtAudio)
+endif()
+
+# Create CMake configuration export file.
+file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/RtAudioConfig.cmake "include(\${CMAKE_CURRENT_LIST_DIR}/RtAudioTargets.cmake)")
+
+# Install CMake configuration export file.
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/RtAudioConfig.cmake
+ DESTINATION ${RTAUDIO_CMAKE_DESTINATION})
+
+# Export library target (build-tree).
+export(EXPORT RtAudioTargets
+ NAMESPACE RtAudio::)
+
+# Export library target (install-tree).
+install(EXPORT RtAudioTargets
+ DESTINATION ${RTAUDIO_CMAKE_DESTINATION}
+ NAMESPACE RtAudio::)
+
+# Configure uninstall target.
+configure_file(
+ "${CMAKE_CURRENT_SOURCE_DIR}/cmake/RtAudioConfigUninstall.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/RtAudioConfigUninstall.cmake" @ONLY)
+
+# Create uninstall target.
+add_custom_target(uninstall
+ COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/RtAudioConfigUninstall.cmake)
install(
- FILES rtaudio.pc
- DESTINATION lib/pkgconfig)
+ FILES ${CMAKE_CURRENT_BINARY_DIR}/rtaudio.pc
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
--- /dev/null
+30.04.2018
+ * Additions and fixes for realtime operation: (Tim E. Real of MusE)
+ - Added realtime operation to Pulse driver.
+ - Fixed ALSA realtime support. Attributes are once again all set
+ in probeDeviceOpen().
+ - Fixed OSS realtime support. Same mods as done to ALSA driver.
+ OSS untested, but should work, it's the same code.
+ - A diagnostic message (streamed to cerr) in each of the callback
+ handlers informs the user if realtime is really running.
+
SUBDIRS += doc
endif
+AM_CXXFLAGS = @visibility@
+
lib_LTLIBRARIES = %D%/librtaudio.la
+%C%_librtaudio_la_CXXFLAGS = -DRTAUDIO_EXPORT
%C%_librtaudio_la_LDFLAGS = -no-undefined -export-dynamic -version-info @SO_VERSION@
%C%_librtaudio_la_SOURCES = \
- %D%/RtAudio.cpp
+ %D%/RtAudio.cpp \
+ %D%/rtaudio_c.cpp
+
+if ASIO
+%C%_librtaudio_la_SOURCES += \
+ include/asio.cpp \
+ include/asiodrivers.cpp \
+ include/asiolist.cpp \
+ include/iasiothiscallresolver.cpp
+
+# due to warning in asiolist.cpp
+%C%_librtaudio_la_CXXFLAGS += -Wno-error=unused-but-set-variable
+endif
rtaudio_incdir = $(includedir)/rtaudio
rtaudio_inc_HEADERS = \
- %D%/RtAudio.h
+ %D%/RtAudio.h \
+ %D%/rtaudio_c.h
pkgconfigdatadir = $(libdir)/pkgconfig
pkgconfigdata_DATA = rtaudio.pc
--- /dev/null
+# RtAudio
+
+[![Build Status](https://travis-ci.org/thestk/rtaudio.svg?branch=master)](https://travis-ci.org/thestk/rtaudio)
+
+A set of C++ classes that provide a common API for realtime audio input/output across Linux (native ALSA, JACK, PulseAudio and OSS), Macintosh OS X (CoreAudio and JACK), and Windows (DirectSound, ASIO and WASAPI) operating systems.
+
+By Gary P. Scavone, 2001-2017 (and many other developers!)
+
+This distribution of RtAudio contains the following:
+
+- doc: RtAudio documentation (see doc/html/index.html)
+- tests: example RtAudio programs
+- include: header and source files necessary for ASIO, DS & OSS compilation
+- tests/Windows: Visual C++ .net test program workspace and projects
+
+## Overview
+
+RtAudio is a set of C++ classes that provides a common API (Application Programming Interface) for realtime audio input/output across Linux (native ALSA, JACK, PulseAudio and OSS), Macintosh OS X and Windows (DirectSound, ASIO and WASAPI) operating systems. RtAudio significantly simplifies the process of interacting with computer audio hardware. It was designed with the following objectives:
+
+ - object-oriented C++ design
+ - simple, common API across all supported platforms
+ - only one source and one header file for easy inclusion in programming projects
+ - allow simultaneous multi-api support
+ - support dynamic connection of devices
+ - provide extensive audio device parameter control
+ - allow audio device capability probing
+ - automatic internal conversion for data format, channel number compensation, (de)interleaving, and byte-swapping
+
+RtAudio incorporates the concept of audio streams, which represent audio output (playback) and/or input (recording). Available audio devices and their capabilities can be enumerated and then specified when opening a stream. Where applicable, multiple API support can be compiled and a particular API specified when creating an RtAudio instance. See the \ref apinotes section for information specific to each of the supported audio APIs.
+
+## Further Reading
+
+For complete documentation on RtAudio, see the doc directory of the distribution or surf to http://www.music.mcgill.ca/~gary/rtaudio/.
+
+
+## Legal and ethical:
+
+The RtAudio license is similar to the MIT License.
+
+ RtAudio: a set of realtime audio i/o C++ classes
+ Copyright (c) 2001-2017 Gary P. Scavone
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation files
+ (the "Software"), to deal in the Software without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of the Software,
+ and to permit persons to whom the Software is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ Any person wishing to distribute modifications to the Software is
+ asked to send the modifications to the original developer so that
+ they can be incorporated into the canonical version. This is,
+ however, not a binding provision of this license.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-/************************************************************************/
+/************************************************************************/
/*! \class RtAudio
\brief Realtime audio i/o C++ classes.
return RTAUDIO_VERSION;
}
-void RtAudio :: getCompiledApi( std::vector<RtAudio::Api> &apis )
-{
- apis.clear();
+// Define API names and display names.
+// Must be in same order as API enum.
+extern "C" {
+const char* rtaudio_api_names[][2] = {
+ { "unspecified" , "Unknown" },
+ { "alsa" , "ALSA" },
+ { "pulse" , "Pulse" },
+ { "oss" , "OpenSoundSystem" },
+ { "jack" , "Jack" },
+ { "core" , "CoreAudio" },
+ { "wasapi" , "WASAPI" },
+ { "asio" , "ASIO" },
+ { "ds" , "DirectSound" },
+ { "dummy" , "Dummy" },
+};
+const unsigned int rtaudio_num_api_names =
+ sizeof(rtaudio_api_names)/sizeof(rtaudio_api_names[0]);
- // The order here will control the order of RtAudio's API search in
- // the constructor.
+// The order here will control the order of RtAudio's API search in
+// the constructor.
+extern "C" const RtAudio::Api rtaudio_compiled_apis[] = {
#if defined(__UNIX_JACK__)
- apis.push_back( UNIX_JACK );
-#endif
-#if defined(__LINUX_ALSA__)
- apis.push_back( LINUX_ALSA );
+ RtAudio::UNIX_JACK,
#endif
#if defined(__LINUX_PULSE__)
- apis.push_back( LINUX_PULSE );
+ RtAudio::LINUX_PULSE,
+#endif
+#if defined(__LINUX_ALSA__)
+ RtAudio::LINUX_ALSA,
#endif
#if defined(__LINUX_OSS__)
- apis.push_back( LINUX_OSS );
+ RtAudio::LINUX_OSS,
#endif
#if defined(__WINDOWS_ASIO__)
- apis.push_back( WINDOWS_ASIO );
+ RtAudio::WINDOWS_ASIO,
#endif
#if defined(__WINDOWS_WASAPI__)
- apis.push_back( WINDOWS_WASAPI );
+ RtAudio::WINDOWS_WASAPI,
#endif
#if defined(__WINDOWS_DS__)
- apis.push_back( WINDOWS_DS );
+ RtAudio::WINDOWS_DS,
#endif
#if defined(__MACOSX_CORE__)
- apis.push_back( MACOSX_CORE );
+ RtAudio::MACOSX_CORE,
#endif
#if defined(__RTAUDIO_DUMMY__)
- apis.push_back( RTAUDIO_DUMMY );
+ RtAudio::RTAUDIO_DUMMY,
#endif
+ RtAudio::UNSPECIFIED,
+};
+extern "C" const unsigned int rtaudio_num_compiled_apis =
+ sizeof(rtaudio_compiled_apis)/sizeof(rtaudio_compiled_apis[0])-1;
+}
+
+// This is a compile-time check that rtaudio_num_api_names == RtAudio::NUM_APIS.
+// If the build breaks here, check that they match.
+template<bool b> class StaticAssert { private: StaticAssert() {} };
+template<> class StaticAssert<true>{ public: StaticAssert() {} };
+class StaticAssertions { StaticAssertions() {
+ StaticAssert<rtaudio_num_api_names == RtAudio::NUM_APIS>();
+}};
+
+void RtAudio :: getCompiledApi( std::vector<RtAudio::Api> &apis )
+{
+ apis = std::vector<RtAudio::Api>(rtaudio_compiled_apis,
+ rtaudio_compiled_apis + rtaudio_num_compiled_apis);
+}
+
+std::string RtAudio :: getApiName( RtAudio::Api api )
+{
+ if (api < 0 || api >= RtAudio::NUM_APIS)
+ return "";
+ return rtaudio_api_names[api][0];
+}
+
+std::string RtAudio :: getApiDisplayName( RtAudio::Api api )
+{
+ if (api < 0 || api >= RtAudio::NUM_APIS)
+ return "Unknown";
+ return rtaudio_api_names[api][1];
+}
+
+RtAudio::Api RtAudio :: getCompiledApiByName( const std::string &name )
+{
+ unsigned int i=0;
+ for (i = 0; i < rtaudio_num_compiled_apis; ++i)
+ if (name == rtaudio_api_names[rtaudio_compiled_apis[i]][0])
+ return rtaudio_compiled_apis[i];
+ return RtAudio::UNSPECIFIED;
}
void RtAudio :: openRtApi( RtAudio::Api api )
return;
}
+ #if defined( HAVE_GETTIMEOFDAY )
+ gettimeofday( &stream_.lastTickTimestamp, NULL );
+ #endif
+
OSStatus result = noErr;
CoreHandle *handle = (CoreHandle *) stream_.apiHandle;
if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
const char **ports;
std::string port, previousPort;
unsigned int nChannels = 0, nDevices = 0;
- ports = jack_get_ports( client, NULL, NULL, 0 );
+ ports = jack_get_ports( client, NULL, JACK_DEFAULT_AUDIO_TYPE, 0 );
if ( ports ) {
// Parse the port names up to the first colon (:).
size_t iColon = 0;
const char **ports;
std::string port, previousPort;
unsigned int nPorts = 0, nDevices = 0;
- ports = jack_get_ports( client, NULL, NULL, 0 );
+ ports = jack_get_ports( client, NULL, JACK_DEFAULT_AUDIO_TYPE, 0 );
if ( ports ) {
// Parse the port names up to the first colon (:).
size_t iColon = 0;
// Count the available ports containing the client name as device
// channels. Jack "input ports" equal RtAudio output channels.
unsigned int nChannels = 0;
- ports = jack_get_ports( client, info.name.c_str(), NULL, JackPortIsInput );
+ ports = jack_get_ports( client, info.name.c_str(), JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput );
if ( ports ) {
while ( ports[ nChannels ] ) nChannels++;
free( ports );
// Jack "output ports" equal RtAudio input channels.
nChannels = 0;
- ports = jack_get_ports( client, info.name.c_str(), NULL, JackPortIsOutput );
+ ports = jack_get_ports( client, info.name.c_str(), JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput );
if ( ports ) {
while ( ports[ nChannels ] ) nChannels++;
free( ports );
static int jackXrun( void *infoPointer )
{
- JackHandle *handle = (JackHandle *) infoPointer;
+ JackHandle *handle = *((JackHandle **) infoPointer);
if ( handle->ports[0] ) handle->xrun[0] = true;
if ( handle->ports[1] ) handle->xrun[1] = true;
const char **ports;
std::string port, previousPort, deviceName;
unsigned int nPorts = 0, nDevices = 0;
- ports = jack_get_ports( client, NULL, NULL, 0 );
+ ports = jack_get_ports( client, NULL, JACK_DEFAULT_AUDIO_TYPE, 0 );
if ( ports ) {
// Parse the port names up to the first colon (:).
size_t iColon = 0;
return FAILURE;
}
- // Count the available ports containing the client name as device
- // channels. Jack "input ports" equal RtAudio output channels.
- unsigned int nChannels = 0;
unsigned long flag = JackPortIsInput;
if ( mode == INPUT ) flag = JackPortIsOutput;
- ports = jack_get_ports( client, deviceName.c_str(), NULL, flag );
- if ( ports ) {
- while ( ports[ nChannels ] ) nChannels++;
- free( ports );
- }
- // Compare the jack ports for specified client to the requested number of channels.
- if ( nChannels < (channels + firstChannel) ) {
- errorStream_ << "RtApiJack::probeDeviceOpen: requested number of channels (" << channels << ") + offset (" << firstChannel << ") not found for specified device (" << device << ":" << deviceName << ").";
- errorText_ = errorStream_.str();
- return FAILURE;
+ if ( ! (options && (options->flags & RTAUDIO_JACK_DONT_CONNECT)) ) {
+ // Count the available ports containing the client name as device
+ // channels. Jack "input ports" equal RtAudio output channels.
+ unsigned int nChannels = 0;
+ ports = jack_get_ports( client, deviceName.c_str(), JACK_DEFAULT_AUDIO_TYPE, flag );
+ if ( ports ) {
+ while ( ports[ nChannels ] ) nChannels++;
+ free( ports );
+ }
+ // Compare the jack ports for specified client to the requested number of channels.
+ if ( nChannels < (channels + firstChannel) ) {
+ errorStream_ << "RtApiJack::probeDeviceOpen: requested number of channels (" << channels << ") + offset (" << firstChannel << ") not found for specified device (" << device << ":" << deviceName << ").";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
}
// Check the jack server sample rate.
stream_.sampleRate = jackRate;
// Get the latency of the JACK port.
- ports = jack_get_ports( client, deviceName.c_str(), NULL, flag );
+ ports = jack_get_ports( client, deviceName.c_str(), JACK_DEFAULT_AUDIO_TYPE, flag );
if ( ports[ firstChannel ] ) {
// Added by Ge Wang
jack_latency_callback_mode_t cbmode = (mode == INPUT ? JackCaptureLatency : JackPlaybackLatency);
else {
stream_.mode = mode;
jack_set_process_callback( handle->client, jackCallbackHandler, (void *) &stream_.callbackInfo );
- jack_set_xrun_callback( handle->client, jackXrun, (void *) &handle );
+ jack_set_xrun_callback( handle->client, jackXrun, (void *) &stream_.apiHandle );
jack_on_shutdown( handle->client, jackShutdown, (void *) &stream_.callbackInfo );
}
return;
}
+ #if defined( HAVE_GETTIMEOFDAY )
+ gettimeofday( &stream_.lastTickTimestamp, NULL );
+ #endif
+
JackHandle *handle = (JackHandle *) stream_.apiHandle;
int result = jack_activate( handle->client );
if ( result ) {
// Get the list of available ports.
if ( shouldAutoconnect_ && (stream_.mode == OUTPUT || stream_.mode == DUPLEX) ) {
result = 1;
- ports = jack_get_ports( handle->client, handle->deviceName[0].c_str(), NULL, JackPortIsInput);
+ ports = jack_get_ports( handle->client, handle->deviceName[0].c_str(), JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput);
if ( ports == NULL) {
errorText_ = "RtApiJack::startStream(): error determining available JACK input ports!";
goto unlock;
if ( shouldAutoconnect_ && (stream_.mode == INPUT || stream_.mode == DUPLEX) ) {
result = 1;
- ports = jack_get_ports( handle->client, handle->deviceName[1].c_str(), NULL, JackPortIsOutput );
+ ports = jack_get_ports( handle->client, handle->deviceName[1].c_str(), JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput );
if ( ports == NULL) {
errorText_ = "RtApiJack::startStream(): error determining available JACK output ports!";
goto unlock;
result = ASIOCreateBuffers( handle->bufferInfos, nChannels, stream_.bufferSize, &asioCallbacks );
if ( result != ASE_OK ) {
// Standard method failed. This can happen with strict/misbehaving drivers that return valid buffer size ranges
- // but only accept the preferred buffer size as parameter for ASIOCreateBuffers. eg. Creatives ASIO driver
- // in that case, let's be naïve and try that instead
+ // but only accept the preferred buffer size as parameter for ASIOCreateBuffers (e.g. Creative's ASIO driver).
+ // In that case, let's be naïve and try that instead.
*bufferSize = preferSize;
stream_.bufferSize = *bufferSize;
result = ASIOCreateBuffers( handle->bufferInfos, nChannels, stream_.bufferSize, &asioCallbacks );
return;
}
+ #if defined( HAVE_GETTIMEOFDAY )
+ gettimeofday( &stream_.lastTickTimestamp, NULL );
+ #endif
+
AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
ASIOError result = ASIOStart();
if ( result != ASE_OK ) {
#ifndef INITGUID
#define INITGUID
#endif
+
+#include <mfapi.h>
+#include <mferror.h>
+#include <mfplay.h>
+#include <mftransform.h>
+#include <wmcodecdsp.h>
+
#include <audioclient.h>
#include <avrt.h>
#include <mmdeviceapi.h>
#include <functiondiscoverykeys_devpkey.h>
+#ifndef MF_E_TRANSFORM_NEED_MORE_INPUT
+ #define MF_E_TRANSFORM_NEED_MORE_INPUT _HRESULT_TYPEDEF_(0xc00d6d72)
+#endif
+
+#ifndef MFSTARTUP_NOSOCKET
+ #define MFSTARTUP_NOSOCKET 0x1
+#endif
+
+#ifdef _MSC_VER
+ #pragma comment( lib, "ksuser" )
+ #pragma comment( lib, "mfplat.lib" )
+ #pragma comment( lib, "mfuuid.lib" )
+ #pragma comment( lib, "wmcodecdspuuid" )
+#endif
+
//=============================================================================
#define SAFE_RELEASE( objectPtr )\
}
// "in" index can end on the "out" index but cannot begin at it
- if ( inIndex_ <= relOutIndex && inIndexEnd > relOutIndex ) {
+ if ( inIndex_ < relOutIndex && inIndexEnd > relOutIndex ) {
return false; // not enough space between "in" index and "out" index
}
}
// "out" index can begin at and end on the "in" index
- if ( outIndex_ < relInIndex && outIndexEnd > relInIndex ) {
+ if ( outIndex_ <= relInIndex && outIndexEnd > relInIndex ) {
return false; // not enough space between "out" index and "in" index
}
//-----------------------------------------------------------------------------
// In order to satisfy WASAPI's buffer requirements, we need a means of converting sample rate
-// between HW and the user. The convertBufferWasapi function is used to perform this conversion
-// between HwIn->UserIn and UserOut->HwOut during the stream callback loop.
-// This sample rate converter works best with conversions between one rate and its multiple.
-void convertBufferWasapi( char* outBuffer,
- const char* inBuffer,
- const unsigned int& channelCount,
- const unsigned int& inSampleRate,
- const unsigned int& outSampleRate,
- const unsigned int& inSampleCount,
- unsigned int& outSampleCount,
- const RtAudioFormat& format )
-{
- // calculate the new outSampleCount and relative sampleStep
- float sampleRatio = ( float ) outSampleRate / inSampleRate;
- float sampleRatioInv = ( float ) 1 / sampleRatio;
- float sampleStep = 1.0f / sampleRatio;
- float inSampleFraction = 0.0f;
-
- outSampleCount = ( unsigned int ) std::roundf( inSampleCount * sampleRatio );
-
- // if inSampleRate is a multiple of outSampleRate (or vice versa) there's no need to interpolate
- if ( floor( sampleRatio ) == sampleRatio || floor( sampleRatioInv ) == sampleRatioInv )
+// between HW and the user. The WasapiResampler class is used to perform this conversion between
+// HwIn->UserIn and UserOut->HwOut during the stream callback loop.
+class WasapiResampler
+{
+public:
+ WasapiResampler( bool isFloat, unsigned int bitsPerSample, unsigned int channelCount,
+ unsigned int inSampleRate, unsigned int outSampleRate )
+ : _bytesPerSample( bitsPerSample / 8 )
+ , _channelCount( channelCount )
+ , _sampleRatio( ( float ) outSampleRate / inSampleRate )
+ , _transformUnk( NULL )
+ , _transform( NULL )
+ , _mediaType( NULL )
+ , _inputMediaType( NULL )
+ , _outputMediaType( NULL )
+
+ #ifdef __IWMResamplerProps_FWD_DEFINED__
+ , _resamplerProps( NULL )
+ #endif
{
- // frame-by-frame, copy each relative input sample into it's corresponding output sample
- for ( unsigned int outSample = 0; outSample < outSampleCount; outSample++ )
- {
- unsigned int inSample = ( unsigned int ) inSampleFraction;
+ // 1. Initialization
- switch ( format )
- {
- case RTAUDIO_SINT8:
- memcpy( &( ( char* ) outBuffer )[ outSample * channelCount ], &( ( char* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( char ) );
- break;
- case RTAUDIO_SINT16:
- memcpy( &( ( short* ) outBuffer )[ outSample * channelCount ], &( ( short* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( short ) );
- break;
- case RTAUDIO_SINT24:
- memcpy( &( ( S24* ) outBuffer )[ outSample * channelCount ], &( ( S24* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( S24 ) );
- break;
- case RTAUDIO_SINT32:
- memcpy( &( ( int* ) outBuffer )[ outSample * channelCount ], &( ( int* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( int ) );
- break;
- case RTAUDIO_FLOAT32:
- memcpy( &( ( float* ) outBuffer )[ outSample * channelCount ], &( ( float* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( float ) );
- break;
- case RTAUDIO_FLOAT64:
- memcpy( &( ( double* ) outBuffer )[ outSample * channelCount ], &( ( double* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( double ) );
- break;
- }
+ MFStartup( MF_VERSION, MFSTARTUP_NOSOCKET );
- // jump to next in sample
- inSampleFraction += sampleStep;
- }
+ // 2. Create Resampler Transform Object
+
+ CoCreateInstance( CLSID_CResamplerMediaObject, NULL, CLSCTX_INPROC_SERVER,
+ IID_IUnknown, ( void** ) &_transformUnk );
+
+ _transformUnk->QueryInterface( IID_PPV_ARGS( &_transform ) );
+
+ #ifdef __IWMResamplerProps_FWD_DEFINED__
+ _transformUnk->QueryInterface( IID_PPV_ARGS( &_resamplerProps ) );
+ _resamplerProps->SetHalfFilterLength( 60 ); // best conversion quality
+ #endif
+
+ // 3. Specify input / output format
+
+ MFCreateMediaType( &_mediaType );
+ _mediaType->SetGUID( MF_MT_MAJOR_TYPE, MFMediaType_Audio );
+ _mediaType->SetGUID( MF_MT_SUBTYPE, isFloat ? MFAudioFormat_Float : MFAudioFormat_PCM );
+ _mediaType->SetUINT32( MF_MT_AUDIO_NUM_CHANNELS, channelCount );
+ _mediaType->SetUINT32( MF_MT_AUDIO_SAMPLES_PER_SECOND, inSampleRate );
+ _mediaType->SetUINT32( MF_MT_AUDIO_BLOCK_ALIGNMENT, _bytesPerSample * channelCount );
+ _mediaType->SetUINT32( MF_MT_AUDIO_AVG_BYTES_PER_SECOND, _bytesPerSample * channelCount * inSampleRate );
+ _mediaType->SetUINT32( MF_MT_AUDIO_BITS_PER_SAMPLE, bitsPerSample );
+ _mediaType->SetUINT32( MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE );
+
+ MFCreateMediaType( &_inputMediaType );
+ _mediaType->CopyAllItems( _inputMediaType );
+
+ _transform->SetInputType( 0, _inputMediaType, 0 );
+
+ MFCreateMediaType( &_outputMediaType );
+ _mediaType->CopyAllItems( _outputMediaType );
+
+ _outputMediaType->SetUINT32( MF_MT_AUDIO_SAMPLES_PER_SECOND, outSampleRate );
+ _outputMediaType->SetUINT32( MF_MT_AUDIO_AVG_BYTES_PER_SECOND, _bytesPerSample * channelCount * outSampleRate );
+
+ _transform->SetOutputType( 0, _outputMediaType, 0 );
+
+ // 4. Send stream start messages to Resampler
+
+ _transform->ProcessMessage( MFT_MESSAGE_COMMAND_FLUSH, 0 );
+ _transform->ProcessMessage( MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0 );
+ _transform->ProcessMessage( MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0 );
}
- else // else interpolate
+
+ ~WasapiResampler()
{
- // frame-by-frame, copy each relative input sample into it's corresponding output sample
- for ( unsigned int outSample = 0; outSample < outSampleCount; outSample++ )
+ // 8. Send stream stop messages to Resampler
+
+ _transform->ProcessMessage( MFT_MESSAGE_NOTIFY_END_OF_STREAM, 0 );
+ _transform->ProcessMessage( MFT_MESSAGE_NOTIFY_END_STREAMING, 0 );
+
+ // 9. Cleanup
+
+ MFShutdown();
+
+ SAFE_RELEASE( _transformUnk );
+ SAFE_RELEASE( _transform );
+ SAFE_RELEASE( _mediaType );
+ SAFE_RELEASE( _inputMediaType );
+ SAFE_RELEASE( _outputMediaType );
+
+ #ifdef __IWMResamplerProps_FWD_DEFINED__
+ SAFE_RELEASE( _resamplerProps );
+ #endif
+ }
+
+ void Convert( char* outBuffer, const char* inBuffer, unsigned int inSampleCount, unsigned int& outSampleCount )
+ {
+ unsigned int inputBufferSize = _bytesPerSample * _channelCount * inSampleCount;
+ if ( _sampleRatio == 1 )
{
- unsigned int inSample = ( unsigned int ) inSampleFraction;
- float inSampleDec = inSampleFraction - inSample;
- unsigned int frameInSample = inSample * channelCount;
- unsigned int frameOutSample = outSample * channelCount;
+ // no sample rate conversion required
+ memcpy( outBuffer, inBuffer, inputBufferSize );
+ outSampleCount = inSampleCount;
+ return;
+ }
- switch ( format )
- {
- case RTAUDIO_SINT8:
- {
- for ( unsigned int channel = 0; channel < channelCount; channel++ )
- {
- char fromSample = ( ( char* ) inBuffer )[ frameInSample + channel ];
- char toSample = ( ( char* ) inBuffer )[ frameInSample + channelCount + channel ];
- char sampleDiff = ( char ) ( ( toSample - fromSample ) * inSampleDec );
- ( ( char* ) outBuffer )[ frameOutSample + channel ] = fromSample + sampleDiff;
- }
- break;
- }
- case RTAUDIO_SINT16:
- {
- for ( unsigned int channel = 0; channel < channelCount; channel++ )
- {
- short fromSample = ( ( short* ) inBuffer )[ frameInSample + channel ];
- short toSample = ( ( short* ) inBuffer )[ frameInSample + channelCount + channel ];
- short sampleDiff = ( short ) ( ( toSample - fromSample ) * inSampleDec );
- ( ( short* ) outBuffer )[ frameOutSample + channel ] = fromSample + sampleDiff;
- }
- break;
- }
- case RTAUDIO_SINT24:
- {
- for ( unsigned int channel = 0; channel < channelCount; channel++ )
- {
- int fromSample = ( ( S24* ) inBuffer )[ frameInSample + channel ].asInt();
- int toSample = ( ( S24* ) inBuffer )[ frameInSample + channelCount + channel ].asInt();
- int sampleDiff = ( int ) ( ( toSample - fromSample ) * inSampleDec );
- ( ( S24* ) outBuffer )[ frameOutSample + channel ] = fromSample + sampleDiff;
- }
- break;
- }
- case RTAUDIO_SINT32:
- {
- for ( unsigned int channel = 0; channel < channelCount; channel++ )
- {
- int fromSample = ( ( int* ) inBuffer )[ frameInSample + channel ];
- int toSample = ( ( int* ) inBuffer )[ frameInSample + channelCount + channel ];
- int sampleDiff = ( int ) ( ( toSample - fromSample ) * inSampleDec );
- ( ( int* ) outBuffer )[ frameOutSample + channel ] = fromSample + sampleDiff;
- }
- break;
- }
- case RTAUDIO_FLOAT32:
- {
- for ( unsigned int channel = 0; channel < channelCount; channel++ )
- {
- float fromSample = ( ( float* ) inBuffer )[ frameInSample + channel ];
- float toSample = ( ( float* ) inBuffer )[ frameInSample + channelCount + channel ];
- float sampleDiff = ( toSample - fromSample ) * inSampleDec;
- ( ( float* ) outBuffer )[ frameOutSample + channel ] = fromSample + sampleDiff;
- }
- break;
- }
- case RTAUDIO_FLOAT64:
- {
- for ( unsigned int channel = 0; channel < channelCount; channel++ )
- {
- double fromSample = ( ( double* ) inBuffer )[ frameInSample + channel ];
- double toSample = ( ( double* ) inBuffer )[ frameInSample + channelCount + channel ];
- double sampleDiff = ( toSample - fromSample ) * inSampleDec;
- ( ( double* ) outBuffer )[ frameOutSample + channel ] = fromSample + sampleDiff;
- }
- break;
- }
- }
+ unsigned int outputBufferSize = ( unsigned int ) ceilf( inputBufferSize * _sampleRatio ) + ( _bytesPerSample * _channelCount );
+
+ IMFMediaBuffer* rInBuffer;
+ IMFSample* rInSample;
+ BYTE* rInByteBuffer = NULL;
+
+ // 5. Create Sample object from input data
+
+ MFCreateMemoryBuffer( inputBufferSize, &rInBuffer );
+
+ rInBuffer->Lock( &rInByteBuffer, NULL, NULL );
+ memcpy( rInByteBuffer, inBuffer, inputBufferSize );
+ rInBuffer->Unlock();
+ rInByteBuffer = NULL;
+
+ rInBuffer->SetCurrentLength( inputBufferSize );
+
+ MFCreateSample( &rInSample );
+ rInSample->AddBuffer( rInBuffer );
+
+ // 6. Pass input data to Resampler
+
+ _transform->ProcessInput( 0, rInSample, 0 );
+
+ SAFE_RELEASE( rInBuffer );
+ SAFE_RELEASE( rInSample );
+
+ // 7. Perform sample rate conversion
+
+ IMFMediaBuffer* rOutBuffer = NULL;
+ BYTE* rOutByteBuffer = NULL;
+
+ MFT_OUTPUT_DATA_BUFFER rOutDataBuffer;
+ DWORD rStatus;
+ DWORD rBytes = outputBufferSize; // maximum bytes accepted per ProcessOutput
+
+ // 7.1 Create Sample object for output data
+
+ memset( &rOutDataBuffer, 0, sizeof rOutDataBuffer );
+ MFCreateSample( &( rOutDataBuffer.pSample ) );
+ MFCreateMemoryBuffer( rBytes, &rOutBuffer );
+ rOutDataBuffer.pSample->AddBuffer( rOutBuffer );
+ rOutDataBuffer.dwStreamID = 0;
+ rOutDataBuffer.dwStatus = 0;
+ rOutDataBuffer.pEvents = NULL;
+
+ // 7.2 Get output data from Resampler
- // jump to next in sample
- inSampleFraction += sampleStep;
+ if ( _transform->ProcessOutput( 0, 1, &rOutDataBuffer, &rStatus ) == MF_E_TRANSFORM_NEED_MORE_INPUT )
+ {
+ outSampleCount = 0;
+ SAFE_RELEASE( rOutBuffer );
+ SAFE_RELEASE( rOutDataBuffer.pSample );
+ return;
}
+
+ // 7.3 Write output data to outBuffer
+
+ SAFE_RELEASE( rOutBuffer );
+ rOutDataBuffer.pSample->ConvertToContiguousBuffer( &rOutBuffer );
+ rOutBuffer->GetCurrentLength( &rBytes );
+
+ rOutBuffer->Lock( &rOutByteBuffer, NULL, NULL );
+ memcpy( outBuffer, rOutByteBuffer, rBytes );
+ rOutBuffer->Unlock();
+ rOutByteBuffer = NULL;
+
+ outSampleCount = rBytes / _bytesPerSample / _channelCount;
+ SAFE_RELEASE( rOutBuffer );
+ SAFE_RELEASE( rOutDataBuffer.pSample );
}
-}
+
+private:
+ unsigned int _bytesPerSample;
+ unsigned int _channelCount;
+ float _sampleRatio;
+
+ IUnknown* _transformUnk;
+ IMFTransform* _transform;
+ IMFMediaType* _mediaType;
+ IMFMediaType* _inputMediaType;
+ IMFMediaType* _outputMediaType;
+
+ #ifdef __IWMResamplerProps_FWD_DEFINED__
+ IWMResamplerProps* _resamplerProps;
+ #endif
+};
//-----------------------------------------------------------------------------
CLSCTX_ALL, __uuidof( IMMDeviceEnumerator ),
( void** ) &deviceEnumerator_ );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::RtApiWasapi: Unable to instantiate device enumerator";
- error( RtAudioError::DRIVER_ERROR );
- }
+ // If this runs on an old Windows, it will fail. Ignore and proceed.
+ if ( FAILED( hr ) )
+ deviceEnumerator_ = NULL;
}
//-----------------------------------------------------------------------------
IMMDeviceCollection* captureDevices = NULL;
IMMDeviceCollection* renderDevices = NULL;
+ if ( !deviceEnumerator_ )
+ return 0;
+
// Count capture devices
errorText_.clear();
HRESULT hr = deviceEnumerator_->EnumAudioEndpoints( eCapture, DEVICE_STATE_ACTIVE, &captureDevices );
return;
}
+ #if defined( HAVE_GETTIMEOFDAY )
+ gettimeofday( &stream_.lastTickTimestamp, NULL );
+ #endif
+
// update stream state
stream_.state = STREAM_RUNNING;
// Wait for the last buffer to play before stopping.
Sleep( 1000 * stream_.bufferSize / stream_.sampleRate );
- // stop capture client if applicable
- if ( ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient ) {
- HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient->Stop();
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::stopStream: Unable to stop capture stream.";
- error( RtAudioError::DRIVER_ERROR );
- return;
- }
- }
-
- // stop render client if applicable
- if ( ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient ) {
- HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient->Stop();
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::stopStream: Unable to stop render stream.";
- error( RtAudioError::DRIVER_ERROR );
- return;
- }
- }
-
// close thread handle
if ( stream_.callbackInfo.thread && !CloseHandle( ( void* ) stream_.callbackInfo.thread ) ) {
errorText_ = "RtApiWasapi::stopStream: Unable to close callback thread.";
Sleep( 1 );
}
- // stop capture client if applicable
- if ( ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient ) {
- HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient->Stop();
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::abortStream: Unable to stop capture stream.";
- error( RtAudioError::DRIVER_ERROR );
- return;
- }
- }
-
- // stop render client if applicable
- if ( ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient ) {
- HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient->Stop();
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::abortStream: Unable to stop render stream.";
- error( RtAudioError::DRIVER_ERROR );
- return;
- }
- }
-
// close thread handle
if ( stream_.callbackInfo.thread && !CloseHandle( ( void* ) stream_.callbackInfo.thread ) ) {
errorText_ = "RtApiWasapi::abortStream: Unable to close callback thread.";
goto Exit;
}
- // determine whether index falls within capture or render devices
+ // if device index falls within capture devices
if ( device >= renderDeviceCount ) {
if ( mode != INPUT ) {
errorType = RtAudioError::INVALID_USE;
hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL,
NULL, ( void** ) &captureAudioClient );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device audio client.";
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve capture device audio client.";
goto Exit;
}
hr = captureAudioClient->GetMixFormat( &deviceFormat );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device mix format.";
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve capture device mix format.";
goto Exit;
}
stream_.nDeviceChannels[mode] = deviceFormat->nChannels;
captureAudioClient->GetStreamLatency( ( long long* ) &stream_.latency[mode] );
}
- else {
- if ( mode != OUTPUT ) {
- errorType = RtAudioError::INVALID_USE;
- errorText_ = "RtApiWasapi::probeDeviceOpen: Render device selected as input device.";
+
+ // if device index falls within render devices and is configured for loopback
+ if ( device < renderDeviceCount && mode == INPUT )
+ {
+ // if renderAudioClient is not initialised, initialise it now
+ IAudioClient*& renderAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient;
+ if ( !renderAudioClient )
+ {
+ probeDeviceOpen( device, OUTPUT, channels, firstChannel, sampleRate, format, bufferSize, options );
+ }
+
+ // retrieve captureAudioClient from devicePtr
+ IAudioClient*& captureAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient;
+
+ hr = renderDevices->Item( device, &devicePtr );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device handle.";
+ goto Exit;
+ }
+
+ hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL,
+ NULL, ( void** ) &captureAudioClient );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device audio client.";
goto Exit;
}
- // retrieve renderAudioClient from devicePtr
+ hr = captureAudioClient->GetMixFormat( &deviceFormat );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device mix format.";
+ goto Exit;
+ }
+
+ stream_.nDeviceChannels[mode] = deviceFormat->nChannels;
+ captureAudioClient->GetStreamLatency( ( long long* ) &stream_.latency[mode] );
+ }
+
+ // if device index falls within render devices and is configured for output
+ if ( device < renderDeviceCount && mode == OUTPUT )
+ {
+ // if renderAudioClient is already initialised, don't initialise it again
IAudioClient*& renderAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient;
+ if ( renderAudioClient )
+ {
+ methodResult = SUCCESS;
+ goto Exit;
+ }
hr = renderDevices->Item( device, &devicePtr );
if ( FAILED( hr ) ) {
hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL,
NULL, ( void** ) &renderAudioClient );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device audio client.";
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device audio client.";
goto Exit;
}
hr = renderAudioClient->GetMixFormat( &deviceFormat );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device mix format.";
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device mix format.";
goto Exit;
}
// Set flags for buffer conversion.
stream_.doConvertBuffer[mode] = false;
if ( stream_.userFormat != stream_.deviceFormat[mode] ||
- stream_.nUserChannels != stream_.nDeviceChannels )
+ stream_.nUserChannels[0] != stream_.nDeviceChannels[0] ||
+ stream_.nUserChannels[1] != stream_.nDeviceChannels[1] )
stream_.doConvertBuffer[mode] = true;
else if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] &&
stream_.nUserChannels[mode] > 1 )
float renderSrRatio = 0.0f;
WasapiBuffer captureBuffer;
WasapiBuffer renderBuffer;
+ WasapiResampler* captureResampler = NULL;
+ WasapiResampler* renderResampler = NULL;
// declare local stream variables
RtAudioCallback callback = ( RtAudioCallback ) stream_.callbackInfo.callback;
unsigned int bufferFrameCount = 0;
unsigned int numFramesPadding = 0;
unsigned int convBufferSize = 0;
- bool callbackPushed = false;
+ bool loopbackEnabled = stream_.device[INPUT] == stream_.device[OUTPUT];
+ bool callbackPushed = true;
bool callbackPulled = false;
bool callbackStopped = false;
int callbackResult = 0;
unsigned int convBuffSize = 0;
unsigned int deviceBuffSize = 0;
- errorText_.clear();
+ std::string errorText;
RtAudioError::Type errorType = RtAudioError::DRIVER_ERROR;
// Attempt to assign "Pro Audio" characteristic to thread
HMODULE AvrtDll = LoadLibrary( (LPCTSTR) "AVRT.dll" );
if ( AvrtDll ) {
DWORD taskIndex = 0;
- TAvSetMmThreadCharacteristicsPtr AvSetMmThreadCharacteristicsPtr = ( TAvSetMmThreadCharacteristicsPtr ) GetProcAddress( AvrtDll, "AvSetMmThreadCharacteristicsW" );
+ TAvSetMmThreadCharacteristicsPtr AvSetMmThreadCharacteristicsPtr =
+ ( TAvSetMmThreadCharacteristicsPtr ) (void(*)()) GetProcAddress( AvrtDll, "AvSetMmThreadCharacteristicsW" );
AvSetMmThreadCharacteristicsPtr( L"Pro Audio", &taskIndex );
FreeLibrary( AvrtDll );
}
if ( captureAudioClient ) {
hr = captureAudioClient->GetMixFormat( &captureFormat );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve device mix format.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to retrieve device mix format.";
goto Exit;
}
- captureSrRatio = ( ( float ) captureFormat->nSamplesPerSec / stream_.sampleRate );
+ // init captureResampler
+ captureResampler = new WasapiResampler( stream_.deviceFormat[INPUT] == RTAUDIO_FLOAT32 || stream_.deviceFormat[INPUT] == RTAUDIO_FLOAT64,
+ formatBytes( stream_.deviceFormat[INPUT] ) * 8, stream_.nDeviceChannels[INPUT],
+ captureFormat->nSamplesPerSec, stream_.sampleRate );
- // initialize capture stream according to desire buffer size
- float desiredBufferSize = stream_.bufferSize * captureSrRatio;
- REFERENCE_TIME desiredBufferPeriod = ( REFERENCE_TIME ) ( ( float ) desiredBufferSize * 10000000 / captureFormat->nSamplesPerSec );
+ captureSrRatio = ( ( float ) captureFormat->nSamplesPerSec / stream_.sampleRate );
if ( !captureClient ) {
hr = captureAudioClient->Initialize( AUDCLNT_SHAREMODE_SHARED,
- AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
- desiredBufferPeriod,
- desiredBufferPeriod,
+ loopbackEnabled ? AUDCLNT_STREAMFLAGS_LOOPBACK : AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
+ 0,
+ 0,
captureFormat,
NULL );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to initialize capture audio client.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to initialize capture audio client.";
goto Exit;
}
hr = captureAudioClient->GetService( __uuidof( IAudioCaptureClient ),
( void** ) &captureClient );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve capture client handle.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to retrieve capture client handle.";
goto Exit;
}
- // configure captureEvent to trigger on every available capture buffer
- captureEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
- if ( !captureEvent ) {
- errorType = RtAudioError::SYSTEM_ERROR;
- errorText_ = "RtApiWasapi::wasapiThread: Unable to create capture event.";
- goto Exit;
+ // don't configure captureEvent if in loopback mode
+ if ( !loopbackEnabled )
+ {
+ // configure captureEvent to trigger on every available capture buffer
+ captureEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+ if ( !captureEvent ) {
+ errorType = RtAudioError::SYSTEM_ERROR;
+ errorText = "RtApiWasapi::wasapiThread: Unable to create capture event.";
+ goto Exit;
+ }
+
+ hr = captureAudioClient->SetEventHandle( captureEvent );
+ if ( FAILED( hr ) ) {
+ errorText = "RtApiWasapi::wasapiThread: Unable to set capture event handle.";
+ goto Exit;
+ }
+
+ ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent = captureEvent;
}
- hr = captureAudioClient->SetEventHandle( captureEvent );
+ ( ( WasapiHandle* ) stream_.apiHandle )->captureClient = captureClient;
+
+ // reset the capture stream
+ hr = captureAudioClient->Reset();
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to set capture event handle.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to reset capture stream.";
goto Exit;
}
- ( ( WasapiHandle* ) stream_.apiHandle )->captureClient = captureClient;
- ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent = captureEvent;
+ // start the capture stream
+ hr = captureAudioClient->Start();
+ if ( FAILED( hr ) ) {
+ errorText = "RtApiWasapi::wasapiThread: Unable to start capture stream.";
+ goto Exit;
+ }
}
unsigned int inBufferSize = 0;
hr = captureAudioClient->GetBufferSize( &inBufferSize );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to get capture buffer size.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to get capture buffer size.";
goto Exit;
}
// scale outBufferSize according to stream->user sample rate ratio
- unsigned int outBufferSize = ( unsigned int ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT];
+ unsigned int outBufferSize = ( unsigned int ) ceilf( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT];
inBufferSize *= stream_.nDeviceChannels[INPUT];
// set captureBuffer size
captureBuffer.setBufferSize( inBufferSize + outBufferSize, formatBytes( stream_.deviceFormat[INPUT] ) );
-
- // reset the capture stream
- hr = captureAudioClient->Reset();
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to reset capture stream.";
- goto Exit;
- }
-
- // start the capture stream
- hr = captureAudioClient->Start();
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to start capture stream.";
- goto Exit;
- }
}
// start render stream if applicable
if ( renderAudioClient ) {
hr = renderAudioClient->GetMixFormat( &renderFormat );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve device mix format.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to retrieve device mix format.";
goto Exit;
}
- renderSrRatio = ( ( float ) renderFormat->nSamplesPerSec / stream_.sampleRate );
+ // init renderResampler
+ renderResampler = new WasapiResampler( stream_.deviceFormat[OUTPUT] == RTAUDIO_FLOAT32 || stream_.deviceFormat[OUTPUT] == RTAUDIO_FLOAT64,
+ formatBytes( stream_.deviceFormat[OUTPUT] ) * 8, stream_.nDeviceChannels[OUTPUT],
+ stream_.sampleRate, renderFormat->nSamplesPerSec );
- // initialize render stream according to desire buffer size
- float desiredBufferSize = stream_.bufferSize * renderSrRatio;
- REFERENCE_TIME desiredBufferPeriod = ( REFERENCE_TIME ) ( ( float ) desiredBufferSize * 10000000 / renderFormat->nSamplesPerSec );
+ renderSrRatio = ( ( float ) renderFormat->nSamplesPerSec / stream_.sampleRate );
if ( !renderClient ) {
hr = renderAudioClient->Initialize( AUDCLNT_SHAREMODE_SHARED,
AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
- desiredBufferPeriod,
- desiredBufferPeriod,
+ 0,
+ 0,
renderFormat,
NULL );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to initialize render audio client.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to initialize render audio client.";
goto Exit;
}
hr = renderAudioClient->GetService( __uuidof( IAudioRenderClient ),
( void** ) &renderClient );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render client handle.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to retrieve render client handle.";
goto Exit;
}
renderEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
if ( !renderEvent ) {
errorType = RtAudioError::SYSTEM_ERROR;
- errorText_ = "RtApiWasapi::wasapiThread: Unable to create render event.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to create render event.";
goto Exit;
}
hr = renderAudioClient->SetEventHandle( renderEvent );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to set render event handle.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to set render event handle.";
goto Exit;
}
( ( WasapiHandle* ) stream_.apiHandle )->renderClient = renderClient;
( ( WasapiHandle* ) stream_.apiHandle )->renderEvent = renderEvent;
+
+ // reset the render stream
+ hr = renderAudioClient->Reset();
+ if ( FAILED( hr ) ) {
+ errorText = "RtApiWasapi::wasapiThread: Unable to reset render stream.";
+ goto Exit;
+ }
+
+ // start the render stream
+ hr = renderAudioClient->Start();
+ if ( FAILED( hr ) ) {
+ errorText = "RtApiWasapi::wasapiThread: Unable to start render stream.";
+ goto Exit;
+ }
}
unsigned int outBufferSize = 0;
hr = renderAudioClient->GetBufferSize( &outBufferSize );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to get render buffer size.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to get render buffer size.";
goto Exit;
}
// scale inBufferSize according to user->stream sample rate ratio
- unsigned int inBufferSize = ( unsigned int ) ( stream_.bufferSize * renderSrRatio ) * stream_.nDeviceChannels[OUTPUT];
+ unsigned int inBufferSize = ( unsigned int ) ceilf( stream_.bufferSize * renderSrRatio ) * stream_.nDeviceChannels[OUTPUT];
outBufferSize *= stream_.nDeviceChannels[OUTPUT];
// set renderBuffer size
renderBuffer.setBufferSize( inBufferSize + outBufferSize, formatBytes( stream_.deviceFormat[OUTPUT] ) );
-
- // reset the render stream
- hr = renderAudioClient->Reset();
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to reset render stream.";
- goto Exit;
- }
-
- // start the render stream
- hr = renderAudioClient->Start();
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to start render stream.";
- goto Exit;
- }
}
- if ( stream_.mode == INPUT ) {
- convBuffSize = ( size_t ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] );
+ // malloc buffer memory
+ if ( stream_.mode == INPUT )
+ {
+ using namespace std; // for ceilf
+ convBuffSize = ( size_t ) ( ceilf( stream_.bufferSize * captureSrRatio ) ) * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] );
deviceBuffSize = stream_.bufferSize * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] );
}
- else if ( stream_.mode == OUTPUT ) {
- convBuffSize = ( size_t ) ( stream_.bufferSize * renderSrRatio ) * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] );
+ else if ( stream_.mode == OUTPUT )
+ {
+ convBuffSize = ( size_t ) ( ceilf( stream_.bufferSize * renderSrRatio ) ) * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] );
deviceBuffSize = stream_.bufferSize * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] );
}
- else if ( stream_.mode == DUPLEX ) {
- convBuffSize = std::max( ( size_t ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] ),
- ( size_t ) ( stream_.bufferSize * renderSrRatio ) * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] ) );
+ else if ( stream_.mode == DUPLEX )
+ {
+ convBuffSize = std::max( ( size_t ) ( ceilf( stream_.bufferSize * captureSrRatio ) ) * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] ),
+ ( size_t ) ( ceilf( stream_.bufferSize * renderSrRatio ) ) * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] ) );
deviceBuffSize = std::max( stream_.bufferSize * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] ),
stream_.bufferSize * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] ) );
}
- convBuffer = ( char* ) malloc( convBuffSize );
- stream_.deviceBuffer = ( char* ) malloc( deviceBuffSize );
+ convBuffSize *= 2; // allow overflow for *SrRatio remainders
+ convBuffer = ( char* ) calloc( convBuffSize, 1 );
+ stream_.deviceBuffer = ( char* ) calloc( deviceBuffSize, 1 );
if ( !convBuffer || !stream_.deviceBuffer ) {
errorType = RtAudioError::MEMORY_ERROR;
- errorText_ = "RtApiWasapi::wasapiThread: Error allocating device buffer memory.";
+ errorText = "RtApiWasapi::wasapiThread: Error allocating device buffer memory.";
goto Exit;
}
// 2. If 1. was successful: Convert callback buffer to user sample rate and channel count
// Convert callback buffer to user format
- if ( captureAudioClient ) {
- // Pull callback buffer from inputBuffer
- callbackPulled = captureBuffer.pullBuffer( convBuffer,
- ( unsigned int ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT],
- stream_.deviceFormat[INPUT] );
+ if ( captureAudioClient )
+ {
+ int samplesToPull = ( unsigned int ) floorf( stream_.bufferSize * captureSrRatio );
+ if ( captureSrRatio != 1 )
+ {
+ // account for remainders
+ samplesToPull--;
+ }
+
+ convBufferSize = 0;
+ while ( convBufferSize < stream_.bufferSize )
+ {
+ // Pull callback buffer from inputBuffer
+ callbackPulled = captureBuffer.pullBuffer( convBuffer,
+ samplesToPull * stream_.nDeviceChannels[INPUT],
+ stream_.deviceFormat[INPUT] );
+
+ if ( !callbackPulled )
+ {
+ break;
+ }
- if ( callbackPulled ) {
// Convert callback buffer to user sample rate
- convertBufferWasapi( stream_.deviceBuffer,
- convBuffer,
- stream_.nDeviceChannels[INPUT],
- captureFormat->nSamplesPerSec,
- stream_.sampleRate,
- ( unsigned int ) ( stream_.bufferSize * captureSrRatio ),
- convBufferSize,
- stream_.deviceFormat[INPUT] );
+ unsigned int deviceBufferOffset = convBufferSize * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] );
+ unsigned int convSamples = 0;
+
+ captureResampler->Convert( stream_.deviceBuffer + deviceBufferOffset,
+ convBuffer,
+ samplesToPull,
+ convSamples );
+ convBufferSize += convSamples;
+ samplesToPull = 1; // now pull one sample at a time until we have stream_.bufferSize samples
+ }
+
+ if ( callbackPulled )
+ {
if ( stream_.doConvertBuffer[INPUT] ) {
// Convert callback buffer to user format
convertBuffer( stream_.userBuffer[INPUT],
HANDLE threadHandle = CreateThread( NULL, 0, stopWasapiThread, this, 0, NULL );
if ( !threadHandle ) {
errorType = RtAudioError::THREAD_ERROR;
- errorText_ = "RtApiWasapi::wasapiThread: Unable to instantiate stream stop thread.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to instantiate stream stop thread.";
goto Exit;
}
else if ( !CloseHandle( threadHandle ) ) {
errorType = RtAudioError::THREAD_ERROR;
- errorText_ = "RtApiWasapi::wasapiThread: Unable to close stream stop thread handle.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to close stream stop thread handle.";
goto Exit;
}
HANDLE threadHandle = CreateThread( NULL, 0, abortWasapiThread, this, 0, NULL );
if ( !threadHandle ) {
errorType = RtAudioError::THREAD_ERROR;
- errorText_ = "RtApiWasapi::wasapiThread: Unable to instantiate stream abort thread.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to instantiate stream abort thread.";
goto Exit;
}
else if ( !CloseHandle( threadHandle ) ) {
errorType = RtAudioError::THREAD_ERROR;
- errorText_ = "RtApiWasapi::wasapiThread: Unable to close stream abort thread handle.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to close stream abort thread handle.";
goto Exit;
}
// 2. Convert callback buffer to stream sample rate and channel count
// 3. Push callback buffer into outputBuffer
- if ( renderAudioClient && callbackPulled ) {
- if ( stream_.doConvertBuffer[OUTPUT] ) {
- // Convert callback buffer to stream format
- convertBuffer( stream_.deviceBuffer,
- stream_.userBuffer[OUTPUT],
- stream_.convertInfo[OUTPUT] );
+ if ( renderAudioClient && callbackPulled )
+ {
+ // if the last call to renderBuffer.PushBuffer() was successful
+ if ( callbackPushed || convBufferSize == 0 )
+ {
+ if ( stream_.doConvertBuffer[OUTPUT] )
+ {
+ // Convert callback buffer to stream format
+ convertBuffer( stream_.deviceBuffer,
+ stream_.userBuffer[OUTPUT],
+ stream_.convertInfo[OUTPUT] );
- }
+ }
+ else {
+ // no further conversion, simple copy userBuffer to deviceBuffer
+ memcpy( stream_.deviceBuffer,
+ stream_.userBuffer[OUTPUT],
+ stream_.bufferSize * stream_.nUserChannels[OUTPUT] * formatBytes( stream_.userFormat ) );
+ }
- // Convert callback buffer to stream sample rate
- convertBufferWasapi( convBuffer,
- stream_.deviceBuffer,
- stream_.nDeviceChannels[OUTPUT],
- stream_.sampleRate,
- renderFormat->nSamplesPerSec,
- stream_.bufferSize,
- convBufferSize,
- stream_.deviceFormat[OUTPUT] );
+ // Convert callback buffer to stream sample rate
+ renderResampler->Convert( convBuffer,
+ stream_.deviceBuffer,
+ stream_.bufferSize,
+ convBufferSize );
+ }
// Push callback buffer into outputBuffer
callbackPushed = renderBuffer.pushBuffer( convBuffer,
if ( captureAudioClient ) {
// if the callback input buffer was not pulled from captureBuffer, wait for next capture event
if ( !callbackPulled ) {
- WaitForSingleObject( captureEvent, INFINITE );
+ WaitForSingleObject( loopbackEnabled ? renderEvent : captureEvent, INFINITE );
}
// Get capture buffer from stream
&bufferFrameCount,
&captureFlags, NULL, NULL );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve capture buffer.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to retrieve capture buffer.";
goto Exit;
}
// Release capture buffer
hr = captureClient->ReleaseBuffer( bufferFrameCount );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to release capture buffer.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to release capture buffer.";
goto Exit;
}
}
// Inform WASAPI that capture was unsuccessful
hr = captureClient->ReleaseBuffer( 0 );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to release capture buffer.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to release capture buffer.";
goto Exit;
}
}
// Inform WASAPI that capture was unsuccessful
hr = captureClient->ReleaseBuffer( 0 );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to release capture buffer.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to release capture buffer.";
goto Exit;
}
}
// Get render buffer from stream
hr = renderAudioClient->GetBufferSize( &bufferFrameCount );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer size.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer size.";
goto Exit;
}
hr = renderAudioClient->GetCurrentPadding( &numFramesPadding );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer padding.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer padding.";
goto Exit;
}
if ( bufferFrameCount != 0 ) {
hr = renderClient->GetBuffer( bufferFrameCount, &streamBuffer );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer.";
goto Exit;
}
// Release render buffer
hr = renderClient->ReleaseBuffer( bufferFrameCount, 0 );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to release render buffer.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to release render buffer.";
goto Exit;
}
}
// Inform WASAPI that render was unsuccessful
hr = renderClient->ReleaseBuffer( 0, 0 );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to release render buffer.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to release render buffer.";
goto Exit;
}
}
// Inform WASAPI that render was unsuccessful
hr = renderClient->ReleaseBuffer( 0, 0 );
if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to release render buffer.";
+ errorText = "RtApiWasapi::wasapiThread: Unable to release render buffer.";
goto Exit;
}
}
// if the callback buffer was pushed renderBuffer reset callbackPulled flag
if ( callbackPushed ) {
+ // unsetting the callbackPulled flag lets the stream know that
+ // the audio device is ready for another callback output buffer.
callbackPulled = false;
+
// tick stream time
RtApi::tickStreamTime();
}
CoTaskMemFree( renderFormat );
free ( convBuffer );
+ delete renderResampler;
+ delete captureResampler;
CoUninitialize();
// update stream state
stream_.state = STREAM_STOPPED;
- if ( errorText_.empty() )
- return;
- else
+ if ( !errorText.empty() )
+ {
+ errorText_ = errorText;
error( errorType );
+ }
}
//******************** End of __WINDOWS_WASAPI__ *********************//
// Various revisions for RtAudio 4.0 by Gary Scavone, April 2007
// Changed device query structure for RtAudio 4.0.7, January 2010
+#include <windows.h>
+#include <process.h>
#include <mmsystem.h>
#include <mmreg.h>
#include <dsound.h>
return;
}
+ #if defined( HAVE_GETTIMEOFDAY )
+ gettimeofday( &stream_.lastTickTimestamp, NULL );
+ #endif
+
DsHandle *handle = (DsHandle *) stream_.apiHandle;
// Increase scheduler frequency on lesser windows (a side-effect of
if ( result == 0 ) {
if ( nDevices == device ) {
strcpy( name, "default" );
+ snd_ctl_close( chandle );
goto foundDevice;
}
nDevices++;
}
+ snd_ctl_close( chandle );
if ( nDevices == 0 ) {
// This should not happen because a check is made before this function is called.
pthread_attr_t attr;
pthread_attr_init( &attr );
pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE );
-
-#ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread)
+#ifdef SCHED_RR // Undefined with some OSes (e.g. NetBSD 1.6.x with GNU Pthread)
if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME ) {
- // We previously attempted to increase the audio callback priority
- // to SCHED_RR here via the attributes. However, while no errors
- // were reported in doing so, it did not work. So, now this is
- // done in the alsaCallbackHandler function.
stream_.callbackInfo.doRealtime = true;
+ struct sched_param param;
int priority = options->priority;
int min = sched_get_priority_min( SCHED_RR );
int max = sched_get_priority_max( SCHED_RR );
if ( priority < min ) priority = min;
else if ( priority > max ) priority = max;
- stream_.callbackInfo.priority = priority;
+ param.sched_priority = priority;
+
+ // Set the policy BEFORE the priority. Otherwise it fails.
+ pthread_attr_setschedpolicy(&attr, SCHED_RR);
+ pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM);
+ // This is definitely required. Otherwise it fails.
+ pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
+ pthread_attr_setschedparam(&attr, ¶m);
}
+ else
+ pthread_attr_setschedpolicy( &attr, SCHED_OTHER );
+#else
+ pthread_attr_setschedpolicy( &attr, SCHED_OTHER );
#endif
stream_.callbackInfo.isRunning = true;
result = pthread_create( &stream_.callbackInfo.thread, &attr, alsaCallbackHandler, &stream_.callbackInfo );
pthread_attr_destroy( &attr );
if ( result ) {
- stream_.callbackInfo.isRunning = false;
- errorText_ = "RtApiAlsa::error creating callback thread!";
- goto error;
+ // Failed. Try instead with default attributes.
+ result = pthread_create( &stream_.callbackInfo.thread, NULL, alsaCallbackHandler, &stream_.callbackInfo );
+ if ( result ) {
+ stream_.callbackInfo.isRunning = false;
+ errorText_ = "RtApiAlsa::error creating callback thread!";
+ goto error;
+ }
}
}
MUTEX_LOCK( &stream_.mutex );
+ #if defined( HAVE_GETTIMEOFDAY )
+ gettimeofday( &stream_.lastTickTimestamp, NULL );
+ #endif
+
int result = 0;
snd_pcm_state_t state;
AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
RtApiAlsa *object = (RtApiAlsa *) info->object;
bool *isRunning = &info->isRunning;
-#ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread)
+#ifdef SCHED_RR // Undefined with some OSes (e.g. NetBSD 1.6.x with GNU Pthread)
if ( info->doRealtime ) {
- pthread_t tID = pthread_self(); // ID of this thread
- sched_param prio = { info->priority }; // scheduling priority of thread
- pthread_setschedparam( tID, SCHED_RR, &prio );
+ std::cerr << "RtAudio alsa: " <<
+ (sched_getscheduler(0) == SCHED_RR ? "" : "_NOT_ ") <<
+ "running realtime scheduling" << std::endl;
}
#endif
CallbackInfo *cbi = static_cast<CallbackInfo *>( user );
RtApiPulse *context = static_cast<RtApiPulse *>( cbi->object );
volatile bool *isRunning = &cbi->isRunning;
-
+
+#ifdef SCHED_RR // Undefined with some OSes (e.g. NetBSD 1.6.x with GNU Pthread)
+ if (cbi->doRealtime) {
+ std::cerr << "RtAudio pulse: " <<
+ (sched_getscheduler(0) == SCHED_RR ? "" : "_NOT_ ") <<
+ "running realtime scheduling" << std::endl;
+ }
+#endif
+
while ( *isRunning ) {
pthread_testcancel();
context->callbackEvent();
MUTEX_LOCK( &stream_.mutex );
+ #if defined( HAVE_GETTIMEOFDAY )
+ gettimeofday( &stream_.lastTickTimestamp, NULL );
+ #endif
+
stream_.state = STREAM_RUNNING;
pah->runnable = true;
if ( !stream_.callbackInfo.isRunning ) {
stream_.callbackInfo.object = this;
+
+ stream_.state = STREAM_STOPPED;
+ // Set the thread attributes for joinable and realtime scheduling
+ // priority (optional). The higher priority will only take affect
+ // if the program is run as root or suid. Note, under Linux
+ // processes with CAP_SYS_NICE privilege, a user can change
+ // scheduling policy and priority (thus need not be root). See
+ // POSIX "capabilities".
+ pthread_attr_t attr;
+ pthread_attr_init( &attr );
+ pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE );
+#ifdef SCHED_RR // Undefined with some OSes (e.g. NetBSD 1.6.x with GNU Pthread)
+ if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME ) {
+ stream_.callbackInfo.doRealtime = true;
+ struct sched_param param;
+ int priority = options->priority;
+ int min = sched_get_priority_min( SCHED_RR );
+ int max = sched_get_priority_max( SCHED_RR );
+ if ( priority < min ) priority = min;
+ else if ( priority > max ) priority = max;
+ param.sched_priority = priority;
+
+ // Set the policy BEFORE the priority. Otherwise it fails.
+ pthread_attr_setschedpolicy(&attr, SCHED_RR);
+ pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM);
+ // This is definitely required. Otherwise it fails.
+ pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
+ pthread_attr_setschedparam(&attr, ¶m);
+ }
+ else
+ pthread_attr_setschedpolicy( &attr, SCHED_OTHER );
+#else
+ pthread_attr_setschedpolicy( &attr, SCHED_OTHER );
+#endif
+
stream_.callbackInfo.isRunning = true;
- if ( pthread_create( &pah->thread, NULL, pulseaudio_callback, (void *)&stream_.callbackInfo) != 0 ) {
- errorText_ = "RtApiPulse::probeDeviceOpen: error creating thread.";
- goto error;
+ int result = pthread_create( &pah->thread, &attr, pulseaudio_callback, (void *)&stream_.callbackInfo);
+ pthread_attr_destroy(&attr);
+ if(result != 0) {
+ // Failed. Try instead with default attributes.
+ result = pthread_create( &pah->thread, NULL, pulseaudio_callback, (void *)&stream_.callbackInfo);
+ if(result != 0) {
+ stream_.callbackInfo.isRunning = false;
+ errorText_ = "RtApiPulse::probeDeviceOpen: error creating thread.";
+ goto error;
+ }
}
}
- stream_.state = STREAM_STOPPED;
- return true;
+ return SUCCESS;
error:
if ( pah && stream_.callbackInfo.isRunning ) {
stream_.deviceBuffer = 0;
}
+ stream_.state = STREAM_CLOSED;
return FAILURE;
}
pthread_attr_t attr;
pthread_attr_init( &attr );
pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE );
-#ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread)
+#ifdef SCHED_RR // Undefined with some OSes (e.g. NetBSD 1.6.x with GNU Pthread)
if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME ) {
+ stream_.callbackInfo.doRealtime = true;
struct sched_param param;
int priority = options->priority;
int min = sched_get_priority_min( SCHED_RR );
if ( priority < min ) priority = min;
else if ( priority > max ) priority = max;
param.sched_priority = priority;
- pthread_attr_setschedparam( &attr, ¶m );
- pthread_attr_setschedpolicy( &attr, SCHED_RR );
+
+ // Set the policy BEFORE the priority. Otherwise it fails.
+ pthread_attr_setschedpolicy(&attr, SCHED_RR);
+ pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM);
+ // This is definitely required. Otherwise it fails.
+ pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
+ pthread_attr_setschedparam(&attr, ¶m);
}
else
pthread_attr_setschedpolicy( &attr, SCHED_OTHER );
result = pthread_create( &stream_.callbackInfo.thread, &attr, ossCallbackHandler, &stream_.callbackInfo );
pthread_attr_destroy( &attr );
if ( result ) {
- stream_.callbackInfo.isRunning = false;
- errorText_ = "RtApiOss::error creating callback thread!";
- goto error;
+ // Failed. Try instead with default attributes.
+ result = pthread_create( &stream_.callbackInfo.thread, NULL, ossCallbackHandler, &stream_.callbackInfo );
+ if ( result ) {
+ stream_.callbackInfo.isRunning = false;
+ errorText_ = "RtApiOss::error creating callback thread!";
+ goto error;
+ }
}
}
stream_.deviceBuffer = 0;
}
+ stream_.state = STREAM_CLOSED;
return FAILURE;
}
MUTEX_LOCK( &stream_.mutex );
+ #if defined( HAVE_GETTIMEOFDAY )
+ gettimeofday( &stream_.lastTickTimestamp, NULL );
+ #endif
+
stream_.state = STREAM_RUNNING;
// No need to do anything else here ... OSS automatically starts
RtApiOss *object = (RtApiOss *) info->object;
bool *isRunning = &info->isRunning;
+#ifdef SCHED_RR // Undefined with some OSes (e.g. NetBSD 1.6.x with GNU Pthread)
+ if (info->doRealtime) {
+ std::cerr << "RtAudio oss: " <<
+ (sched_getscheduler(0) == SCHED_RR ? "" : "_NOT_ ") <<
+ "running realtime scheduling" << std::endl;
+ }
+#endif
+
while ( *isRunning == true ) {
pthread_testcancel();
object->callbackEvent();
#define RTAUDIO_VERSION "5.0.0"
+#if defined _WIN32 || defined __CYGWIN__
+ #if defined(RTAUDIO_EXPORT)
+ #define RTAUDIO_DLL_PUBLIC __declspec(dllexport)
+ #else
+ #define RTAUDIO_DLL_PUBLIC
+ #endif
+#else
+ #if __GNUC__ >= 4
+ #define RTAUDIO_DLL_PUBLIC __attribute__( (visibility( "default" )) )
+ #else
+ #define RTAUDIO_DLL_PUBLIC
+ #endif
+#endif
+
#include <string>
#include <vector>
#include <stdexcept>
Certain audio APIs offer a number of parameters that influence the
I/O latency of a stream. By default, RtAudio will attempt to set
these parameters internally for robust (glitch-free) performance
- (though some APIs, like Windows Direct Sound, make this difficult).
+ (though some APIs, like Windows DirectSound, make this difficult).
By passing the RTAUDIO_MINIMIZE_LATENCY flag to the openStream()
function, internal stream settings will be influenced in an attempt
to minimize stream latency, though possibly at the expense of stream
*/
/************************************************************************/
-class RtAudioError : public std::runtime_error
+class RTAUDIO_DLL_PUBLIC RtAudioError : public std::runtime_error
{
public:
//! Defined RtAudioError types.
class RtApi;
-class RtAudio
+class RTAUDIO_DLL_PUBLIC RtAudio
{
public:
MACOSX_CORE, /*!< Macintosh OS-X Core Audio API. */
WINDOWS_WASAPI, /*!< The Microsoft WASAPI API. */
WINDOWS_ASIO, /*!< The Steinberg Audio Stream I/O API. */
- WINDOWS_DS, /*!< The Microsoft Direct Sound API. */
- RTAUDIO_DUMMY /*!< A compilable but non-functional API. */
+ WINDOWS_DS, /*!< The Microsoft DirectSound API. */
+ RTAUDIO_DUMMY, /*!< A compilable but non-functional API. */
+ NUM_APIS /*!< Number of values in this enum. */
};
//! The public device information structure for returning queried values.
bool isDefaultOutput; /*!< true if this is the default output device. */
bool isDefaultInput; /*!< true if this is the default input device. */
std::vector<unsigned int> sampleRates; /*!< Supported sample rates (queried from list of standard rates). */
- unsigned int preferredSampleRate; /*!< Preferred sample rate, eg. for WASAPI the system sample rate. */
+ unsigned int preferredSampleRate; /*!< Preferred sample rate, e.g. for WASAPI the system sample rate. */
RtAudioFormat nativeFormats; /*!< Bit mask of supported data formats. */
// Default constructor.
Certain audio APIs offer a number of parameters that influence the
I/O latency of a stream. By default, RtAudio will attempt to set
these parameters internally for robust (glitch-free) performance
- (though some APIs, like Windows Direct Sound, make this difficult).
+ (though some APIs, like Windows DirectSound, make this difficult).
By passing the RTAUDIO_MINIMIZE_LATENCY flag to the openStream()
function, internal stream settings will be influenced in an attempt
to minimize stream latency, though possibly at the expense of stream
*/
static void getCompiledApi( std::vector<RtAudio::Api> &apis );
+ //! Return the name of a specified compiled audio API.
+ /*!
+ This obtains a short lower-case name used for identification purposes.
+ This value is guaranteed to remain identical across library versions.
+ If the API is unknown, this function will return the empty string.
+ */
+ static std::string getApiName( RtAudio::Api api );
+
+ //! Return the display name of a specified compiled audio API.
+ /*!
+ This obtains a long name used for display purposes.
+ If the API is unknown, this function will return the empty string.
+ */
+ static std::string getApiDisplayName( RtAudio::Api api );
+
+ //! Return the compiled audio API having the given name.
+ /*!
+ A case insensitive comparison will check the specified name
+ against the list of compiled APIs, and return the one which
+ matches. On failure, the function returns UNSPECIFIED.
+ */
+ static RtAudio::Api getCompiledApiByName( const std::string &name );
+
//! The class constructor.
/*!
The constructor performs minor initialization tasks. An exception
#endif
#include <windows.h>
#include <process.h>
+ #include <stdint.h>
typedef uintptr_t ThreadHandle;
typedef CRITICAL_SECTION StreamMutex;
return *this;
}
- S24( const S24& v ) { *this = v; }
S24( const double& d ) { *this = (int) d; }
S24( const float& f ) { *this = (int) f; }
S24( const signed short& s ) { *this = (int) s; }
#include <sstream>
-class RtApi
+class RTAUDIO_DLL_PUBLIC RtApi
{
public:
void startStream( void );
void stopStream( void );
void abortStream( void );
- long getStreamLatency( void );
// This function is intended for internal use only. It must be
// public because it is called by the internal callback handler,
void startStream( void );
void stopStream( void );
void abortStream( void );
- long getStreamLatency( void );
// This function is intended for internal use only. It must be
// public because it is called by the internal callback handler,
void startStream( void );
void stopStream( void );
void abortStream( void );
- long getStreamLatency( void );
// This function is intended for internal use only. It must be
// public because it is called by the internal callback handler,
void startStream( void );
void stopStream( void );
void abortStream( void );
- long getStreamLatency( void );
// This function is intended for internal use only. It must be
// public because it is called by the internal callback handler,
{
public:
RtApiWasapi();
- ~RtApiWasapi();
+ virtual ~RtApiWasapi();
RtAudio::Api getCurrentApi( void ) { return RtAudio::WINDOWS_WASAPI; }
unsigned int getDeviceCount( void );
--- /dev/null
+if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+ message(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"")
+endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+
+file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
+string(REGEX REPLACE "\n" ";" files "${files}")
+foreach(file ${files})
+ message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"")
+ if(EXISTS "$ENV{DESTDIR}${file}")
+ exec_program(
+ "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
+ OUTPUT_VARIABLE rm_out
+ RETURN_VALUE rm_retval
+ )
+ if(NOT "${rm_retval}" STREQUAL 0)
+ message(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"")
+ endif(NOT "${rm_retval}" STREQUAL 0)
+ else(EXISTS "$ENV{DESTDIR}${file}")
+ message(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.")
+ endif(EXISTS "$ENV{DESTDIR}${file}")
+endforeach(file)
SO_VERSION=lt_version_info
AC_SUBST(SO_VERSION)
+AC_SUBST(api)
+AC_SUBST(req)
+AC_SUBST(visibility)
+
+api=""
+req=""
+use_asio=""
+
+
+# configure flags
+AC_ARG_ENABLE(debug, [AS_HELP_STRING([--enable-debug],[enable various debug output])])
+AC_ARG_WITH(jack, [AS_HELP_STRING([--with-jack], [choose JACK server support])])
+AC_ARG_WITH(alsa, [AS_HELP_STRING([--with-alsa], [choose native ALSA API support (linux only)])])
+AC_ARG_WITH(pulse, [AS_HELP_STRING([--with-pulse], [choose PulseAudio API support (unixes)])])
+AC_ARG_WITH(oss, [AS_HELP_STRING([--with-oss], [choose OSS API support (unixes)])])
+AC_ARG_WITH(core, [AS_HELP_STRING([--with-core], [choose CoreAudio API support (mac only)])])
+AC_ARG_WITH(asio, [AS_HELP_STRING([--with-asio], [choose ASIO API support (win32 only)])])
+AC_ARG_WITH(ds, [AS_HELP_STRING([--with-ds], [choose DirectSound API support (win32 only)])])
+AC_ARG_WITH(wasapi, [AS_HELP_STRING([--with-wasapi], [choose Windows Audio Session API support (win32 only)])])
# Check version number coherency between RtAudio.h and configure.ac
AC_MSG_CHECKING([that version numbers are coherent])
-AC_RUN_IFELSE(
- [AC_LANG_PROGRAM([#include <string.h>
- `grep "define RTAUDIO_VERSION" $srcdir/RtAudio.h`],
- [return strcmp(RTAUDIO_VERSION, PACKAGE_VERSION);])],
- [AC_MSG_RESULT([yes])],
- [AC_MSG_FAILURE([testing RTAUDIO_VERSION==PACKAGE_VERSION failed, check that RtAudio.h defines RTAUDIO_VERSION as "$PACKAGE_VERSION" or that the first line of configure.ac has been updated.])])
-
+RTAUDIO_VERSION=`sed -n 's/#define RTAUDIO_VERSION "\(.*\)"/\1/p' $srcdir/RtAudio.h`
+AS_IF([test "x$RTAUDIO_VERSION" != "x$PACKAGE_VERSION"],[
+ AC_MSG_RESULT([no])
+ AC_MSG_FAILURE([testing RTAUDIO_VERSION==PACKAGE_VERSION failed, check that RtAudio.h defines RTAUDIO_VERSION as "$PACKAGE_VERSION" or that the first line of configure.ac has been updated.])
+ ],[
+ AC_MSG_RESULT([yes])
+])
# Enable some nice automake features if they are available
m4_ifdef([AM_MAINTAINER_MODE], [AM_MAINTAINER_MODE])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
# Fill GXX with something before test.
-AC_SUBST( GXX, ["no"] )
-
-dnl Check for pkg-config program, used for configuring some libraries.
-m4_define_default([PKG_PROG_PKG_CONFIG],
-[AC_MSG_CHECKING([pkg-config])
-AC_MSG_RESULT([no])])
-
-PKG_PROG_PKG_CONFIG
-
-dnl If the pkg-config autoconf support isn't installed, define its
-dnl autoconf macro to disable any packages depending on it.
-m4_define_default([PKG_CHECK_MODULES],
-[AC_MSG_CHECKING([$1])
-AC_MSG_RESULT([no])
-$4])
-
-# Check for debug
-AC_MSG_CHECKING(whether to compile debug version)
-AC_ARG_ENABLE(debug,
- [AS_HELP_STRING([--enable-debug],[enable various debug output])],
- [: ${CXXFLAGS="-g -O0"};] [AC_DEFINE([__RTAUDIO_DEBUG__])],
- [: ${CXXFLAGS="-O3"}])
+GXX="no"
+# if the user did not provide any CXXFLAGS, we can override them
+AS_IF([test "x$CXXFLAGS" = "x" ], [override_cxx=yes], [override_cxx=no])
+AS_IF([test "x$CFLAGS" = "x" ], [override_c=yes], [override_c=no])
# Checks for programs.
AC_PROG_CXX(g++ CC c++ cxx)
AM_PROG_AR
AC_PATH_PROG(AR, ar, no)
-if [[ $AR = "no" ]] ; then
- AC_MSG_ERROR("Could not find ar - needed to create a library");
-fi
+AS_IF([test "x${AR}" = "xno" ], [
+ AC_MSG_ERROR([Could not find ar - needed to create a library])
+])
# Initialize libtool
LT_INIT([win32-dll])
AC_CHECK_HEADERS(sys/ioctl.h unistd.h)
# Check compiler and use -Wall if gnu
-if test x"$GXX" = "xyes"; then
- CXXFLAGS="${CXXFLAGS} -Wall -Wextra"
- # Add -Werror in debug mode
- if test x"${enable_debug+set}" = xset; then
- CXXFLAGS="${CXXFLAGS} -Werror"
- fi
-fi
+AS_IF([test "x${GXX}" = "xyes" ], [
+ CXXFLAGS="-Wall -Wextra ${CXXFLAGS}"
+ AS_IF([ test "x${enable_debug}" = "xyes" ], [
+ # Add -Werror in debug mode (except unused-function)
+ CXXFLAGS="-Werror -Wno-error=unused-function ${CXXFLAGS}"
+ ], [
+ # hide private symbols in non-debug mode
+ visibility="-fvisibility=hidden"
+ ])
+])
+
+# Check for debug
+AC_MSG_CHECKING([whether to compile debug version])
+debugflags=""
+AS_CASE([${enable_debug}],
+ [ yes ], [
+ AC_MSG_RESULT([yes])
+ AC_DEFINE([__RTAUDIO_DEBUG__])
+ debugflags="${debugflags} -g -O0"
+ object_path=Debug
+ ],
+ [ no ], [
+ AC_MSG_RESULT([no!])
+ debugflags="${debugflags} -O3"
+ ], [
+ AC_MSG_RESULT([no])
+ ])
+
+# For debugging and optimization ... overwrite default because it has both -g and -O2
+AS_IF([test "x$debugflags" != x],
+ AS_IF([test "x$override_cxx" = "xyes" ], CXXFLAGS="$CXXFLAGS $debugflags", CXXFLAGS="$debugflags $CXXFLAGS")
+ AS_IF([test "x$override_c" = "xyes" ], CFLAGS="$CFLAGS $debugflags", CFLAGS="$debugflags $CFLAGS")
+ )
+
# Checks for functions
AC_CHECK_FUNC(gettimeofday, [cppflag="$cppflag -DHAVE_GETTIMEOFDAY"], )
# Checks for doxygen
AC_CHECK_PROG( DOXYGEN, [doxygen], [doxygen] )
-AM_CONDITIONAL( MAKE_DOC, [test "x${DOXYGEN}" != x] )
+AM_CONDITIONAL( MAKE_DOC, [test "x${DOXYGEN}" != x ] )
# Copy doc files to build dir if necessary
AC_CONFIG_LINKS( [doc/release.txt:doc/release.txt] )
# Checks for package options and external software
AC_CANONICAL_HOST
-AC_SUBST( api, [""] )
-AC_SUBST( req, [""] )
-AC_MSG_CHECKING(for audio API)
-
-AC_ARG_WITH(jack, [ --with-jack = choose JACK server support (mac and linux only)])
-AS_IF([test "x$with_jack" == "xyes"], [
- api="$api -D__UNIX_JACK__"
- AC_MSG_RESULT(using JACK)
- AC_CHECK_LIB(jack, jack_client_open, , AC_MSG_ERROR(JACK support requires the jack library!))])
-
-case $host in
- *-*-netbsd*)
- AS_IF([test "$api" == ""], [
- AC_MSG_RESULT(using OSS)
- api="$api -D__LINUX_OSS__"
- LIBS="$LIBS -lossaudio"
- AC_CHECK_LIB(pthread, pthread_create, , AC_MSG_ERROR(RtAudio requires the pthread library!))])
- ;;
-
- *-*-freebsd*)
- AS_IF([test "$api" == ""], [
- AC_MSG_RESULT(using OSS)
- api="$api -D__LINUX_OSS__"
- LIBS="$LIBS -lossaudio"
- AC_CHECK_LIB(pthread, pthread_create, , AC_MSG_ERROR(RtAudio requires the pthread library!))])
- ;;
-
- *-*-linux*)
- # Look for ALSA flag
- AC_ARG_WITH(alsa, [ --with-alsa = choose native ALSA API support (linux only)])
- AS_IF([test "x$with_alsa" == "xyes"], [
- api="$api -D__LINUX_ALSA__"
- req="$req alsa"
- AC_MSG_RESULT(using ALSA)
- AC_CHECK_LIB(asound, snd_pcm_open, , AC_MSG_ERROR(ALSA support requires the asound library!))])
-
- # Look for PULSE flag
- AC_ARG_WITH(pulse, [ --with-pulse = choose PulseAudio API support (linux only)])
- AS_IF([test "x$with_pulse" == "xyes"], [
- api="$api -D__LINUX_PULSE__"
- req="$req libpulse-simple"
- AC_MSG_RESULT(using PulseAudio)
- AC_CHECK_LIB(pulse-simple, pa_simple_flush, , AC_MSG_ERROR(PulseAudio support requires the pulse-simple library!))])
-
- # Look for OSS flag
- AC_ARG_WITH(oss, [ --with-oss = choose OSS API support (unixes)])
- AS_IF([test "x$with_oss" == "xyes"], [
- api="$api -D__LINUX_OSS__"
- AC_MSG_RESULT(using OSS)])
-
- # If no audio api flags specified, use ALSA
- if [test "$api" == "";] then
- AC_MSG_RESULT(using ALSA)
- AC_SUBST( api, [-D__LINUX_ALSA__] )
- req="$req alsa"
- AC_CHECK_LIB(asound, snd_pcm_open, , AC_MSG_ERROR(ALSA support requires the asound library!))
- fi
-
- AC_CHECK_LIB(pthread, pthread_create, , AC_MSG_ERROR(RtAudio requires the pthread library!))
- ;;
-
- *-apple*)
- # Look for Core flag
- AC_ARG_WITH(core, [ --with-core = choose CoreAudio API support (mac only)])
- AS_IF([test "x$with_core" == "xyes"], [
- api="$api -D__MACOSX_CORE__"
- AC_MSG_RESULT(using CoreAudio)
- AC_CHECK_HEADER(CoreAudio/CoreAudio.h, [], [AC_MSG_ERROR(CoreAudio header files not found!)] )
- LIBS="$LIBS -framework CoreAudio -framework CoreFoundation" ])
-
- # If no audio api flags specified, use CoreAudio
- if [test "$api" == ""; ] then
- AC_SUBST( api, [-D__MACOSX_CORE__] )
- AC_MSG_RESULT(using CoreAudio)
- AC_CHECK_HEADER(CoreAudio/CoreAudio.h,
- [],
- [AC_MSG_ERROR(CoreAudio header files not found!)] )
- AC_SUBST( LIBS, ["-framework CoreAudio -framework CoreFoundation"] )
- fi
-
- AC_CHECK_LIB(pthread, pthread_create, , AC_MSG_ERROR(RtAudio requires the pthread library!))
- ;;
-
- *-mingw32*)
- AC_ARG_WITH(asio, [ --with-asio = choose ASIO API support (windoze only)])
- AS_IF([test "x$with_asio" == "xyes"], [
- api="$api -D__WINDOWS_ASIO__"
- AC_MSG_RESULT(using ASIO)
- AC_SUBST( objects, ["asio.o asiodrivers.o asiolist.o iasiothiscallresolver.o"] ) ])
-
- # Look for DirectSound flag
- AC_ARG_WITH(ds, [ --with-ds = choose DirectSound API support (windoze only)])
- AS_IF([test "x$with_ds" == "xyes"], [
- api="$api -D__WINDOWS_DS__"
- AC_MSG_RESULT(using DirectSound)
- LIBS="-ldsound -lwinmm $LIBS" ])
-
- # Look for WASAPI flag
- AC_ARG_WITH(wasapi, [ --with-wasapi = choose Windows Audio Session API support (windoze only)])
- AS_IF([test "x$with_wasapi" == "xyes"], [
- api="$api -D__WINDOWS_WASAPI__"
- AC_MSG_RESULT(using WASAPI)
- LIBS="-lwinmm -luuid -lksuser $LIBS" ])
-
- # If no audio api flags specified, use DS
- if [test "$api" == "";] then
- AC_SUBST( api, [-D__WINDOWS_DS__] )
- AC_MSG_RESULT(using DirectSound)
- LIBS="-ldsound -lwinmm $LIBS"
- fi
-
- LIBS="-lole32 $LIBS"
- ;;
-
- *)
- # Default case for unknown realtime systems.
- AC_MSG_ERROR(Unknown system type for realtime support!)
- ;;
-esac
+# Aggregate options into a single string.
+AS_IF([test "x$with_jack" = "xyes"], [systems="$systems jack"])
+AS_IF([test "x$with_alsa" = "xyes"], [systems="$systems alsa"])
+AS_IF([test "x$with_pulse" = "xyes"], [systems="$systems pulse"])
+AS_IF([test "x$with_oss" = "xyes"], [systems="$systems oss"])
+AS_IF([test "x$with_core" = "xyes"], [systems="$systems core"])
+AS_IF([test "x$with_asio" = "xyes"], [systems="$systems asio"])
+AS_IF([test "x$with_dsound" = "xyes"], [systems="$systems dsound"])
+AS_IF([test "x$with_wasapi" = "xyes"], [systems="$systems wasapi"])
+required=" $systems "
+
+# If none, assign defaults if any are known for this OS.
+# User must specified with-* options for any unknown OS.
+AS_IF([test "x$systems" = "x"],
+ AS_CASE([$host],
+ [*-*-netbsd*], [systems="oss"],
+ [*-*-freebsd*], [systems="oss"],
+ [*-*-linux*], [systems="alsa pulse jack oss"],
+ [*-apple*], [systems="core jack"],
+ [*-mingw32*], [systems="asio dsound wasapi jack"],
+ [*-mingw64*], [systems="asio dsound wasapi jack"],
+ [*-msys*], [systems="asio dsound wasapi jack"],
+ ))
+
+# If any were specifically requested disabled, do it.
+AS_IF([test "x$with_jack" = "xno"], [systems=`echo $systems|tr ' ' \\\\n|grep -v jack`])
+AS_IF([test "x$with_alsa" = "xno"], [systems=`echo $systems|tr ' ' \\\\n|grep -v alsa`])
+AS_IF([test "x$with_pulse" = "xno"], [systems=`echo $systems|tr ' ' \\\\n|grep -v pulse`])
+AS_IF([test "x$with_oss" = "xno"], [systems=`echo $systems|tr ' ' \\\\n|grep -v oss`])
+AS_IF([test "x$with_core" = "xno"], [systems=`echo $systems|tr ' ' \\\\n|grep -v core`])
+AS_IF([test "x$with_asio" = "xno"], [systems=`echo $systems|tr ' ' \\\\n|grep -v asio`])
+AS_IF([test "x$with_dsound" = "xno"], [systems=`echo $systems|tr ' ' \\\\n|grep -v dsound`])
+AS_IF([test "x$with_wasapi" = "xno"], [systems=`echo $systems|tr ' ' \\\\n|grep -v wasapi`])
+systems=" `echo $systems|tr \\\\n ' '` "
+
+# For each audio system, check if it is selected and found.
+# Note: Order specified above is not necessarily respected. However,
+# *actual* priority is set at run-time, see RtAudio::openRtApi.
+# One AS_CASE per system, since they are not mutually-exclusive.
+
+AS_CASE(["$systems"], [*" alsa "*], [
+ AC_CHECK_LIB(asound, snd_pcm_open,
+ [api="$api -D__LINUX_ALSA__"
+ req="$req alsa"
+ need_pthread=yes
+ found="$found ALSA"
+ LIBS="-lasound $LIBS"],
+ AS_CASE(["$required"], [*" alsa "*],
+ AC_MSG_ERROR([ALSA support requires the asound library!])))
+])
+
+AS_CASE(["$systems"], [*" pulse "*], [
+ AC_CHECK_LIB(pulse-simple, pa_simple_flush,
+ [api="$api -D__LINUX_PULSE__"
+ req="$req libpulse-simple"
+ need_pthread=yes
+ found="$found PulseAudio"
+ LIBS="-lpulse-simple $LIBS"],
+ AS_CASE(["$required"], [*" pulse "*],
+ AC_MSG_ERROR([PulseAudio support requires the pulse-simple library!])))
+])
+
+AS_CASE(["$systems"], [*" oss "*], [
+ # libossaudio not required on some platforms (e.g. linux) so we
+ # don't break things if it's not found, but issue a warning when we
+ # are not sure (i.e. not on linux)
+ AS_CASE([$host], [*-*-linux*], [], [*], [need_ossaudio=yes])
+ AC_CHECK_LIB(ossaudio, main, [have_ossaudio=true],
+ AS_CASE(["$required"], [*" oss "*],
+ AS_IF([test "x$need_ossaudio" = xyes],
+ AC_MSG_WARN([RtAudio may require the ossaudio library]))))
+
+ # linux systems may have soundcard.h but *not* have OSS4 installed,
+ # we have to actually check if it exports OSS4 symbols
+ AC_CHECK_DECL(SNDCTL_SYSINFO,
+ [api="$api -D__LINUX_OSS__"
+ need_pthread=yes
+ found="$found OSS"],
+ AS_CASE(["$required"], [*" oss "*],
+ AC_MSG_ERROR([sys/soundcard.h not found]))
+ [],
+ [#include <sys/soundcard.h>])
+])
+
+AS_CASE(["$systems"], [*" jack "*], [
+ AC_CHECK_LIB(jack, jack_client_open,
+ [api="$api -D__UNIX_JACK__"
+ req="$req jack"
+ need_pthread=yes
+ found="$found JACK"
+ LIBS="-ljack $LIBS"],
+ AS_CASE(["$required"], [*" jack "*],
+ AC_MSG_ERROR([JACK support requires the jack library!])))
+])
+
+AS_CASE(["$systems"], [*" core "*], [
+ AC_CHECK_HEADER(CoreAudio/CoreAudio.h,
+ [api="$api -D__MACOSX_CORE__"
+ need_pthread=yes
+ found="$found CoreAudio",
+ LIBS="$LIBS -framework CoreAudio -framework CoreFoundation"],
+ AS_CASE(["$required"], [*" core "*],
+ AC_MSG_ERROR([CoreAudio header files not found!])))
+])
+
+AS_CASE(["$systems"], [*" asio "*], [
+ api="$api -D__WINDOWS_ASIO__"
+ use_asio=yes
+ CPPFLAGS="-I$srcdir/include $CPPFLAGS"
+ need_ole32=yes
+ found="$found ASIO"
+])
+
+AS_CASE(["$systems"], [*" dsound "*], [
+ AC_CHECK_HEADERS(windows.h)
+ AC_CHECK_HEADERS(mmsystem.h mmreg.h dsound.h, [], [],
+[#ifdef HAVE_WINDOWS_H
+# include <windows.h>
+#endif])
+ AS_IF([test "x$ac_cv_header_windows_h" = xyes \
+ && test "x$ac_cv_header_mmsystem_h" = xyes \
+ && test "x$ac_cv_header_mmreg_h" = xyes \
+ && test "x$ac_cv_header_dsound_h" = xyes],
+ [api="$api -D__WINDOWS_DS__"
+ need_ole32=yes
+ found="$found DirectSound"
+ LIBS="-ldsound -lwinmm $LIBS"])
+])
+
+AS_CASE(["$systems"], [*" wasapi "*], [
+ AC_CHECK_HEADERS(windows.h)
+ AC_CHECK_HEADERS(audioclient.h avrt.h mmdeviceapi.h, [], [],
+[#ifdef HAVE_WINDOWS_H
+# include <windows.h>
+#endif])
+ AS_IF([test "x$ac_cv_header_windows_h" = xyes \
+ && test "x$ac_cv_header_audioclient_h" = xyes \
+ && test "x$ac_cv_header_avrt_h" = xyes \
+ && test "x$ac_cv_header_mmdeviceapi_h" = xyes],
+ [api="$api -D__WINDOWS_WASAPI__"
+ CPPFLAGS="-I$srcdir/include $CPPFLAGS"
+ need_ole32=yes
+ found="$found WASAPI"
+ LIBS="-lwinmm -lksuser -lmfplat -lmfuuid -lwmcodecdspuuid $LIBS"])
+])
+
+AS_IF([test -n "$need_ole32"], [LIBS="-lole32 $LIBS"])
+
+AS_IF([test -n "$need_pthread"],[
+ AC_MSG_CHECKING([for pthread])
+ AC_CHECK_LIB(pthread, pthread_create, ,
+ AC_MSG_ERROR([RtAudio requires the pthread library!]))])
+
+AC_MSG_CHECKING([for audio API])
+
+# Error case: no known realtime systems found.
+AS_IF([test x"$api" = "x"], [
+ AC_MSG_RESULT([none])
+ AC_MSG_ERROR([No known system type found for realtime support!])
+], [
+ AC_MSG_RESULT([$found])
+])
+
+AM_CONDITIONAL( ASIO, [test "x${use_asio}" = "xyes" ])
CPPFLAGS="$CPPFLAGS $api"
--- /dev/null
+package rtaudio
+
+/*
+
+#cgo CXXFLAGS: -g
+#cgo LDFLAGS: -lstdc++ -g
+
+#cgo linux CXXFLAGS: -D__LINUX_ALSA__
+#cgo linux LDFLAGS: -lm -lasound -pthread
+
+#cgo linux,pulseaudio CXXFLAGS: -D__LINUX_PULSE__
+#cgo linux,pulseaudio LDFLAGS: -lpulse -lpulse-simple
+
+#cgo jack CXXFLAGS: -D__UNIX_JACK__
+#cgo jack LDFLAGS: -ljack
+
+#cgo windows CXXFLAGS: -D__WINDOWS_WASAPI__
+#cgo windows LDFLAGS: -lm -lksuser -lmfplat -lmfuuid -lwmcodecdspuuid -lwinmm -lole32 -static
+
+#cgo darwin CXXFLAGS: -D__MACOSX_CORE__
+#cgo darwin LDFLAGS: -framework CoreAudio -framework CoreFoundation
+
+#include <stdlib.h>
+#include <stdint.h>
+#include "rtaudio_stub.h"
+
+extern int goCallback(void *out, void *in, unsigned int nFrames,
+ double stream_time, rtaudio_stream_status_t status, void *userdata);
+
+static inline void cgoRtAudioOpenStream(rtaudio_t audio,
+ rtaudio_stream_parameters_t *output_params,
+ rtaudio_stream_parameters_t *input_params,
+ rtaudio_format_t format,
+ unsigned int sample_rate,
+ unsigned int *buffer_frames,
+ int cb_id,
+ rtaudio_stream_options_t *options) {
+ rtaudio_open_stream(audio, output_params, input_params,
+ format, sample_rate, buffer_frames,
+ goCallback, (void *)(uintptr_t)cb_id, options, NULL);
+}
+*/
+import "C"
+import (
+ "errors"
+ "sync"
+ "time"
+ "unsafe"
+)
+
+// API is an enumeration of available compiled APIs. Supported API include
+// Alsa/PulseAudio/OSS, Jack, CoreAudio, WASAPI/ASIO/DS and dummy API.
+type API C.rtaudio_api_t
+
+const (
+ // APIUnspecified looks for a working compiled API.
+ APIUnspecified API = C.RTAUDIO_API_UNSPECIFIED
+ // APILinuxALSA uses the Advanced Linux Sound Architecture API.
+ APILinuxALSA = C.RTAUDIO_API_LINUX_ALSA
+ // APILinuxPulse uses the Linux PulseAudio API.
+ APILinuxPulse = C.RTAUDIO_API_LINUX_PULSE
+ // APILinuxOSS uses the Linux Open Sound System API.
+ APILinuxOSS = C.RTAUDIO_API_LINUX_OSS
+ // APIUnixJack uses the Jack Low-Latency Audio Server API.
+ APIUnixJack = C.RTAUDIO_API_UNIX_JACK
+ // APIMacOSXCore uses Macintosh OS-X Core Audio API.
+ APIMacOSXCore = C.RTAUDIO_API_MACOSX_CORE
+ // APIWindowsWASAPI uses the Microsoft WASAPI API.
+ APIWindowsWASAPI = C.RTAUDIO_API_WINDOWS_WASAPI
+ // APIWindowsASIO uses the Steinberg Audio Stream I/O API.
+ APIWindowsASIO = C.RTAUDIO_API_WINDOWS_ASIO
+ // APIWindowsDS uses the Microsoft DirectSound API.
+ APIWindowsDS = C.RTAUDIO_API_WINDOWS_DS
+ // APIDummy is a compilable but non-functional API.
+ APIDummy = C.RTAUDIO_API_DUMMY
+)
+
+func (api API) String() string {
+ switch api {
+ case APIUnspecified:
+ return "unspecified"
+ case APILinuxALSA:
+ return "alsa"
+ case APILinuxPulse:
+ return "pulse"
+ case APILinuxOSS:
+ return "oss"
+ case APIUnixJack:
+ return "jack"
+ case APIMacOSXCore:
+ return "coreaudio"
+ case APIWindowsWASAPI:
+ return "wasapi"
+ case APIWindowsASIO:
+ return "asio"
+ case APIWindowsDS:
+ return "directsound"
+ case APIDummy:
+ return "dummy"
+ }
+ return "?"
+}
+
+// StreamStatus defines over- or underflow flags in the audio callback.
+type StreamStatus C.rtaudio_stream_status_t
+
+const (
+ // StatusInputOverflow indicates that data was discarded because of an
+ // overflow condition at the driver.
+ StatusInputOverflow StreamStatus = C.RTAUDIO_STATUS_INPUT_OVERFLOW
+ // StatusOutputUnderflow indicates that the output buffer ran low, likely
+ // producing a break in the output sound.
+ StatusOutputUnderflow StreamStatus = C.RTAUDIO_STATUS_OUTPUT_UNDERFLOW
+)
+
+// Version returns current RtAudio library version string.
+func Version() string {
+ return C.GoString(C.rtaudio_version())
+}
+
+// CompiledAPI determines the available compiled audio APIs.
+func CompiledAPI() (apis []API) {
+ capis := (*[1 << 27]C.rtaudio_api_t)(unsafe.Pointer(C.rtaudio_compiled_api()))
+ for i := 0; ; i++ {
+ api := capis[i]
+ if api == C.RTAUDIO_API_UNSPECIFIED {
+ break
+ }
+ apis = append(apis, API(api))
+ }
+ return apis
+}
+
+// DeviceInfo is the public device information structure for returning queried values.
+type DeviceInfo struct {
+ Name string
+ Probed bool
+ NumOutputChannels int
+ NumInputChannels int
+ NumDuplexChannels int
+ IsDefaultOutput bool
+ IsDefaultInput bool
+
+ //rtaudio_format_t native_formats;
+
+ PreferredSampleRate uint
+ SampleRates []int
+}
+
+// StreamParams is the structure for specifying input or output stream parameters.
+type StreamParams struct {
+ DeviceID uint
+ NumChannels uint
+ FirstChannel uint
+}
+
+// StreamFlags is a set of RtAudio stream option flags.
+type StreamFlags C.rtaudio_stream_flags_t
+
+const (
+ // FlagsNoninterleaved is set to use non-interleaved buffers (default = interleaved).
+ FlagsNoninterleaved = C.RTAUDIO_FLAGS_NONINTERLEAVED
+ // FlagsMinimizeLatency when set attempts to configure stream parameters for lowest possible latency.
+ FlagsMinimizeLatency = C.RTAUDIO_FLAGS_MINIMIZE_LATENCY
+ // FlagsHogDevice when set attempts to grab device for exclusive use.
+ FlagsHogDevice = C.RTAUDIO_FLAGS_HOG_DEVICE
+ // FlagsScheduleRealtime is set in attempt to select realtime scheduling (round-robin) for the callback thread.
+ FlagsScheduleRealtime = C.RTAUDIO_FLAGS_SCHEDULE_REALTIME
+ // FlagsAlsaUseDefault is set to use the "default" PCM device (ALSA only).
+ FlagsAlsaUseDefault = C.RTAUDIO_FLAGS_ALSA_USE_DEFAULT
+)
+
+// StreamOptions is the structure for specifying stream options.
+type StreamOptions struct {
+ Flags StreamFlags
+ NumBuffers uint
+ Priotity int
+ Name string
+}
+
+// RtAudio is a "controller" used to select an available audio i/o interface.
+type RtAudio interface {
+ Destroy()
+ CurrentAPI() API
+ Devices() ([]DeviceInfo, error)
+ DefaultOutputDevice() int
+ DefaultInputDevice() int
+
+ Open(out, in *StreamParams, format Format, sampleRate uint, frames uint, cb Callback, opts *StreamOptions) error
+ Close()
+ Start() error
+ Stop() error
+ Abort() error
+
+ IsOpen() bool
+ IsRunning() bool
+
+ Latency() (int, error)
+ SampleRate() (uint, error)
+ Time() (time.Duration, error)
+ SetTime(time.Duration) error
+
+ ShowWarnings(bool)
+}
+
+type rtaudio struct {
+ audio C.rtaudio_t
+ cb Callback
+ inputChannels int
+ outputChannels int
+ format Format
+}
+
+var _ RtAudio = &rtaudio{}
+
+// Create a new RtAudio instance using the given API.
+func Create(api API) (RtAudio, error) {
+ audio := C.rtaudio_create(C.rtaudio_api_t(api))
+ if C.rtaudio_error(audio) != nil {
+ return nil, errors.New(C.GoString(C.rtaudio_error(audio)))
+ }
+ return &rtaudio{audio: audio}, nil
+}
+
+func (audio *rtaudio) Destroy() {
+ C.rtaudio_destroy(audio.audio)
+}
+
+func (audio *rtaudio) CurrentAPI() API {
+ return API(C.rtaudio_current_api(audio.audio))
+}
+
+func (audio *rtaudio) DefaultInputDevice() int {
+ return int(C.rtaudio_get_default_input_device(audio.audio))
+}
+
+func (audio *rtaudio) DefaultOutputDevice() int {
+ return int(C.rtaudio_get_default_output_device(audio.audio))
+}
+
+func (audio *rtaudio) Devices() ([]DeviceInfo, error) {
+ n := C.rtaudio_device_count(audio.audio)
+ devices := []DeviceInfo{}
+ for i := C.int(0); i < n; i++ {
+ cinfo := C.rtaudio_get_device_info(audio.audio, i)
+ if C.rtaudio_error(audio.audio) != nil {
+ return nil, errors.New(C.GoString(C.rtaudio_error(audio.audio)))
+ }
+ sr := []int{}
+ for _, r := range cinfo.sample_rates {
+ if r == 0 {
+ break
+ }
+ sr = append(sr, int(r))
+ }
+ devices = append(devices, DeviceInfo{
+ Name: C.GoString(&cinfo.name[0]),
+ Probed: cinfo.probed != 0,
+ NumInputChannels: int(cinfo.input_channels),
+ NumOutputChannels: int(cinfo.output_channels),
+ NumDuplexChannels: int(cinfo.duplex_channels),
+ IsDefaultOutput: cinfo.is_default_output != 0,
+ IsDefaultInput: cinfo.is_default_input != 0,
+ PreferredSampleRate: uint(cinfo.preferred_sample_rate),
+ SampleRates: sr,
+ })
+ // TODO: formats
+ }
+ return devices, nil
+}
+
+// Format defines RtAudio data format type.
+type Format int
+
+const (
+ // FormatInt8 uses 8-bit signed integer.
+ FormatInt8 Format = C.RTAUDIO_FORMAT_SINT8
+ // FormatInt16 uses 16-bit signed integer.
+ FormatInt16 = C.RTAUDIO_FORMAT_SINT16
+ // FormatInt24 uses 24-bit signed integer.
+ FormatInt24 = C.RTAUDIO_FORMAT_SINT24
+ // FormatInt32 uses 32-bit signed integer.
+ FormatInt32 = C.RTAUDIO_FORMAT_SINT32
+ // FormatFloat32 uses 32-bit floating point values normalized between (-1..1).
+ FormatFloat32 = C.RTAUDIO_FORMAT_FLOAT32
+ // FormatFloat64 uses 64-bit floating point values normalized between (-1..1).
+ FormatFloat64 = C.RTAUDIO_FORMAT_FLOAT64
+)
+
+// Buffer is a common interface for audio buffers of various data format types.
+type Buffer interface {
+ Len() int
+ Int8() []int8
+ Int16() []int16
+ Int24() []Int24
+ Int32() []int32
+ Float32() []float32
+ Float64() []float64
+}
+
+// Int24 is a helper type to convert int32 values to int24 and back.
+type Int24 [3]byte
+
+// Set Int24 value using the least significant bytes of the given number n.
+func (i *Int24) Set(n int32) {
+ (*i)[0], (*i)[1], (*i)[2] = byte(n&0xff), byte((n&0xff00)>>8), byte((n&0xff0000)>>16)
+}
+
+// Get Int24 value as int32.
+func (i Int24) Get() int32 {
+ n := int32(i[0]) | int32(i[1])<<8 | int32(i[2])<<16
+ if n&0x800000 != 0 {
+ n |= ^0xffffff
+ }
+ return n
+}
+
+type buffer struct {
+ format Format
+ length int
+ numChannels int
+ ptr unsafe.Pointer
+}
+
+func (b *buffer) Len() int {
+ if b.ptr == nil {
+ return 0
+ }
+ return b.length
+}
+
+func (b *buffer) Int8() []int8 {
+ if b.format != FormatInt8 {
+ return nil
+ }
+ if b.ptr == nil {
+ return nil
+ }
+ return (*[1 << 30]int8)(b.ptr)[:b.length*b.numChannels : b.length*b.numChannels]
+}
+
+func (b *buffer) Int16() []int16 {
+ if b.format != FormatInt16 {
+ return nil
+ }
+ if b.ptr == nil {
+ return nil
+ }
+ return (*[1 << 29]int16)(b.ptr)[:b.length*b.numChannels : b.length*b.numChannels]
+}
+
+func (b *buffer) Int24() []Int24 {
+ if b.format != FormatInt24 {
+ return nil
+ }
+ if b.ptr == nil {
+ return nil
+ }
+ return (*[1 << 28]Int24)(b.ptr)[:b.length*b.numChannels : b.length*b.numChannels]
+}
+
+func (b *buffer) Int32() []int32 {
+ if b.format != FormatInt32 {
+ return nil
+ }
+ if b.ptr == nil {
+ return nil
+ }
+ return (*[1 << 27]int32)(b.ptr)[:b.length*b.numChannels : b.length*b.numChannels]
+}
+
+func (b *buffer) Float32() []float32 {
+ if b.format != FormatFloat32 {
+ return nil
+ }
+ if b.ptr == nil {
+ return nil
+ }
+ return (*[1 << 27]float32)(b.ptr)[:b.length*b.numChannels : b.length*b.numChannels]
+}
+
+func (b *buffer) Float64() []float64 {
+ if b.format != FormatFloat64 {
+ return nil
+ }
+ if b.ptr == nil {
+ return nil
+ }
+ return (*[1 << 23]float64)(b.ptr)[:b.length*b.numChannels : b.length*b.numChannels]
+}
+
+// Callback is a client-defined function that will be invoked when input data
+// is available and/or output data is needed.
+type Callback func(out Buffer, in Buffer, dur time.Duration, status StreamStatus) int
+
+var (
+ mu sync.Mutex
+ audios = map[int]*rtaudio{}
+)
+
+func registerAudio(a *rtaudio) int {
+ mu.Lock()
+ defer mu.Unlock()
+ for i := 0; ; i++ {
+ if _, ok := audios[i]; !ok {
+ audios[i] = a
+ return i
+ }
+ }
+}
+
+func unregisterAudio(a *rtaudio) {
+ mu.Lock()
+ defer mu.Unlock()
+ for i := 0; i < len(audios); i++ {
+ if audios[i] == a {
+ delete(audios, i)
+ return
+ }
+ }
+}
+
+func findAudio(k int) *rtaudio {
+ mu.Lock()
+ defer mu.Unlock()
+ return audios[k]
+}
+
+//export goCallback
+func goCallback(out, in unsafe.Pointer, frames C.uint, sec C.double,
+ status C.rtaudio_stream_status_t, userdata unsafe.Pointer) C.int {
+
+ k := int(uintptr(userdata))
+ audio := findAudio(k)
+ dur := time.Duration(time.Microsecond * time.Duration(sec*1000000.0))
+ inbuf := &buffer{audio.format, int(frames), audio.inputChannels, in}
+ outbuf := &buffer{audio.format, int(frames), audio.outputChannels, out}
+ return C.int(audio.cb(outbuf, inbuf, dur, StreamStatus(status)))
+}
+
+func (audio *rtaudio) Open(out, in *StreamParams, format Format, sampleRate uint,
+ frames uint, cb Callback, opts *StreamOptions) error {
+ var (
+ cInPtr *C.rtaudio_stream_parameters_t
+ cOutPtr *C.rtaudio_stream_parameters_t
+ cOptsPtr *C.rtaudio_stream_options_t
+ cIn C.rtaudio_stream_parameters_t
+ cOut C.rtaudio_stream_parameters_t
+ cOpts C.rtaudio_stream_options_t
+ )
+
+ audio.inputChannels = 0
+ audio.outputChannels = 0
+ if out != nil {
+ audio.outputChannels = int(out.NumChannels)
+ cOut.device_id = C.uint(out.DeviceID)
+ cOut.num_channels = C.uint(out.NumChannels)
+ cOut.first_channel = C.uint(out.FirstChannel)
+ cOutPtr = &cOut
+ }
+ if in != nil {
+ audio.inputChannels = int(in.NumChannels)
+ cIn.device_id = C.uint(in.DeviceID)
+ cIn.num_channels = C.uint(in.NumChannels)
+ cIn.first_channel = C.uint(in.FirstChannel)
+ cInPtr = &cIn
+ }
+ if opts != nil {
+ cOpts.flags = C.rtaudio_stream_flags_t(opts.Flags)
+ cOpts.num_buffers = C.uint(opts.NumBuffers)
+ cOpts.priority = C.int(opts.Priotity)
+ cOptsPtr = &cOpts
+ }
+ framesCount := C.uint(frames)
+ audio.format = format
+ audio.cb = cb
+
+ k := registerAudio(audio)
+ C.cgoRtAudioOpenStream(audio.audio, cOutPtr, cInPtr,
+ C.rtaudio_format_t(format), C.uint(sampleRate), &framesCount, C.int(k), cOptsPtr)
+ if C.rtaudio_error(audio.audio) != nil {
+ return errors.New(C.GoString(C.rtaudio_error(audio.audio)))
+ }
+ return nil
+}
+
+func (audio *rtaudio) Close() {
+ unregisterAudio(audio)
+ C.rtaudio_close_stream(audio.audio)
+}
+
+func (audio *rtaudio) Start() error {
+ C.rtaudio_start_stream(audio.audio)
+ if C.rtaudio_error(audio.audio) != nil {
+ return errors.New(C.GoString(C.rtaudio_error(audio.audio)))
+ }
+ return nil
+}
+
+func (audio *rtaudio) Stop() error {
+ C.rtaudio_stop_stream(audio.audio)
+ if C.rtaudio_error(audio.audio) != nil {
+ return errors.New(C.GoString(C.rtaudio_error(audio.audio)))
+ }
+ return nil
+}
+
+func (audio *rtaudio) Abort() error {
+ C.rtaudio_abort_stream(audio.audio)
+ if C.rtaudio_error(audio.audio) != nil {
+ return errors.New(C.GoString(C.rtaudio_error(audio.audio)))
+ }
+ return nil
+}
+
+func (audio *rtaudio) IsOpen() bool {
+ return C.rtaudio_is_stream_open(audio.audio) != 0
+}
+
+func (audio *rtaudio) IsRunning() bool {
+ return C.rtaudio_is_stream_running(audio.audio) != 0
+}
+
+func (audio *rtaudio) Latency() (int, error) {
+ latency := C.rtaudio_get_stream_latency(audio.audio)
+ if C.rtaudio_error(audio.audio) != nil {
+ return 0, errors.New(C.GoString(C.rtaudio_error(audio.audio)))
+ }
+ return int(latency), nil
+}
+
+func (audio *rtaudio) SampleRate() (uint, error) {
+ sampleRate := C.rtaudio_get_stream_sample_rate(audio.audio)
+ if C.rtaudio_error(audio.audio) != nil {
+ return 0, errors.New(C.GoString(C.rtaudio_error(audio.audio)))
+ }
+ return uint(sampleRate), nil
+}
+
+func (audio *rtaudio) Time() (time.Duration, error) {
+ sec := C.rtaudio_get_stream_time(audio.audio)
+ if C.rtaudio_error(audio.audio) != nil {
+ return 0, errors.New(C.GoString(C.rtaudio_error(audio.audio)))
+ }
+ return time.Duration(time.Microsecond * time.Duration(sec*1000000.0)), nil
+}
+
+func (audio *rtaudio) SetTime(t time.Duration) error {
+ sec := float64(t) * 1000000.0 / float64(time.Microsecond)
+ C.rtaudio_set_stream_time(audio.audio, C.double(sec))
+ if C.rtaudio_error(audio.audio) != nil {
+ return errors.New(C.GoString(C.rtaudio_error(audio.audio)))
+ }
+ return nil
+}
+
+func (audio *rtaudio) ShowWarnings(show bool) {
+ if show {
+ C.rtaudio_show_warnings(audio.audio, 1)
+ } else {
+ C.rtaudio_show_warnings(audio.audio, 0)
+ }
+}
--- /dev/null
+#include "../../../RtAudio.h"
+
+#include "../../../RtAudio.cpp"
+#include "../../../rtaudio_c.cpp"
--- /dev/null
+#include "../../../rtaudio_c.h"
--- /dev/null
+package rtaudio
+
+import (
+ "log"
+ "math"
+ "time"
+)
+
+func ExampleCompiledAPI() {
+ log.Println("RtAudio version: ", Version())
+ for _, api := range CompiledAPI() {
+ log.Println("Compiled API: ", api)
+ }
+}
+
+func ExampleRtAudio_Devices() {
+ audio, err := Create(APIUnspecified)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer audio.Destroy()
+ devices, err := audio.Devices()
+ if err != nil {
+ log.Fatal(err)
+ }
+ for _, d := range devices {
+ log.Printf("Audio device: %#v\n", d)
+ }
+}
+
+func ExampleRtAudio_Open() {
+ const (
+ sampleRate = 44100
+ bufSz = 512
+ freq = 440.0
+ )
+ phase := 0.0
+ audio, err := Create(APIUnspecified)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer audio.Destroy()
+
+ params := StreamParams{
+ DeviceID: uint(audio.DefaultOutputDevice()),
+ NumChannels: 2,
+ FirstChannel: 0,
+ }
+ options := StreamOptions{
+ Flags: FlagsAlsaUseDefault,
+ }
+ cb := func(out, in Buffer, dur time.Duration, status StreamStatus) int {
+ samples := out.Float32()
+ for i := 0; i < len(samples)/2; i++ {
+ sample := float32(math.Sin(2 * math.Pi * phase))
+ phase += freq / sampleRate
+
+ samples[i*2] = sample
+ samples[i*2+1] = sample
+ }
+ return 0
+ }
+ err = audio.Open(¶ms, nil, FormatFloat32, sampleRate, bufSz, cb, &options)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer audio.Close()
+ audio.Start()
+ defer audio.Stop()
+ time.Sleep(3 * time.Second)
+}
</TR>
<TR>
<TD>Windows</TD>
- <TD>Direct Sound</TD>
+ <TD>DirectSound</TD>
<TD>RtApiDs</TD>
<TD>__WINDOWS_DS__</TD>
<TD><TT>dsound.lib (ver. 5.0 or higher), multithreaded</TT></TD>
<TD>WASAPI</TD>
<TD>RtApiWasapi</TD>
<TD>__WINDOWS_WASAPI__</TD>
- <TD>MinGW: <TT>FunctionDiscoveryKeys_devpkey.h, lksuser, luuid, lwinmm, lole32</TT></TD>
- <TD>MinGW: <TT>g++ -Wall -D__WINDOWS_WASAPI__ -Iinclude -o audioprobe audioprobe.cpp RtAudio.cpp -lole32 -lwinmm -lksuser -luuid</TT></TD>
+ <TD>MinGW: <TT>FunctionDiscoveryKeys_devpkey.h, lksuser, lmfplat, lmfuuid, lwmcodecdspuuid, lwinmm, lole32</TT></TD>
+ <TD>MinGW: <TT>g++ -Wall -D__WINDOWS_WASAPI__ -Iinclude -o audioprobe audioprobe.cpp RtAudio.cpp -lole32 -lwinmm -lksuser -lmfplat -lmfuuid -lwmcodecdspuuid</TT></TD>
</TR>
</TABLE>
<P>
bool isDefaultOutput; // true if this is the default output device.
bool isDefaultInput; // true if this is the default input device.
std::vector<unsigned int> sampleRates; // Supported sample rates.
- unsigned int preferredSampleRate; // Preferred sample rate, eg. for WASAPI the system sample rate.
+ unsigned int preferredSampleRate; // Preferred sample rate, e.g. for WASAPI the system sample rate.
RtAudioFormat nativeFormats; // Bit mask of supported data formats.
};
\endcode
+++ /dev/null
-#pragma once
-
-/*++
-
-Copyright (c) Microsoft Corporation. All rights reserved.
-
-Module Name:
-
- devpkey.h
-
-Abstract:
-
- Defines property keys for the Plug and Play Device Property API.
-
-Author:
-
- Jim Cavalaris (jamesca) 10-14-2003
-
-Environment:
-
- User-mode only.
-
-Revision History:
-
- 14-October-2003 jamesca
-
- Creation and initial implementation.
-
- 20-June-2006 dougb
-
- Copied Jim's version replaced "DEFINE_DEVPROPKEY(DEVPKEY_" with "DEFINE_PROPERTYKEY(PKEY_"
-
---*/
-
-//#include <devpropdef.h>
-
-//
-// _NAME
-//
-
-DEFINE_PROPERTYKEY(PKEY_NAME, 0xb725f130, 0x47ef, 0x101a, 0xa5, 0xf1, 0x02, 0x60, 0x8c, 0x9e, 0xeb, 0xac, 10); // DEVPROP_TYPE_STRING
-
-//
-// Device properties
-// These PKEYs correspond to the old setupapi SPDRP_XXX properties
-//
-DEFINE_PROPERTYKEY(PKEY_Device_DeviceDesc, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 2); // DEVPROP_TYPE_STRING
-DEFINE_PROPERTYKEY(PKEY_Device_HardwareIds, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 3); // DEVPROP_TYPE_STRING_LIST
-DEFINE_PROPERTYKEY(PKEY_Device_CompatibleIds, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 4); // DEVPROP_TYPE_STRING_LIST
-DEFINE_PROPERTYKEY(PKEY_Device_Service, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 6); // DEVPROP_TYPE_STRING
-DEFINE_PROPERTYKEY(PKEY_Device_Class, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 9); // DEVPROP_TYPE_STRING
-DEFINE_PROPERTYKEY(PKEY_Device_ClassGuid, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 10); // DEVPROP_TYPE_GUID
-DEFINE_PROPERTYKEY(PKEY_Device_Driver, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 11); // DEVPROP_TYPE_STRING
-DEFINE_PROPERTYKEY(PKEY_Device_ConfigFlags, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 12); // DEVPROP_TYPE_UINT32
-DEFINE_PROPERTYKEY(PKEY_Device_Manufacturer, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 13); // DEVPROP_TYPE_STRING
-DEFINE_PROPERTYKEY(PKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 14); // DEVPROP_TYPE_STRING
-DEFINE_PROPERTYKEY(PKEY_Device_LocationInfo, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 15); // DEVPROP_TYPE_STRING
-DEFINE_PROPERTYKEY(PKEY_Device_PDOName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 16); // DEVPROP_TYPE_STRING
-DEFINE_PROPERTYKEY(PKEY_Device_Capabilities, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 17); // DEVPROP_TYPE_UNINT32
-DEFINE_PROPERTYKEY(PKEY_Device_UINumber, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 18); // DEVPROP_TYPE_STRING
-DEFINE_PROPERTYKEY(PKEY_Device_UpperFilters, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 19); // DEVPROP_TYPE_STRING_LIST
-DEFINE_PROPERTYKEY(PKEY_Device_LowerFilters, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 20); // DEVPROP_TYPE_STRING_LIST
-DEFINE_PROPERTYKEY(PKEY_Device_BusTypeGuid, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 21); // DEVPROP_TYPE_GUID
-DEFINE_PROPERTYKEY(PKEY_Device_LegacyBusType, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 22); // DEVPROP_TYPE_UINT32
-DEFINE_PROPERTYKEY(PKEY_Device_BusNumber, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 23); // DEVPROP_TYPE_UINT32
-DEFINE_PROPERTYKEY(PKEY_Device_EnumeratorName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 24); // DEVPROP_TYPE_STRING
-DEFINE_PROPERTYKEY(PKEY_Device_Security, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 25); // DEVPROP_TYPE_SECURITY_DESCRIPTOR
-DEFINE_PROPERTYKEY(PKEY_Device_SecuritySDS, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 26); // DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING
-DEFINE_PROPERTYKEY(PKEY_Device_DevType, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 27); // DEVPROP_TYPE_UINT32
-DEFINE_PROPERTYKEY(PKEY_Device_Exclusive, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 28); // DEVPROP_TYPE_UINT32
-DEFINE_PROPERTYKEY(PKEY_Device_Characteristics, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 29); // DEVPROP_TYPE_UINT32
-DEFINE_PROPERTYKEY(PKEY_Device_Address, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 30); // DEVPROP_TYPE_UINT32
-DEFINE_PROPERTYKEY(PKEY_Device_UINumberDescFormat, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 31); // DEVPROP_TYPE_STRING
-DEFINE_PROPERTYKEY(PKEY_Device_PowerData, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 32); // DEVPROP_TYPE_BINARY
-DEFINE_PROPERTYKEY(PKEY_Device_RemovalPolicy, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 33); // DEVPROP_TYPE_UINT32
-DEFINE_PROPERTYKEY(PKEY_Device_RemovalPolicyDefault, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 34); // DEVPROP_TYPE_UINT32
-DEFINE_PROPERTYKEY(PKEY_Device_RemovalPolicyOverride, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 35); // DEVPROP_TYPE_UINT32
-DEFINE_PROPERTYKEY(PKEY_Device_InstallState, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 36); // DEVPROP_TYPE_UINT32
-DEFINE_PROPERTYKEY(PKEY_Device_LocationPaths, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 37); // DEVPROP_TYPE_STRING_LIST
-DEFINE_PROPERTYKEY(PKEY_Device_BaseContainerId, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 38); // DEVPROP_TYPE_GUID
-
-//
-// Device properties
-// These PKEYs correspond to a device's status and problem code
-//
-DEFINE_PROPERTYKEY(PKEY_Device_DevNodeStatus, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 2); // DEVPROP_TYPE_UINT32
-DEFINE_PROPERTYKEY(PKEY_Device_ProblemCode, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 3); // DEVPROP_TYPE_UINT32
-
-//
-// Device properties
-// These PKEYs correspond to device relations
-//
-DEFINE_PROPERTYKEY(PKEY_Device_EjectionRelations, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 4); // DEVPROP_TYPE_STRING_LIST
-DEFINE_PROPERTYKEY(PKEY_Device_RemovalRelations, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 5); // DEVPROP_TYPE_STRING_LIST
-DEFINE_PROPERTYKEY(PKEY_Device_PowerRelations, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 6); // DEVPROP_TYPE_STRING_LIST
-DEFINE_PROPERTYKEY(PKEY_Device_BusRelations, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 7); // DEVPROP_TYPE_STRING_LIST
-DEFINE_PROPERTYKEY(PKEY_Device_Parent, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 8); // DEVPROP_TYPE_STRING
-DEFINE_PROPERTYKEY(PKEY_Device_Children, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 9); // DEVPROP_TYPE_STRING_LIST
-DEFINE_PROPERTYKEY(PKEY_Device_Siblings, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 10); // DEVPROP_TYPE_STRING_LIST
-DEFINE_PROPERTYKEY(PKEY_Device_TransportRelations, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 11); // DEVPROP_TYPE_STRING_LIST
-
-//
-// Other Device properties
-//
-DEFINE_PROPERTYKEY(PKEY_Device_Reported, 0x80497100, 0x8c73, 0x48b9, 0xaa, 0xd9, 0xce, 0x38, 0x7e, 0x19, 0xc5, 0x6e, 2); // DEVPROP_TYPE_BOOLEAN
-DEFINE_PROPERTYKEY(PKEY_Device_Legacy, 0x80497100, 0x8c73, 0x48b9, 0xaa, 0xd9, 0xce, 0x38, 0x7e, 0x19, 0xc5, 0x6e, 3); // DEVPROP_TYPE_BOOLEAN
-DEFINE_PROPERTYKEY(PKEY_Device_InstanceId, 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 256); // DEVPROP_TYPE_STRING
-
-DEFINE_PROPERTYKEY(PKEY_Device_ContainerId, 0x8c7ed206, 0x3f8a, 0x4827, 0xb3, 0xab, 0xae, 0x9e, 0x1f, 0xae, 0xfc, 0x6c, 2); // DEVPROP_TYPE_GUID
-
-DEFINE_PROPERTYKEY(PKEY_Device_ModelId, 0x80d81ea6, 0x7473, 0x4b0c, 0x82, 0x16, 0xef, 0xc1, 0x1a, 0x2c, 0x4c, 0x8b, 2); // DEVPROP_TYPE_GUID
-
-DEFINE_PROPERTYKEY(PKEY_Device_FriendlyNameAttributes, 0x80d81ea6, 0x7473, 0x4b0c, 0x82, 0x16, 0xef, 0xc1, 0x1a, 0x2c, 0x4c, 0x8b, 3); // DEVPROP_TYPE_UINT32
-DEFINE_PROPERTYKEY(PKEY_Device_ManufacturerAttributes, 0x80d81ea6, 0x7473, 0x4b0c, 0x82, 0x16, 0xef, 0xc1, 0x1a, 0x2c, 0x4c, 0x8b, 4); // DEVPROP_TYPE_UINT32
-
-DEFINE_PROPERTYKEY(PKEY_Device_PresenceNotForDevice, 0x80d81ea6, 0x7473, 0x4b0c, 0x82, 0x16, 0xef, 0xc1, 0x1a, 0x2c, 0x4c, 0x8b, 5); // DEVPROP_TYPE_BOOLEAN
-
-
-DEFINE_PROPERTYKEY(PKEY_Numa_Proximity_Domain, 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 1); // DEVPROP_TYPE_UINT32
-DEFINE_PROPERTYKEY(PKEY_Device_DHP_Rebalance_Policy, 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 2); // DEVPROP_TYPE_UINT32
-DEFINE_PROPERTYKEY(PKEY_Device_Numa_Node, 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 3); // DEVPROP_TYPE_UINT32
-DEFINE_PROPERTYKEY(PKEY_Device_BusReportedDeviceDesc, 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 4); // DEVPROP_TYPE_STRING
-
-DEFINE_PROPERTYKEY(PKEY_Device_InstallInProgress, 0x83da6326, 0x97a6, 0x4088, 0x94, 0x53, 0xa1, 0x92, 0x3f, 0x57, 0x3b, 0x29, 9); // DEVPROP_TYPE_BOOLEAN
-
-//
-// Device driver properties
-//
-DEFINE_PROPERTYKEY(PKEY_Device_DriverDate, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 2); // DEVPROP_TYPE_FILETIME
-DEFINE_PROPERTYKEY(PKEY_Device_DriverVersion, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 3); // DEVPROP_TYPE_STRING
-DEFINE_PROPERTYKEY(PKEY_Device_DriverDesc, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 4); // DEVPROP_TYPE_STRING
-DEFINE_PROPERTYKEY(PKEY_Device_DriverInfPath, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 5); // DEVPROP_TYPE_STRING
-DEFINE_PROPERTYKEY(PKEY_Device_DriverInfSection, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 6); // DEVPROP_TYPE_STRING
-DEFINE_PROPERTYKEY(PKEY_Device_DriverInfSectionExt, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 7); // DEVPROP_TYPE_STRING
-DEFINE_PROPERTYKEY(PKEY_Device_MatchingDeviceId, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 8); // DEVPROP_TYPE_STRING
-DEFINE_PROPERTYKEY(PKEY_Device_DriverProvider, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 9); // DEVPROP_TYPE_STRING
-DEFINE_PROPERTYKEY(PKEY_Device_DriverPropPageProvider, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 10); // DEVPROP_TYPE_STRING
-DEFINE_PROPERTYKEY(PKEY_Device_DriverCoInstallers, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 11); // DEVPROP_TYPE_STRING_LIST
-DEFINE_PROPERTYKEY(PKEY_Device_ResourcePickerTags, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 12); // DEVPROP_TYPE_STRING
-DEFINE_PROPERTYKEY(PKEY_Device_ResourcePickerExceptions, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 13); // DEVPROP_TYPE_STRING
-DEFINE_PROPERTYKEY(PKEY_Device_DriverRank, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 14); // DEVPROP_TYPE_UINT32
-DEFINE_PROPERTYKEY(PKEY_Device_DriverLogoLevel, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 15); // DEVPROP_TYPE_UINT32
-DEFINE_PROPERTYKEY(PKEY_Device_NoConnectSound, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 17); // DEVPROP_TYPE_BOOLEAN
-DEFINE_PROPERTYKEY(PKEY_Device_GenericDriverInstalled, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 18); // DEVPROP_TYPE_BOOLEAN
-DEFINE_PROPERTYKEY(PKEY_Device_AdditionalSoftwareRequested, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 19);// DEVPROP_TYPE_BOOLEAN
-
-//
-// Device safe-removal properties
-//
-DEFINE_PROPERTYKEY(PKEY_Device_SafeRemovalRequired, 0xafd97640, 0x86a3, 0x4210, 0xb6, 0x7c, 0x28, 0x9c, 0x41, 0xaa, 0xbe, 0x55, 2); // DEVPROP_TYPE_BOOLEAN
-DEFINE_PROPERTYKEY(PKEY_Device_SafeRemovalRequiredOverride, 0xafd97640, 0x86a3, 0x4210, 0xb6, 0x7c, 0x28, 0x9c, 0x41, 0xaa, 0xbe, 0x55, 3);// DEVPROP_TYPE_BOOLEAN
-
-
-//
-// Device properties that were set by the driver package that was installed
-// on the device.
-//
-DEFINE_PROPERTYKEY(PKEY_DrvPkg_Model, 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 2); // DEVPROP_TYPE_STRING
-DEFINE_PROPERTYKEY(PKEY_DrvPkg_VendorWebSite, 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 3); // DEVPROP_TYPE_STRING
-DEFINE_PROPERTYKEY(PKEY_DrvPkg_DetailedDescription, 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 4); // DEVPROP_TYPE_STRING
-DEFINE_PROPERTYKEY(PKEY_DrvPkg_DocumentationLink, 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 5); // DEVPROP_TYPE_STRING
-DEFINE_PROPERTYKEY(PKEY_DrvPkg_Icon, 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 6); // DEVPROP_TYPE_STRING_LIST
-DEFINE_PROPERTYKEY(PKEY_DrvPkg_BrandingIcon, 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 7); // DEVPROP_TYPE_STRING_LIST
-
-//
-// Device setup class properties
-// These PKEYs correspond to the old setupapi SPCRP_XXX properties
-//
-DEFINE_PROPERTYKEY(PKEY_DeviceClass_UpperFilters, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 19); // DEVPROP_TYPE_STRING_LIST
-DEFINE_PROPERTYKEY(PKEY_DeviceClass_LowerFilters, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 20); // DEVPROP_TYPE_STRING_LIST
-DEFINE_PROPERTYKEY(PKEY_DeviceClass_Security, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 25); // DEVPROP_TYPE_SECURITY_DESCRIPTOR
-DEFINE_PROPERTYKEY(PKEY_DeviceClass_SecuritySDS, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 26); // DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING
-DEFINE_PROPERTYKEY(PKEY_DeviceClass_DevType, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 27); // DEVPROP_TYPE_UINT32
-DEFINE_PROPERTYKEY(PKEY_DeviceClass_Exclusive, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 28); // DEVPROP_TYPE_UINT32
-DEFINE_PROPERTYKEY(PKEY_DeviceClass_Characteristics, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 29); // DEVPROP_TYPE_UINT32
-
-//
-// Device setup class properties
-// These PKEYs correspond to registry values under the device class GUID key
-//
-DEFINE_PROPERTYKEY(PKEY_DeviceClass_Name, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 2); // DEVPROP_TYPE_STRING
-DEFINE_PROPERTYKEY(PKEY_DeviceClass_ClassName, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 3); // DEVPROP_TYPE_STRING
-DEFINE_PROPERTYKEY(PKEY_DeviceClass_Icon, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 4); // DEVPROP_TYPE_STRING
-DEFINE_PROPERTYKEY(PKEY_DeviceClass_ClassInstaller, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 5); // DEVPROP_TYPE_STRING
-DEFINE_PROPERTYKEY(PKEY_DeviceClass_PropPageProvider, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 6); // DEVPROP_TYPE_STRING
-DEFINE_PROPERTYKEY(PKEY_DeviceClass_NoInstallClass, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 7); // DEVPROP_TYPE_BOOLEAN
-DEFINE_PROPERTYKEY(PKEY_DeviceClass_NoDisplayClass, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 8); // DEVPROP_TYPE_BOOLEAN
-DEFINE_PROPERTYKEY(PKEY_DeviceClass_SilentInstall, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 9); // DEVPROP_TYPE_BOOLEAN
-DEFINE_PROPERTYKEY(PKEY_DeviceClass_NoUseClass, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 10); // DEVPROP_TYPE_BOOLEAN
-DEFINE_PROPERTYKEY(PKEY_DeviceClass_DefaultService, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 11); // DEVPROP_TYPE_STRING
-DEFINE_PROPERTYKEY(PKEY_DeviceClass_IconPath, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 12); // DEVPROP_TYPE_STRING_LIST
-
-//
-// Other Device setup class properties
-//
-DEFINE_PROPERTYKEY(PKEY_DeviceClass_ClassCoInstallers, 0x713d1703, 0xa2e2, 0x49f5, 0x92, 0x14, 0x56, 0x47, 0x2e, 0xf3, 0xda, 0x5c, 2); // DEVPROP_TYPE_STRING_LIST
-
-//
-// Device interface properties
-//
-DEFINE_PROPERTYKEY(PKEY_DeviceInterface_FriendlyName, 0x026e516e, 0xb814, 0x414b, 0x83, 0xcd, 0x85, 0x6d, 0x6f, 0xef, 0x48, 0x22, 2); // DEVPROP_TYPE_STRING
-DEFINE_PROPERTYKEY(PKEY_DeviceInterface_Enabled, 0x026e516e, 0xb814, 0x414b, 0x83, 0xcd, 0x85, 0x6d, 0x6f, 0xef, 0x48, 0x22, 3); // DEVPROP_TYPE_BOOLEAN
-DEFINE_PROPERTYKEY(PKEY_DeviceInterface_ClassGuid, 0x026e516e, 0xb814, 0x414b, 0x83, 0xcd, 0x85, 0x6d, 0x6f, 0xef, 0x48, 0x22, 4); // DEVPROP_TYPE_GUID
-
-//
-// Device interface class properties
-//
-DEFINE_PROPERTYKEY(PKEY_DeviceInterfaceClass_DefaultInterface, 0x14c83a99, 0x0b3f, 0x44b7, 0xbe, 0x4c, 0xa1, 0x78, 0xd3, 0x99, 0x05, 0x64, 2); // DEVPROP_TYPE_STRING
-
-
-
-
\r
/*\r
Steinberg Audio Stream I/O API\r
- (c) 1997 - 2005, Steinberg Media Technologies GmbH\r
+ (c) 1997 - 2013, Steinberg Media Technologies GmbH\r
\r
- ASIO Interface Specification v 2.1\r
+ ASIO Interface Specification v 2.3\r
\r
2005 - Added support for DSD sample data (in cooperation with Sony)\r
-\r
+ 2012 - Added support for drop out detection\r
+ \r
+ \r
\r
basic concept is an i/o synchronous double-buffer scheme:\r
\r
kAsioCanInputMeter,\r
kAsioCanOutputGain,\r
kAsioCanOutputMeter,\r
-\r
+ kAsioOptionalOne,\r
+ \r
// DSD support\r
// The following extensions are required to allow switching\r
// and control of the DSD subsystem.\r
kAsioSetIoFormat = 0x23111961, /* ASIOIoFormat * in params. */\r
kAsioGetIoFormat = 0x23111983, /* ASIOIoFormat * in params. */\r
kAsioCanDoIoFormat = 0x23112004, /* ASIOIoFormat * in params. */\r
+ \r
+ // Extension for drop out detection\r
+ kAsioCanReportOverload = 0x24042012, /* return ASE_SUCCESS if driver can detect and report overloads */\r
+ \r
+ kAsioGetInternalBufferSamples = 0x25042012 /* ASIOInternalBufferInfo * in params. Deliver size of driver internal buffering, return ASE_SUCCESS if supported */\r
};\r
\r
typedef struct ASIOInputMonitor\r
char future[512-sizeof(ASIOIoFormatType)];\r
} ASIOIoFormat;\r
\r
+// Extension for drop detection\r
+// Note: Refers to buffering that goes beyond the double buffer e.g. used by USB driver designs\r
+typedef struct ASIOInternalBufferInfo\r
+{\r
+ long inputSamples; // size of driver's internal input buffering which is included in getLatencies\r
+ long outputSamples; // size of driver's internal output buffering which is included in getLatencies\r
+} ASIOInternalBufferInfo;\r
+\r
\r
ASIOError ASIOOutputReady(void);\r
/* Purpose:\r
#ifndef __asiosys__\r
#define __asiosys__\r
\r
- #ifdef WIN32\r
+ #if defined(_WIN32) || defined(_WIN64)\r
#undef MAC \r
#define PPC 0\r
#define WINDOWS 1\r
--- /dev/null
+#pragma once
+
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ devpkey.h
+
+Abstract:
+
+ Defines property keys for the Plug and Play Device Property API.
+
+Author:
+
+ Jim Cavalaris (jamesca) 10-14-2003
+
+Environment:
+
+ User-mode only.
+
+Revision History:
+
+ 14-October-2003 jamesca
+
+ Creation and initial implementation.
+
+ 20-June-2006 dougb
+
+ Copied Jim's version replaced "DEFINE_DEVPROPKEY(DEVPKEY_" with "DEFINE_PROPERTYKEY(PKEY_"
+
+--*/
+
+//#include <devpropdef.h>
+
+//
+// _NAME
+//
+
+DEFINE_PROPERTYKEY(PKEY_NAME, 0xb725f130, 0x47ef, 0x101a, 0xa5, 0xf1, 0x02, 0x60, 0x8c, 0x9e, 0xeb, 0xac, 10); // DEVPROP_TYPE_STRING
+
+//
+// Device properties
+// These PKEYs correspond to the old setupapi SPDRP_XXX properties
+//
+DEFINE_PROPERTYKEY(PKEY_Device_DeviceDesc, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 2); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_HardwareIds, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 3); // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_Device_CompatibleIds, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 4); // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_Device_Service, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 6); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_Class, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 9); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_ClassGuid, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 10); // DEVPROP_TYPE_GUID
+DEFINE_PROPERTYKEY(PKEY_Device_Driver, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 11); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_ConfigFlags, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 12); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_Manufacturer, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 13); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 14); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_LocationInfo, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 15); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_PDOName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 16); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_Capabilities, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 17); // DEVPROP_TYPE_UNINT32
+DEFINE_PROPERTYKEY(PKEY_Device_UINumber, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 18); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_UpperFilters, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 19); // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_Device_LowerFilters, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 20); // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_Device_BusTypeGuid, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 21); // DEVPROP_TYPE_GUID
+DEFINE_PROPERTYKEY(PKEY_Device_LegacyBusType, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 22); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_BusNumber, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 23); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_EnumeratorName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 24); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_Security, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 25); // DEVPROP_TYPE_SECURITY_DESCRIPTOR
+DEFINE_PROPERTYKEY(PKEY_Device_SecuritySDS, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 26); // DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_DevType, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 27); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_Exclusive, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 28); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_Characteristics, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 29); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_Address, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 30); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_UINumberDescFormat, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 31); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_PowerData, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 32); // DEVPROP_TYPE_BINARY
+DEFINE_PROPERTYKEY(PKEY_Device_RemovalPolicy, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 33); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_RemovalPolicyDefault, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 34); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_RemovalPolicyOverride, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 35); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_InstallState, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 36); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_LocationPaths, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 37); // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_Device_BaseContainerId, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 38); // DEVPROP_TYPE_GUID
+
+//
+// Device properties
+// These PKEYs correspond to a device's status and problem code
+//
+DEFINE_PROPERTYKEY(PKEY_Device_DevNodeStatus, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 2); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_ProblemCode, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 3); // DEVPROP_TYPE_UINT32
+
+//
+// Device properties
+// These PKEYs correspond to device relations
+//
+DEFINE_PROPERTYKEY(PKEY_Device_EjectionRelations, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 4); // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_Device_RemovalRelations, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 5); // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_Device_PowerRelations, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 6); // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_Device_BusRelations, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 7); // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_Device_Parent, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 8); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_Children, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 9); // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_Device_Siblings, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 10); // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_Device_TransportRelations, 0x4340a6c5, 0x93fa, 0x4706, 0x97, 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 11); // DEVPROP_TYPE_STRING_LIST
+
+//
+// Other Device properties
+//
+DEFINE_PROPERTYKEY(PKEY_Device_Reported, 0x80497100, 0x8c73, 0x48b9, 0xaa, 0xd9, 0xce, 0x38, 0x7e, 0x19, 0xc5, 0x6e, 2); // DEVPROP_TYPE_BOOLEAN
+DEFINE_PROPERTYKEY(PKEY_Device_Legacy, 0x80497100, 0x8c73, 0x48b9, 0xaa, 0xd9, 0xce, 0x38, 0x7e, 0x19, 0xc5, 0x6e, 3); // DEVPROP_TYPE_BOOLEAN
+DEFINE_PROPERTYKEY(PKEY_Device_InstanceId, 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 256); // DEVPROP_TYPE_STRING
+
+DEFINE_PROPERTYKEY(PKEY_Device_ContainerId, 0x8c7ed206, 0x3f8a, 0x4827, 0xb3, 0xab, 0xae, 0x9e, 0x1f, 0xae, 0xfc, 0x6c, 2); // DEVPROP_TYPE_GUID
+
+DEFINE_PROPERTYKEY(PKEY_Device_ModelId, 0x80d81ea6, 0x7473, 0x4b0c, 0x82, 0x16, 0xef, 0xc1, 0x1a, 0x2c, 0x4c, 0x8b, 2); // DEVPROP_TYPE_GUID
+
+DEFINE_PROPERTYKEY(PKEY_Device_FriendlyNameAttributes, 0x80d81ea6, 0x7473, 0x4b0c, 0x82, 0x16, 0xef, 0xc1, 0x1a, 0x2c, 0x4c, 0x8b, 3); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_ManufacturerAttributes, 0x80d81ea6, 0x7473, 0x4b0c, 0x82, 0x16, 0xef, 0xc1, 0x1a, 0x2c, 0x4c, 0x8b, 4); // DEVPROP_TYPE_UINT32
+
+DEFINE_PROPERTYKEY(PKEY_Device_PresenceNotForDevice, 0x80d81ea6, 0x7473, 0x4b0c, 0x82, 0x16, 0xef, 0xc1, 0x1a, 0x2c, 0x4c, 0x8b, 5); // DEVPROP_TYPE_BOOLEAN
+
+
+DEFINE_PROPERTYKEY(PKEY_Numa_Proximity_Domain, 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 1); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_DHP_Rebalance_Policy, 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 2); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_Numa_Node, 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 3); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_BusReportedDeviceDesc, 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 4); // DEVPROP_TYPE_STRING
+
+DEFINE_PROPERTYKEY(PKEY_Device_InstallInProgress, 0x83da6326, 0x97a6, 0x4088, 0x94, 0x53, 0xa1, 0x92, 0x3f, 0x57, 0x3b, 0x29, 9); // DEVPROP_TYPE_BOOLEAN
+
+//
+// Device driver properties
+//
+DEFINE_PROPERTYKEY(PKEY_Device_DriverDate, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 2); // DEVPROP_TYPE_FILETIME
+DEFINE_PROPERTYKEY(PKEY_Device_DriverVersion, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 3); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_DriverDesc, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 4); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_DriverInfPath, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 5); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_DriverInfSection, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 6); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_DriverInfSectionExt, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 7); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_MatchingDeviceId, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 8); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_DriverProvider, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 9); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_DriverPropPageProvider, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 10); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_DriverCoInstallers, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 11); // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_Device_ResourcePickerTags, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 12); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_ResourcePickerExceptions, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 13); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_Device_DriverRank, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 14); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_DriverLogoLevel, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 15); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_Device_NoConnectSound, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 17); // DEVPROP_TYPE_BOOLEAN
+DEFINE_PROPERTYKEY(PKEY_Device_GenericDriverInstalled, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 18); // DEVPROP_TYPE_BOOLEAN
+DEFINE_PROPERTYKEY(PKEY_Device_AdditionalSoftwareRequested, 0xa8b865dd, 0x2e3d, 0x4094, 0xad, 0x97, 0xe5, 0x93, 0xa7, 0xc, 0x75, 0xd6, 19);// DEVPROP_TYPE_BOOLEAN
+
+//
+// Device safe-removal properties
+//
+DEFINE_PROPERTYKEY(PKEY_Device_SafeRemovalRequired, 0xafd97640, 0x86a3, 0x4210, 0xb6, 0x7c, 0x28, 0x9c, 0x41, 0xaa, 0xbe, 0x55, 2); // DEVPROP_TYPE_BOOLEAN
+DEFINE_PROPERTYKEY(PKEY_Device_SafeRemovalRequiredOverride, 0xafd97640, 0x86a3, 0x4210, 0xb6, 0x7c, 0x28, 0x9c, 0x41, 0xaa, 0xbe, 0x55, 3);// DEVPROP_TYPE_BOOLEAN
+
+
+//
+// Device properties that were set by the driver package that was installed
+// on the device.
+//
+DEFINE_PROPERTYKEY(PKEY_DrvPkg_Model, 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 2); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_DrvPkg_VendorWebSite, 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 3); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_DrvPkg_DetailedDescription, 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 4); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_DrvPkg_DocumentationLink, 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 5); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_DrvPkg_Icon, 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 6); // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_DrvPkg_BrandingIcon, 0xcf73bb51, 0x3abf, 0x44a2, 0x85, 0xe0, 0x9a, 0x3d, 0xc7, 0xa1, 0x21, 0x32, 7); // DEVPROP_TYPE_STRING_LIST
+
+//
+// Device setup class properties
+// These PKEYs correspond to the old setupapi SPCRP_XXX properties
+//
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_UpperFilters, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 19); // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_LowerFilters, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 20); // DEVPROP_TYPE_STRING_LIST
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_Security, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 25); // DEVPROP_TYPE_SECURITY_DESCRIPTOR
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_SecuritySDS, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 26); // DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_DevType, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 27); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_Exclusive, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 28); // DEVPROP_TYPE_UINT32
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_Characteristics, 0x4321918b, 0xf69e, 0x470d, 0xa5, 0xde, 0x4d, 0x88, 0xc7, 0x5a, 0xd2, 0x4b, 29); // DEVPROP_TYPE_UINT32
+
+//
+// Device setup class properties
+// These PKEYs correspond to registry values under the device class GUID key
+//
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_Name, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 2); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_ClassName, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 3); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_Icon, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 4); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_ClassInstaller, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 5); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_PropPageProvider, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 6); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_NoInstallClass, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 7); // DEVPROP_TYPE_BOOLEAN
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_NoDisplayClass, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 8); // DEVPROP_TYPE_BOOLEAN
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_SilentInstall, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 9); // DEVPROP_TYPE_BOOLEAN
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_NoUseClass, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 10); // DEVPROP_TYPE_BOOLEAN
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_DefaultService, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 11); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_IconPath, 0x259abffc, 0x50a7, 0x47ce, 0xaf, 0x8, 0x68, 0xc9, 0xa7, 0xd7, 0x33, 0x66, 12); // DEVPROP_TYPE_STRING_LIST
+
+//
+// Other Device setup class properties
+//
+DEFINE_PROPERTYKEY(PKEY_DeviceClass_ClassCoInstallers, 0x713d1703, 0xa2e2, 0x49f5, 0x92, 0x14, 0x56, 0x47, 0x2e, 0xf3, 0xda, 0x5c, 2); // DEVPROP_TYPE_STRING_LIST
+
+//
+// Device interface properties
+//
+DEFINE_PROPERTYKEY(PKEY_DeviceInterface_FriendlyName, 0x026e516e, 0xb814, 0x414b, 0x83, 0xcd, 0x85, 0x6d, 0x6f, 0xef, 0x48, 0x22, 2); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_DeviceInterface_Enabled, 0x026e516e, 0xb814, 0x414b, 0x83, 0xcd, 0x85, 0x6d, 0x6f, 0xef, 0x48, 0x22, 3); // DEVPROP_TYPE_BOOLEAN
+DEFINE_PROPERTYKEY(PKEY_DeviceInterface_ClassGuid, 0x026e516e, 0xb814, 0x414b, 0x83, 0xcd, 0x85, 0x6d, 0x6f, 0xef, 0x48, 0x22, 4); // DEVPROP_TYPE_GUID
+
+//
+// Device interface class properties
+//
+DEFINE_PROPERTYKEY(PKEY_DeviceInterfaceClass_DefaultInterface, 0x14c83a99, 0x0b3f, 0x44b7, 0xbe, 0x4c, 0xa1, 0x78, 0xd3, 0x99, 0x05, 0x64, 2); // DEVPROP_TYPE_STRING
+
+
+
+
//\r
#define ASIO_BIG_ENDIAN 1\r
#define ASIO_CPU_MIPS 1\r
-#elif defined WIN32\r
+#elif defined(_WIN32) || defined(_WIN64)\r
#undef BEOS \r
#undef MAC \r
#undef SGI\r
Typing "./configure --help" will display all the available options. Note that you can provide more than one "--with-" flag to the configure script to enable multiple API support.
-If you wish to use a different compiler than that selected by configure, specify that compiler in the command line (ex. to use CC):
+If you wish to use a different compiler than that selected by configure, specify that compiler in the command line (e.g. to use CC):
./configure CXX=CC
+++ /dev/null
-RtAudio - a set of C++ classes that provide a common API for realtime audio input/output across Linux (native ALSA, JACK, PulseAudio and OSS), Macintosh OS X (CoreAudio and JACK), and Windows (DirectSound, ASIO and WASAPI) operating systems.
-
-By Gary P. Scavone, 2001-2017 (and many other developers!)
-
-This distribution of RtAudio contains the following:
-
-doc: RtAudio documentation (see doc/html/index.html)
-tests: example RtAudio programs
-include: header and source files necessary for ASIO, DS & OSS compilation
-tests/Windows: Visual C++ .net test program workspace and projects
-
-OVERVIEW:
-
-RtAudio is a set of C++ classes that provides a common API (Application Programming Interface) for realtime audio input/output across Linux (native ALSA, JACK, PulseAudio and OSS), Macintosh OS X and Windows (DirectSound, ASIO and WASAPI) operating systems. RtAudio significantly simplifies the process of interacting with computer audio hardware. It was designed with the following objectives:
-
- - object-oriented C++ design
- - simple, common API across all supported platforms
- - only one source and one header file for easy inclusion in programming projects
- - allow simultaneous multi-api support
- - support dynamic connection of devices
- - provide extensive audio device parameter control
- - allow audio device capability probing
- - automatic internal conversion for data format, channel number compensation, (de)interleaving, and byte-swapping
-
-RtAudio incorporates the concept of audio streams, which represent audio output (playback) and/or input (recording). Available audio devices and their capabilities can be enumerated and then specified when opening a stream. Where applicable, multiple API support can be compiled and a particular API specified when creating an RtAudio instance. See the \ref apinotes section for information specific to each of the supported audio APIs.
-
-FURTHER READING:
-
-For complete documentation on RtAudio, see the doc directory of the distribution or surf to http://www.music.mcgill.ca/~gary/rtaudio/.
-
-
-LEGAL AND ETHICAL:
-
-The RtAudio license is similar to the MIT License.
-
- RtAudio: a set of realtime audio i/o C++ classes
- Copyright (c) 2001-2017 Gary P. Scavone
-
- Permission is hereby granted, free of charge, to any person
- obtaining a copy of this software and associated documentation files
- (the "Software"), to deal in the Software without restriction,
- including without limitation the rights to use, copy, modify, merge,
- publish, distribute, sublicense, and/or sell copies of the Software,
- and to permit persons to whom the Software is furnished to do so,
- subject to the following conditions:
-
- The above copyright notice and this permission notice shall be
- included in all copies or substantial portions of the Software.
-
- Any person wishing to distribute modifications to the Software is
- asked to send the modifications to the original developer so that
- they can be incorporated into the canonical version. This is,
- however, not a binding provision of this license.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Requires: @req@
Libs: -L${libdir} -lrtaudio
Libs.private: -lpthread
-Cflags: -pthread -I${includedir} @CPPFLAGS@
+Cflags: -pthread -I${includedir} @api@
--- /dev/null
+#include "rtaudio_c.h"
+#include "RtAudio.h"
+
+#include <cstring>
+
+#define MAX_ERROR_MESSAGE_LENGTH 512
+
+struct rtaudio {
+ RtAudio *audio;
+
+ rtaudio_cb_t cb;
+ void *userdata;
+
+ int has_error;
+ char errmsg[MAX_ERROR_MESSAGE_LENGTH];
+};
+
+const char *rtaudio_version() { return RTAUDIO_VERSION; }
+
+extern "C" const RtAudio::Api rtaudio_compiled_apis[];
+const rtaudio_api_t *rtaudio_compiled_api() {
+ return (rtaudio_api_t *) &rtaudio_compiled_apis[0];
+}
+
+extern "C" const unsigned int rtaudio_num_compiled_apis;
+unsigned int rtaudio_get_num_compiled_apis(void) {
+ return rtaudio_num_compiled_apis;
+}
+
+extern "C" const char* rtaudio_api_names[][2];
+const char *rtaudio_api_name(rtaudio_api_t api) {
+ if (api < 0 || api >= RTAUDIO_API_NUM)
+ return NULL;
+ return rtaudio_api_names[api][0];
+}
+
+const char *rtaudio_api_display_name(rtaudio_api_t api)
+{
+ if (api < 0 || api >= RTAUDIO_API_NUM)
+ return "Unknown";
+ return rtaudio_api_names[api][1];
+}
+
+rtaudio_api_t rtaudio_compiled_api_by_name(const char *name) {
+ RtAudio::Api api = RtAudio::UNSPECIFIED;
+ if (name) {
+ api = RtAudio::getCompiledApiByName(name);
+ }
+ return (rtaudio_api_t)api;
+}
+
+const char *rtaudio_error(rtaudio_t audio) {
+ if (audio->has_error) {
+ return audio->errmsg;
+ }
+ return NULL;
+}
+
+rtaudio_t rtaudio_create(rtaudio_api_t api) {
+ rtaudio_t audio = new struct rtaudio();
+ try {
+ audio->audio = new RtAudio((RtAudio::Api)api);
+ } catch (RtAudioError &err) {
+ audio->has_error = 1;
+ strncpy(audio->errmsg, err.what(), sizeof(audio->errmsg) - 1);
+ }
+ return audio;
+}
+
+void rtaudio_destroy(rtaudio_t audio) { delete audio->audio; }
+
+rtaudio_api_t rtaudio_current_api(rtaudio_t audio) {
+ return (rtaudio_api_t)audio->audio->getCurrentApi();
+}
+
+int rtaudio_device_count(rtaudio_t audio) {
+ return audio->audio->getDeviceCount();
+}
+
+rtaudio_device_info_t rtaudio_get_device_info(rtaudio_t audio, int i) {
+ rtaudio_device_info_t result;
+ std::memset(&result, 0, sizeof(result));
+ try {
+ audio->has_error = 0;
+ RtAudio::DeviceInfo info = audio->audio->getDeviceInfo(i);
+ result.probed = info.probed;
+ result.output_channels = info.outputChannels;
+ result.input_channels = info.inputChannels;
+ result.duplex_channels = info.duplexChannels;
+ result.is_default_output = info.isDefaultOutput;
+ result.is_default_input = info.isDefaultInput;
+ result.native_formats = info.nativeFormats;
+ result.preferred_sample_rate = info.preferredSampleRate;
+ strncpy(result.name, info.name.c_str(), sizeof(result.name) - 1);
+ for (unsigned int j = 0; j < info.sampleRates.size(); j++) {
+ if (j < sizeof(result.sample_rates) / sizeof(result.sample_rates[0])) {
+ result.sample_rates[j] = info.sampleRates[j];
+ }
+ }
+ } catch (RtAudioError &err) {
+ audio->has_error = 1;
+ strncpy(audio->errmsg, err.what(), sizeof(audio->errmsg) - 1);
+ }
+ return result;
+}
+
+unsigned int rtaudio_get_default_output_device(rtaudio_t audio) {
+ return audio->audio->getDefaultOutputDevice();
+}
+
+unsigned int rtaudio_get_default_input_device(rtaudio_t audio) {
+ return audio->audio->getDefaultInputDevice();
+}
+
+static int proxy_cb_func(void *out, void *in, unsigned int nframes, double time,
+ RtAudioStreamStatus status, void *userdata) {
+ rtaudio_t audio = (rtaudio_t)userdata;
+ return audio->cb(out, in, nframes, time, (rtaudio_stream_status_t)status,
+ audio->userdata);
+}
+
+int rtaudio_open_stream(rtaudio_t audio,
+ rtaudio_stream_parameters_t *output_params,
+ rtaudio_stream_parameters_t *input_params,
+ rtaudio_format_t format, unsigned int sample_rate,
+ unsigned int *buffer_frames, rtaudio_cb_t cb,
+ void *userdata, rtaudio_stream_options_t *options,
+ rtaudio_error_cb_t /*errcb*/) {
+ try {
+ audio->has_error = 0;
+ RtAudio::StreamParameters *in = NULL;
+ RtAudio::StreamParameters *out = NULL;
+ RtAudio::StreamOptions *opts = NULL;
+
+ RtAudio::StreamParameters inparams;
+ RtAudio::StreamParameters outparams;
+ RtAudio::StreamOptions stream_opts;
+
+ if (input_params != NULL) {
+ inparams.deviceId = input_params->device_id;
+ inparams.nChannels = input_params->num_channels;
+ inparams.firstChannel = input_params->first_channel;
+ in = &inparams;
+ }
+ if (output_params != NULL) {
+ outparams.deviceId = output_params->device_id;
+ outparams.nChannels = output_params->num_channels;
+ outparams.firstChannel = output_params->first_channel;
+ out = &outparams;
+ }
+
+ if (options != NULL) {
+ stream_opts.flags = (RtAudioStreamFlags)options->flags;
+ stream_opts.numberOfBuffers = options->num_buffers;
+ stream_opts.priority = options->priority;
+ if (strlen(options->name) > 0) {
+ stream_opts.streamName = std::string(options->name);
+ }
+ opts = &stream_opts;
+ }
+ audio->cb = cb;
+ audio->userdata = userdata;
+ audio->audio->openStream(out, in, (RtAudioFormat)format, sample_rate,
+ buffer_frames, proxy_cb_func, (void *)audio, opts,
+ NULL);
+ return 0;
+ } catch (RtAudioError &err) {
+ audio->has_error = 1;
+ strncpy(audio->errmsg, err.what(), sizeof(audio->errmsg) - 1);
+ return -1;
+ }
+}
+
+void rtaudio_close_stream(rtaudio_t audio) { audio->audio->closeStream(); }
+
+int rtaudio_start_stream(rtaudio_t audio) {
+ try {
+ audio->has_error = 0;
+ audio->audio->startStream();
+ } catch (RtAudioError &err) {
+ audio->has_error = 1;
+ strncpy(audio->errmsg, err.what(), sizeof(audio->errmsg) - 1);
+ }
+ return 0;
+}
+
+int rtaudio_stop_stream(rtaudio_t audio) {
+ try {
+ audio->has_error = 0;
+ audio->audio->stopStream();
+ } catch (RtAudioError &err) {
+ audio->has_error = 1;
+ strncpy(audio->errmsg, err.what(), sizeof(audio->errmsg) - 1);
+ }
+ return 0;
+}
+
+int rtaudio_abort_stream(rtaudio_t audio) {
+ try {
+ audio->has_error = 0;
+ audio->audio->abortStream();
+ } catch (RtAudioError &err) {
+ audio->has_error = 1;
+ strncpy(audio->errmsg, err.what(), sizeof(audio->errmsg) - 1);
+ }
+ return 0;
+}
+
+int rtaudio_is_stream_open(rtaudio_t audio) {
+ return !!audio->audio->isStreamOpen();
+}
+
+int rtaudio_is_stream_running(rtaudio_t audio) {
+ return !!audio->audio->isStreamRunning();
+}
+
+double rtaudio_get_stream_time(rtaudio_t audio) {
+ try {
+ audio->has_error = 0;
+ return audio->audio->getStreamTime();
+ } catch (RtAudioError &err) {
+ audio->has_error = 1;
+ strncpy(audio->errmsg, err.what(), sizeof(audio->errmsg) - 1);
+ return 0;
+ }
+}
+
+void rtaudio_set_stream_time(rtaudio_t audio, double time) {
+ try {
+ audio->has_error = 0;
+ audio->audio->setStreamTime(time);
+ } catch (RtAudioError &err) {
+ audio->has_error = 1;
+ strncpy(audio->errmsg, err.what(), sizeof(audio->errmsg) - 1);
+ }
+}
+
+int rtaudio_get_stream_latency(rtaudio_t audio) {
+ try {
+ audio->has_error = 0;
+ return audio->audio->getStreamLatency();
+ } catch (RtAudioError &err) {
+ audio->has_error = 1;
+ strncpy(audio->errmsg, err.what(), sizeof(audio->errmsg) - 1);
+ return -1;
+ }
+}
+
+unsigned int rtaudio_get_stream_sample_rate(rtaudio_t audio) {
+ try {
+ return audio->audio->getStreamSampleRate();
+ } catch (RtAudioError &err) {
+ audio->has_error = 1;
+ strncpy(audio->errmsg, err.what(), sizeof(audio->errmsg) - 1);
+ return -1;
+ }
+}
+
+void rtaudio_show_warnings(rtaudio_t audio, int show) {
+ audio->audio->showWarnings(!!show);
+}
--- /dev/null
+#ifndef RTAUDIO_C_H
+#define RTAUDIO_C_H
+
+#if defined(RTAUDIO_EXPORT)
+#if defined _WIN32 || defined __CYGWIN__
+#define RTAUDIOAPI __declspec(dllexport)
+#else
+#define RTAUDIOAPI __attribute__((visibility("default")))
+#endif
+#else
+#define RTAUDIOAPI //__declspec(dllimport)
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef unsigned long rtaudio_format_t;
+
+#define RTAUDIO_FORMAT_SINT8 0x01
+#define RTAUDIO_FORMAT_SINT16 0x02
+#define RTAUDIO_FORMAT_SINT24 0x04
+#define RTAUDIO_FORMAT_SINT32 0x08
+#define RTAUDIO_FORMAT_FLOAT32 0x10
+#define RTAUDIO_FORMAT_FLOAT64 0x20
+
+typedef unsigned int rtaudio_stream_flags_t;
+
+#define RTAUDIO_FLAGS_NONINTERLEAVED 0x1
+#define RTAUDIO_FLAGS_MINIMIZE_LATENCY 0x2
+#define RTAUDIO_FLAGS_HOG_DEVICE 0x4
+#define RTAUDIO_FLAGS_SCHEDULE_REALTIME 0x8
+#define RTAUDIO_FLAGS_ALSA_USE_DEFAULT 0x10
+
+typedef unsigned int rtaudio_stream_status_t;
+
+#define RTAUDIO_STATUS_INPUT_OVERFLOW 0x1
+#define RTAUDIO_STATUS_OUTPUT_UNDERFLOW 0x2
+
+typedef int (*rtaudio_cb_t)(void *out, void *in, unsigned int nFrames,
+ double stream_time, rtaudio_stream_status_t status,
+ void *userdata);
+
+typedef enum rtaudio_error {
+ RTAUDIO_ERROR_WARNING,
+ RTAUDIO_ERROR_DEBUG_WARNING,
+ RTAUDIO_ERROR_UNSPECIFIED,
+ RTAUDIO_ERROR_NO_DEVICES_FOUND,
+ RTAUDIO_ERROR_INVALID_DEVICE,
+ RTAUDIO_ERROR_MEMORY_ERROR,
+ RTAUDIO_ERROR_INVALID_PARAMETER,
+ RTAUDIO_ERROR_INVALID_USE,
+ RTAUDIO_ERROR_DRIVER_ERROR,
+ RTAUDIO_ERROR_SYSTEM_ERROR,
+ RTAUDIO_ERROR_THREAD_ERROR,
+} rtaudio_error_t;
+
+typedef void (*rtaudio_error_cb_t)(rtaudio_error_t err, const char *msg);
+
+typedef enum rtaudio_api {
+ RTAUDIO_API_UNSPECIFIED,
+ RTAUDIO_API_LINUX_ALSA,
+ RTAUDIO_API_LINUX_PULSE,
+ RTAUDIO_API_LINUX_OSS,
+ RTAUDIO_API_UNIX_JACK,
+ RTAUDIO_API_MACOSX_CORE,
+ RTAUDIO_API_WINDOWS_WASAPI,
+ RTAUDIO_API_WINDOWS_ASIO,
+ RTAUDIO_API_WINDOWS_DS,
+ RTAUDIO_API_DUMMY,
+ RTAUDIO_API_NUM,
+} rtaudio_api_t;
+
+#define NUM_SAMPLE_RATES 16
+#define MAX_NAME_LENGTH 512
+typedef struct rtaudio_device_info {
+ int probed;
+ unsigned int output_channels;
+ unsigned int input_channels;
+ unsigned int duplex_channels;
+
+ int is_default_output;
+ int is_default_input;
+
+ rtaudio_format_t native_formats;
+
+ unsigned int preferred_sample_rate;
+ int sample_rates[NUM_SAMPLE_RATES];
+
+ char name[MAX_NAME_LENGTH];
+} rtaudio_device_info_t;
+
+typedef struct rtaudio_stream_parameters {
+ unsigned int device_id;
+ unsigned int num_channels;
+ unsigned int first_channel;
+} rtaudio_stream_parameters_t;
+
+typedef struct rtaudio_stream_options {
+ rtaudio_stream_flags_t flags;
+ unsigned int num_buffers;
+ int priority;
+ char name[MAX_NAME_LENGTH];
+} rtaudio_stream_options_t;
+
+typedef struct rtaudio *rtaudio_t;
+
+RTAUDIOAPI const char *rtaudio_version(void);
+RTAUDIOAPI unsigned int rtaudio_get_num_compiled_apis(void);
+RTAUDIOAPI const rtaudio_api_t *rtaudio_compiled_api(void);
+RTAUDIOAPI const char *rtaudio_api_name(rtaudio_api_t api);
+RTAUDIOAPI const char *rtaudio_api_display_name(rtaudio_api_t api);
+RTAUDIOAPI rtaudio_api_t rtaudio_compiled_api_by_name(const char *name);
+
+RTAUDIOAPI const char *rtaudio_error(rtaudio_t audio);
+
+RTAUDIOAPI rtaudio_t rtaudio_create(rtaudio_api_t api);
+RTAUDIOAPI void rtaudio_destroy(rtaudio_t audio);
+
+RTAUDIOAPI rtaudio_api_t rtaudio_current_api(rtaudio_t audio);
+
+RTAUDIOAPI int rtaudio_device_count(rtaudio_t audio);
+RTAUDIOAPI rtaudio_device_info_t rtaudio_get_device_info(rtaudio_t audio,
+ int i);
+RTAUDIOAPI unsigned int rtaudio_get_default_output_device(rtaudio_t audio);
+RTAUDIOAPI unsigned int rtaudio_get_default_input_device(rtaudio_t audio);
+
+RTAUDIOAPI int
+rtaudio_open_stream(rtaudio_t audio, rtaudio_stream_parameters_t *output_params,
+ rtaudio_stream_parameters_t *input_params,
+ rtaudio_format_t format, unsigned int sample_rate,
+ unsigned int *buffer_frames, rtaudio_cb_t cb,
+ void *userdata, rtaudio_stream_options_t *options,
+ rtaudio_error_cb_t errcb);
+RTAUDIOAPI void rtaudio_close_stream(rtaudio_t audio);
+RTAUDIOAPI int rtaudio_start_stream(rtaudio_t audio);
+RTAUDIOAPI int rtaudio_stop_stream(rtaudio_t audio);
+RTAUDIOAPI int rtaudio_abort_stream(rtaudio_t audio);
+
+RTAUDIOAPI int rtaudio_is_stream_open(rtaudio_t audio);
+RTAUDIOAPI int rtaudio_is_stream_running(rtaudio_t audio);
+
+RTAUDIOAPI double rtaudio_get_stream_time(rtaudio_t audio);
+RTAUDIOAPI void rtaudio_set_stream_time(rtaudio_t audio, double time);
+RTAUDIOAPI int rtaudio_get_stream_latency(rtaudio_t audio);
+RTAUDIOAPI unsigned int rtaudio_get_stream_sample_rate(rtaudio_t audio);
+
+RTAUDIOAPI void rtaudio_show_warnings(rtaudio_t audio, int show);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* RTAUDIO_C_H */
include_directories(../include)
endif (WIN32)
+list(GET LIB_TARGETS 0 LIBRTAUDIO)
+
add_executable(audioprobe audioprobe.cpp)
-target_link_libraries(audioprobe rtaudio_static ${LINKLIBS})
+target_link_libraries(audioprobe ${LIBRTAUDIO} ${LINKLIBS})
add_executable(playsaw playsaw.cpp)
-target_link_libraries(playsaw rtaudio_static ${LINKLIBS})
+target_link_libraries(playsaw ${LIBRTAUDIO} ${LINKLIBS})
add_executable(playraw playraw.cpp)
-target_link_libraries(playraw rtaudio_static ${LINKLIBS})
+target_link_libraries(playraw ${LIBRTAUDIO} ${LINKLIBS})
add_executable(record record.cpp)
-target_link_libraries(record rtaudio_static ${LINKLIBS})
+target_link_libraries(record ${LIBRTAUDIO} ${LINKLIBS})
add_executable(duplex duplex.cpp)
-target_link_libraries(duplex rtaudio_static ${LINKLIBS})
+target_link_libraries(duplex ${LIBRTAUDIO} ${LINKLIBS})
+
+add_executable(apinames apinames.cpp)
+target_link_libraries(apinames ${LIBRTAUDIO} ${LINKLIBS})
add_executable(testall testall.cpp)
-target_link_libraries(testall rtaudio_static ${LINKLIBS})
+target_link_libraries(testall ${LIBRTAUDIO} ${LINKLIBS})
add_executable(teststops teststops.cpp)
-target_link_libraries(teststops rtaudio_static ${LINKLIBS})
+target_link_libraries(teststops ${LIBRTAUDIO} ${LINKLIBS})
-noinst_PROGRAMS = audioprobe playsaw playraw record duplex testall teststops
+noinst_PROGRAMS = audioprobe playsaw playraw record duplex apinames testall teststops
AM_CXXFLAGS = -Wall -I$(top_srcdir)
duplex_SOURCES = duplex.cpp
duplex_LDADD = $(top_builddir)/librtaudio.la
+apinames_SOURCES = apinames.cpp
+apinames_LDADD = $(top_builddir)/librtaudio.la
+
testall_SOURCES = testall.cpp
testall_LDADD = $(top_builddir)/librtaudio.la
--- /dev/null
+/******************************************/
+/*
+ apinames.cpp
+ by Jean Pierre Cimalando, 2018.
+
+ This program tests parts of RtAudio related
+ to API names, the conversion from name to API
+ and vice-versa.
+*/
+/******************************************/
+
+#include "RtAudio.h"
+#include <cctype>
+#include <cstdlib>
+#include <iostream>
+
+int test_cpp() {
+ std::vector<RtAudio::Api> apis;
+ RtAudio::getCompiledApi( apis );
+
+ // ensure the known APIs return valid names
+ std::cout << "API names by identifier (C++):\n";
+ for ( size_t i = 0; i < apis.size() ; ++i ) {
+ const std::string name = RtAudio::getApiName(apis[i]);
+ if (name.empty()) {
+ std::cout << "Invalid name for API " << (int)apis[i] << "\n";
+ exit(1);
+ }
+ const std::string displayName = RtAudio::getApiDisplayName(apis[i]);
+ if (displayName.empty()) {
+ std::cout << "Invalid display name for API " << (int)apis[i] << "\n";
+ exit(1);
+ }
+ std::cout << "* " << (int)apis[i] << " '" << name << "': '" << displayName << "'\n";
+ }
+
+ // ensure unknown APIs return the empty string
+ {
+ const std::string name = RtAudio::getApiName((RtAudio::Api)-1);
+ if (!name.empty()) {
+ std::cout << "Bad string for invalid API '" << name << "'\n";
+ exit(1);
+ }
+ const std::string displayName = RtAudio::getApiDisplayName((RtAudio::Api)-1);
+ if (displayName!="Unknown") {
+ std::cout << "Bad display string for invalid API '" << displayName << "'\n";
+ exit(1);
+ }
+ }
+
+ // try getting API identifier by name
+ std::cout << "API identifiers by name (C++):\n";
+ for ( size_t i = 0; i < apis.size() ; ++i ) {
+ std::string name = RtAudio::getApiName(apis[i]);
+ if ( RtAudio::getCompiledApiByName(name) != apis[i] ) {
+ std::cout << "Bad identifier for API '" << name << "'\n";
+ exit( 1 );
+ }
+ std::cout << "* '" << name << "': " << (int)apis[i] << "\n";
+
+ for ( size_t j = 0; j < name.size(); ++j )
+ name[j] = (j & 1) ? toupper(name[j]) : tolower(name[j]);
+ RtAudio::Api api = RtAudio::getCompiledApiByName(name);
+ if ( api != RtAudio::UNSPECIFIED ) {
+ std::cout << "Identifier " << (int)api << " for invalid API '" << name << "'\n";
+ exit( 1 );
+ }
+ }
+
+ // try getting an API identifier by unknown name
+ {
+ RtAudio::Api api;
+ api = RtAudio::getCompiledApiByName("");
+ if ( api != RtAudio::UNSPECIFIED ) {
+ std::cout << "Bad identifier for unknown API name\n";
+ exit( 1 );
+ }
+ }
+
+ return 0;
+}
+
+#include "rtaudio_c.h"
+
+int test_c() {
+ const rtaudio_api_t *apis = rtaudio_compiled_api();
+
+ // ensure the known APIs return valid names
+ std::cout << "API names by identifier (C):\n";
+ for ( size_t i = 0; apis[i] != RTAUDIO_API_UNSPECIFIED; ++i) {
+ const std::string name = rtaudio_api_name(apis[i]);
+ if (name.empty()) {
+ std::cout << "Invalid name for API " << (int)apis[i] << "\n";
+ exit(1);
+ }
+ const std::string displayName = rtaudio_api_display_name(apis[i]);
+ if (displayName.empty()) {
+ std::cout << "Invalid display name for API " << (int)apis[i] << "\n";
+ exit(1);
+ }
+ std::cout << "* " << (int)apis[i] << " '" << name << "': '" << displayName << "'\n";
+ }
+
+ // ensure unknown APIs return the empty string
+ {
+ const char *s = rtaudio_api_name((rtaudio_api_t)-1);
+ const std::string name(s?s:"");
+ if (!name.empty()) {
+ std::cout << "Bad string for invalid API '" << name << "'\n";
+ exit(1);
+ }
+ s = rtaudio_api_display_name((rtaudio_api_t)-1);
+ const std::string displayName(s?s:"");
+ if (displayName!="Unknown") {
+ std::cout << "Bad display string for invalid API '" << displayName << "'\n";
+ exit(1);
+ }
+ }
+
+ // try getting API identifier by name
+ std::cout << "API identifiers by name (C):\n";
+ for ( size_t i = 0; apis[i] != RTAUDIO_API_UNSPECIFIED ; ++i ) {
+ const char *s = rtaudio_api_name(apis[i]);
+ std::string name(s?s:"");
+ if ( rtaudio_compiled_api_by_name(name.c_str()) != apis[i] ) {
+ std::cout << "Bad identifier for API '" << name << "'\n";
+ exit( 1 );
+ }
+ std::cout << "* '" << name << "': " << (int)apis[i] << "\n";
+
+ for ( size_t j = 0; j < name.size(); ++j )
+ name[j] = (j & 1) ? toupper(name[j]) : tolower(name[j]);
+ rtaudio_api_t api = rtaudio_compiled_api_by_name(name.c_str());
+ if ( api != RTAUDIO_API_UNSPECIFIED ) {
+ std::cout << "Identifier " << (int)api << " for invalid API '" << name << "'\n";
+ exit( 1 );
+ }
+ }
+
+ // try getting an API identifier by unknown name
+ {
+ rtaudio_api_t api;
+ api = rtaudio_compiled_api_by_name("");
+ if ( api != RTAUDIO_API_UNSPECIFIED ) {
+ std::cout << "Bad identifier for unknown API name\n";
+ exit( 1 );
+ }
+ }
+
+ return 0;
+}
+
+int main()
+{
+ test_cpp();
+ test_c();
+}
std::map<int, std::string> apiMap;
apiMap[RtAudio::MACOSX_CORE] = "OS-X Core Audio";
apiMap[RtAudio::WINDOWS_ASIO] = "Windows ASIO";
- apiMap[RtAudio::WINDOWS_DS] = "Windows Direct Sound";
+ apiMap[RtAudio::WINDOWS_DS] = "Windows DirectSound";
apiMap[RtAudio::WINDOWS_WASAPI] = "Windows WASAPI";
apiMap[RtAudio::UNIX_JACK] = "Jack Client";
apiMap[RtAudio::LINUX_ALSA] = "Linux ALSA";
info = audio.getDeviceInfo(i);
std::cout << "\nDevice Name = " << info.name << '\n';
+ std::cout << "Device ID = " << i << '\n';
if ( info.probed == false )
std::cout << "Probe Status = UNsuccessful\n";
else {