Skip to content

Commit

Permalink
PulseAudio Portaudio HostAPI (#336)
Browse files Browse the repository at this point in the history
Adds support for PulseAudio API on Linux.

For more information about Pulseaudio visit: https://www.freedesktop.org/wiki/Software/PulseAudio/

---------

Signed-off-by: Mario Kleiner <[email protected]>
Co-authored-by: sqweek <[email protected]>
Co-authored-by: Daniel Schürmann <[email protected]>
Co-authored-by: Mooneer Salem <[email protected]>
Co-authored-by: Be <[email protected]>
Co-authored-by: Mario Kleiner <[email protected]>
  • Loading branch information
6 people authored Sep 29, 2023
1 parent 67ead0a commit 0dce0e9
Show file tree
Hide file tree
Showing 15 changed files with 3,374 additions and 6 deletions.
18 changes: 18 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,24 @@ elseif(UNIX)
target_compile_definitions(PortAudio PUBLIC PA_USE_AUDIOIO=1)
set(PKGCONFIG_CFLAGS "${PKGCONFIG_CFLAGS} -DPA_USE_AUDIOIO=1")
endif()

find_package(PulseAudio)
cmake_dependent_option(PA_USE_PULSEAUDIO "Enable support for PulseAudio general purpose sound server" ON PulseAudio_FOUND OFF)
if(PA_USE_PULSEAUDIO)
target_link_libraries(PortAudio PRIVATE PulseAudio::PulseAudio)
target_sources(PortAudio PRIVATE
src/hostapi/pulseaudio/pa_linux_pulseaudio_block.c
src/hostapi/pulseaudio/pa_linux_pulseaudio.c
src/hostapi/pulseaudio/pa_linux_pulseaudio_cb.c)

target_compile_definitions(PortAudio PUBLIC PA_USE_PULSEAUDIO=1)
set(PKGCONFIG_CFLAGS "${PKGCONFIG_CFLAGS} -DPA_USE_PULSEAUDIO=1")
set(PKGCONFIG_REQUIRES_PRIVATE "${PKGCONFIG_REQUIRES_PRIVATE} libpulse")

# needed for PortAudioConfig.cmake so `find_package(PortAudio)` works in downstream projects
install(FILES cmake/modules/FindPulseAudio.cmake DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/portaudio/modules")
endif()

endif()
endif()

Expand Down
7 changes: 4 additions & 3 deletions Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ PALIB = libportaudio.la
PAINC = include/portaudio.h

PA_LDFLAGS = $(LDFLAGS) $(SHARED_FLAGS) -rpath $(libdir) -no-undefined \
-export-symbols-regex "(Pa|PaMacCore|PaJack|PaAlsa|PaAsio|PaOSS|PaWasapi|PaWasapiWinrt|PaWinMME)_.*" \
-export-symbols-regex "(Pa|PaMacCore|PaPulseAudio|PaJack|PaAlsa|PaAsio|PaOSS|PaWasapi|PaWasapiWinrt|PaWinMME)_.*" \
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)

COMMON_OBJS = \
Expand All @@ -66,7 +66,7 @@ LOOPBACK_OBJS = \
qa/loopback/src/test_audio_analyzer.o \
qa/loopback/src/write_wav.o \
qa/loopback/src/paqa.o

EXAMPLES = \
bin/pa_devs \
bin/pa_fuzz \
Expand All @@ -82,7 +82,7 @@ SELFTESTS = \
bin/paqa_devs \
bin/paqa_errs \
bin/paqa_latency

TESTS = \
bin/patest1 \
bin/patest_buffer \
Expand Down Expand Up @@ -146,6 +146,7 @@ SRC_DIRS = \
src/hostapi/coreaudio \
src/hostapi/dsound \
src/hostapi/jack \
src/hostapi/pulseaudio \
src/hostapi/oss \
src/hostapi/skeleton \
src/hostapi/wasapi \
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ Please feel free to join. See http://www.portaudio.com for details.
src/hostapi/dsound = Windows Direct Sound
src/hostapi/jack = JACK Audio Connection Kit
src/hostapi/oss = Unix Open Sound System (OSS)
src/hostapi/pulseaudio = Sound system for POSIX OSes
src/hostapi/wasapi = Windows Vista WASAPI
src/hostapi/wdmks = Windows WDM Kernel Streaming
src/hostapi/wmme = Windows MultiMedia Extensions (MME)
Expand Down
147 changes: 147 additions & 0 deletions cmake/modules/FindPulseAudio.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# Copyright 2008 Matthias Kretz <[email protected]>
# Copyright 2009 Marcus Hufgard <[email protected]>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# SPDX-FileCopyrightText: 2008 Matthias Kretz <[email protected]>
# SPDX-FileCopyrightText: 2009 Marcus Hufgard <[email protected]>
#
# SPDX-License-Identifier: BSD-3-Clause

#.rst:
# FindPulseAudio
# --------------
#
# This is base on
# https://invent.kde.org/frameworks/extra-cmake-modules/-/blob/master/find-modules/FindPulseAudio.cmake
#
# Try to locate the PulseAudio library.
# If found, this will define the following variables:
#
# ``PulseAudio_FOUND``
# True if the system has the PulseAudio library of at least
# the minimum version specified by either the version parameter
# to find_package() or the variable PulseAudio_MINIMUM_VERSION
# ``PulseAudio_INCLUDE_DIRS``
# The PulseAudio include directory
# ``PulseAudio_LIBRARIES``
# The PulseAudio libraries for linking
# ``PulseAudio_MAINLOOP_LIBRARY``
# The libraries needed to use PulseAudio Mainloop
# ``PulseAudio_VERSION``
# The version of PulseAudio that was found
# ``PulseAudio_INCLUDE_DIR``
# Deprecated, use ``PulseAudio_INCLUDE_DIRS``
# ``PulseAudio_LIBRARY``
# Deprecated, use ``PulseAudio_LIBRARIES``
#
# If ``PulseAudio_FOUND`` is TRUE, it will also define the following
# imported target:
#
# ``PulseAudio::PulseAudio``
# The PulseAudio library
#
# Since 5.41.0.

# Support PulseAudio_MINIMUM_VERSION for compatibility:
if(NOT PulseAudio_FIND_VERSION)
set(PulseAudio_FIND_VERSION "${PulseAudio_MINIMUM_VERSION}")
endif()

# the minimum version of PulseAudio we require
if(NOT PulseAudio_FIND_VERSION)
set(PulseAudio_FIND_VERSION "1.0.0")
endif()

find_package(PkgConfig)
pkg_check_modules(PC_PulseAudio QUIET libpulse>=${PulseAudio_FIND_VERSION})
pkg_check_modules(PC_PulseAudio_MAINLOOP QUIET libpulse-mainloop-glib)

find_path(PulseAudio_INCLUDE_DIRS pulse/pulseaudio.h
HINTS
${PC_PulseAudio_INCLUDEDIR}
${PC_PulseAudio_INCLUDE_DIRS}
)

find_library(PulseAudio_LIBRARIES NAMES pulse libpulse
HINTS
${PC_PulseAudio_LIBDIR}
${PC_PulseAudio_LIBRARY_DIRS}
)

find_library(PulseAudio_MAINLOOP_LIBRARY
NAMES pulse-mainloop pulse-mainloop-glib libpulse-mainloop-glib
HINTS
${PC_PulseAudio_LIBDIR}
${PC_PulseAudio_LIBRARY_DIRS}
)

# Store the version number in the cache,
# so we don't have to search every time again:
if(PulseAudio_INCLUDE_DIRS AND NOT PulseAudio_VERSION)

# get PulseAudio's version from its version.h
file(STRINGS "${PulseAudio_INCLUDE_DIRS}/pulse/version.h" pulse_version_h
REGEX ".*pa_get_headers_version\\(\\).*")
string(REGEX REPLACE ".*pa_get_headers_version\\(\\)\ \\(\"([0-9]+\\.[0-9]+\\.[0-9]+)[^\"]*\"\\).*" "\\1"
_PulseAudio_VERSION "${pulse_version_h}")

set(PulseAudio_VERSION "${_PulseAudio_VERSION}"
CACHE STRING "Version number of PulseAudio"
FORCE)
endif()

# Use the new extended syntax of
# find_package_handle_standard_args(),
# which also handles version checking:
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(PulseAudio
REQUIRED_VARS PulseAudio_LIBRARIES
PulseAudio_INCLUDE_DIRS
VERSION_VAR PulseAudio_VERSION)

# Deprecated synonyms
set(PulseAudio_INCLUDE_DIR "${PulseAudio_INCLUDE_DIRS}")
set(PulseAudio_LIBRARY "${PulseAudio_LIBRARIES}")
set(PulseAudio_MAINLOOP_LIBRARY "${PulseAudio_MAINLOOP_LIBRARY}")
set(PulseAudio_FOUND "${PulseAudio_FOUND}")

if(PulseAudio_FOUND AND NOT TARGET PulseAudio::PulseAudio)
add_library(PulseAudio::PulseAudio UNKNOWN IMPORTED)
set_target_properties(PulseAudio::PulseAudio PROPERTIES
IMPORTED_LOCATION "${PulseAudio_LIBRARIES}"
INTERFACE_INCLUDE_DIRECTORIES "${PulseAudio_INCLUDE_DIRS}")
endif()

mark_as_advanced(PulseAudio_INCLUDE_DIRS PulseAudio_INCLUDE_DIR
PulseAudio_LIBRARIES PulseAudio_LIBRARY
PulseAudio_MAINLOOP_LIBRARY PulseAudio_MAINLOOP_LIBRARY)

include(FeatureSummary)
set_package_properties(PulseAudio PROPERTIES
URL "https://www.freedesktop.org/wiki/Software/PulseAudio"
DESCRIPTION "Sound server, for sound stream routing and mixing")
29 changes: 28 additions & 1 deletion configure.in
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ AC_ARG_WITH(jack,
AS_HELP_STRING([--with-jack], [Enable support for JACK @<:@autodetect@:>@]),
[with_jack=$withval])

AC_ARG_WITH(pulseaudio,
AS_HELP_STRING([--with-pulseaudio], [Enable support for PulseAudio @<:@autodetect@:>@]),
[with_pulseaudio=$withval])

AC_ARG_WITH(oss,
AS_HELP_STRING([--with-oss], [Enable support for OSS @<:@autodetect@:>@]),
[with_oss=$withval])
Expand Down Expand Up @@ -149,10 +153,17 @@ if test "x$with_oss" != "xno"; then
AC_CHECK_LIB(ossaudio, _oss_ioctl, have_libossaudio=yes, have_libossaudio=no)
fi
fi
if [[ "x$with_jack" != "xno" ] || [ "x$with_pulseaudio" != "xno" ]]; then
PKG_PROG_PKG_CONFIG
fi
have_jack=no
if test "x$with_jack" != "xno"; then
PKG_CHECK_MODULES(JACK, jack, have_jack=yes, have_jack=no)
fi
have_pulse=no
if test "x$with_pulseaudio" != "xno"; then
PKG_CHECK_MODULES(PULSE, libpulse, have_pulse=yes, have_pulse=no)
fi


dnl sizeof checks: we will need a 16-bit and a 32-bit type
Expand Down Expand Up @@ -386,11 +397,26 @@ case "${host_os}" in
if [[ "$have_jack" = "yes" ] && [ "$with_jack" != "no" ]] ; then
DLL_LIBS="$DLL_LIBS $JACK_LIBS"
CFLAGS="$CFLAGS $JACK_CFLAGS"
OTHER_OBJS="$OTHER_OBJS src/hostapi/jack/pa_jack.o src/common/pa_ringbuffer.o"
OTHER_OBJS="$OTHER_OBJS src/hostapi/jack/pa_jack.o"
INCLUDES="$INCLUDES pa_jack.h"
AC_DEFINE(PA_USE_JACK,1)
fi

if [[ "$have_pulse" = "yes" ] || [ "$have_jack" = "yes" ]] ; then
OTHER_OBJS="$OTHER_OBJS src/common/pa_ringbuffer.o"
INCLUDES="$INCLUDES pa_linux_pulseaudio.h"
fi

if [[ "$have_pulse" = "yes" ] && [ "$with_pulse" != "no" ]] ; then
DLL_LIBS="$DLL_LIBS $PULSE_LIBS"
CFLAGS="$CFLAGS $PULSE_CFLAGS"
OTHER_OBJS="$OTHER_OBJS src/hostapi/pulseaudio/pa_linux_pulseaudio_cb.o"
OTHER_OBJS="$OTHER_OBJS src/hostapi/pulseaudio/pa_linux_pulseaudio_block.o"
OTHER_OBJS="$OTHER_OBJS src/hostapi/pulseaudio/pa_linux_pulseaudio.o"
dnl INCLUDES="$INCLUDES pa_pulseaudio.h src/hostapi/pulseaudio/pa_linux_pulseaudio_internal.h src/hostapi/pulseaudio/pa_linux_pulseaudio_block_internal.h src/hostapi/pulseaudio/pa_linux_pulseaudio_cb_internal.h"
AC_DEFINE(PA_USE_PULSEAUDIO,1)
fi

if [[ "$with_oss" != "no" ]] ; then
OTHER_OBJS="$OTHER_OBJS src/hostapi/oss/pa_unix_oss.o"
if [[ "$have_libossaudio" = "yes" ]] ; then
Expand Down Expand Up @@ -489,6 +515,7 @@ case "$target_os" in
AudioIO ..................... $have_audioio
OSS ......................... $have_oss
JACK ........................ $have_jack
PulseAudio .................. $have_pulse
])
;;
esac
79 changes: 79 additions & 0 deletions include/pa_linux_pulseaudio.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#ifndef PA_LINUX_PULSEAUDIO_H
#define PA_LINUX_PULSEAUDIO_H

/*
* $Id$
* PortAudio Portable Real-Time Audio Library
* PulseAudio-specific extensions
*
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

/*
* The text above constitutes the entire PortAudio license; however,
* the PortAudio community also makes the following non-binding requests:
*
* Any person wishing to distribute modifications to the Software is
* requested to send the modifications to the original developer so that
* they can be incorporated into the canonical version. It is also
* requested that these non-binding requests be included along with the
* license above.
*/

/** @file
* @ingroup public_header
* @brief PulseAudio-specific PortAudio API extension header file.
*/

#include "portaudio.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
* Renames the PulseAudio description for the source that is opened
* by PortAudio.
*
* @param s The PortAudio stream to operate on.
* @param streamName The new name/description of the source.
*
* @return paNoError on success or the error encountered otherwise.
*/
PaError PaPulseAudio_RenameSource( PaStream *s, const char *streamName );

/**
* Renames the PulseAudio description for the sink that is opened
* by PortAudio.
*
* @param s The PortAudio stream to operate on.
* @param streamName The new name/description of the sink.
*
* @return paNoError on success or the error encountered otherwise.
*/
PaError PaPulseAudio_RenameSink( PaStream *s, const char *streamName );

#ifdef __cplusplus
}
#endif

#endif
3 changes: 2 additions & 1 deletion include/portaudio.h
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,8 @@ typedef enum PaHostApiTypeId
paJACK=12,
paWASAPI=13,
paAudioScienceHPI=14,
paAudioIO=15
paAudioIO=15,
paPulseAudio=16
} PaHostApiTypeId;


Expand Down
9 changes: 8 additions & 1 deletion src/common/pa_hostapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ are defaulted to 1.
#define PA_USE_SKELETON 1
#endif

#if defined(PA_NO_ASIO) || defined(PA_NO_DS) || defined(PA_NO_WMME) || defined(PA_NO_WASAPI) || defined(PA_NO_WDMKS)
#if defined(PA_NO_PULSEAUDIO) || defined(PA_NO_ASIO) || defined(PA_NO_DS) || defined(PA_NO_WMME) || defined(PA_NO_WASAPI) || defined(PA_NO_WDMKS)
#error "Portaudio: PA_NO_<APINAME> is no longer supported, please remove definition and use PA_USE_<APINAME> instead"
#endif

Expand Down Expand Up @@ -132,6 +132,13 @@ are defaulted to 1.
#define PA_USE_JACK 1
#endif

#ifndef PA_USE_PULSEAUDIO
#define PA_USE_PULSEAUDIO 0
#elif (PA_USE_PULSEAUDIO != 0) && (PA_USE_PULSEAUDIO != 1)
#undef PA_USE_PULSEAUDIO
#define PA_USE_PULSEAUDIO 1
#endif

#ifndef PA_USE_SGI
#define PA_USE_SGI 0
#elif (PA_USE_SGI != 0) && (PA_USE_SGI != 1)
Expand Down
Loading

0 comments on commit 0dce0e9

Please sign in to comment.