summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/Audio/DrvHostAudioPulseAudioStubs.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/Audio/DrvHostAudioPulseAudioStubs.cpp')
-rw-r--r--src/VBox/Devices/Audio/DrvHostAudioPulseAudioStubs.cpp375
1 files changed, 375 insertions, 0 deletions
diff --git a/src/VBox/Devices/Audio/DrvHostAudioPulseAudioStubs.cpp b/src/VBox/Devices/Audio/DrvHostAudioPulseAudioStubs.cpp
new file mode 100644
index 00000000..bcaf5a18
--- /dev/null
+++ b/src/VBox/Devices/Audio/DrvHostAudioPulseAudioStubs.cpp
@@ -0,0 +1,375 @@
+/* $Id: DrvHostAudioPulseAudioStubs.cpp $ */
+/** @file
+ * Stubs for libpulse.
+ */
+
+/*
+ * Copyright (C) 2006-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
+#include <iprt/assert.h>
+#include <iprt/errcore.h>
+#include <iprt/ldr.h>
+#include <VBox/log.h>
+#include <iprt/once.h>
+
+#include <pulse/pulseaudio.h>
+
+#include "DrvHostAudioPulseAudioStubs.h"
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+#define VBOX_PULSE_LIB "libpulse.so.0"
+
+#define PROXY_STUB(function, rettype, signature, shortsig) \
+ static rettype (*g_pfn_ ## function) signature; \
+ \
+ extern "C" rettype VBox_##function signature; \
+ rettype VBox_##function signature \
+ { \
+ return g_pfn_ ## function shortsig; \
+ }
+
+#define PROXY_STUB_VOID(function, signature, shortsig) \
+ static void (*g_pfn_ ## function) signature; \
+ \
+ extern "C" void VBox_##function signature; \
+ void VBox_##function signature \
+ { \
+ g_pfn_ ## function shortsig; \
+ }
+
+PROXY_STUB (pa_bytes_per_second, size_t,
+ (const pa_sample_spec *spec),
+ (spec))
+PROXY_STUB (pa_bytes_to_usec, pa_usec_t,
+ (uint64_t l, const pa_sample_spec *spec),
+ (l, spec))
+PROXY_STUB (pa_channel_map_init_auto, pa_channel_map*,
+ (pa_channel_map *m, unsigned channels, pa_channel_map_def_t def),
+ (m, channels, def))
+
+PROXY_STUB (pa_context_connect, int,
+ (pa_context *c, const char *server, pa_context_flags_t flags,
+ const pa_spawn_api *api),
+ (c, server, flags, api))
+PROXY_STUB_VOID(pa_context_disconnect,
+ (pa_context *c),
+ (c))
+PROXY_STUB (pa_context_get_server_info, pa_operation*,
+ (pa_context *c, pa_server_info_cb_t cb, void *userdata),
+ (c, cb, userdata))
+PROXY_STUB (pa_context_get_sink_info_by_name, pa_operation*,
+ (pa_context *c, const char *name, pa_sink_info_cb_t cb, void *userdata),
+ (c, name, cb, userdata))
+PROXY_STUB (pa_context_get_sink_info_list, pa_operation *,
+ (pa_context *c, pa_sink_info_cb_t cb, void *userdata),
+ (c, cb, userdata))
+PROXY_STUB (pa_context_get_source_info_by_name, pa_operation*,
+ (pa_context *c, const char *name, pa_source_info_cb_t cb, void *userdata),
+ (c, name, cb, userdata))
+PROXY_STUB (pa_context_get_source_info_list, pa_operation *,
+ (pa_context *c, pa_source_info_cb_t cb, void *userdata),
+ (c, cb, userdata))
+PROXY_STUB (pa_context_get_state, pa_context_state_t,
+ (pa_context *c),
+ (c))
+PROXY_STUB_VOID(pa_context_unref,
+ (pa_context *c),
+ (c))
+PROXY_STUB (pa_context_errno, int,
+ (pa_context *c),
+ (c))
+PROXY_STUB (pa_context_new, pa_context*,
+ (pa_mainloop_api *mainloop, const char *name),
+ (mainloop, name))
+PROXY_STUB_VOID(pa_context_set_state_callback,
+ (pa_context *c, pa_context_notify_cb_t cb, void *userdata),
+ (c, cb, userdata))
+
+PROXY_STUB (pa_frame_size, size_t,
+ (const pa_sample_spec *spec),
+ (spec))
+PROXY_STUB (pa_get_library_version, const char *, (void), ())
+PROXY_STUB_VOID(pa_operation_unref,
+ (pa_operation *o),
+ (o))
+PROXY_STUB (pa_operation_get_state, pa_operation_state_t,
+ (pa_operation *o),
+ (o))
+PROXY_STUB_VOID(pa_operation_cancel,
+ (pa_operation *o),
+ (o))
+
+PROXY_STUB (pa_rtclock_now, pa_usec_t,
+ (void),
+ ())
+PROXY_STUB (pa_sample_format_to_string, const char*,
+ (pa_sample_format_t f),
+ (f))
+PROXY_STUB (pa_sample_spec_valid, int,
+ (const pa_sample_spec *spec),
+ (spec))
+PROXY_STUB (pa_strerror, const char*,
+ (int error),
+ (error))
+
+#if PA_PROTOCOL_VERSION >= 16
+PROXY_STUB (pa_stream_connect_playback, int,
+ (pa_stream *s, const char *dev, const pa_buffer_attr *attr,
+ pa_stream_flags_t flags, const pa_cvolume *volume, pa_stream *sync_stream),
+ (s, dev, attr, flags, volume, sync_stream))
+#else
+PROXY_STUB (pa_stream_connect_playback, int,
+ (pa_stream *s, const char *dev, const pa_buffer_attr *attr,
+ pa_stream_flags_t flags, pa_cvolume *volume, pa_stream *sync_stream),
+ (s, dev, attr, flags, volume, sync_stream))
+#endif
+PROXY_STUB (pa_stream_connect_record, int,
+ (pa_stream *s, const char *dev, const pa_buffer_attr *attr,
+ pa_stream_flags_t flags),
+ (s, dev, attr, flags))
+PROXY_STUB (pa_stream_disconnect, int,
+ (pa_stream *s),
+ (s))
+PROXY_STUB (pa_stream_get_sample_spec, const pa_sample_spec*,
+ (pa_stream *s),
+ (s))
+PROXY_STUB_VOID(pa_stream_set_latency_update_callback,
+ (pa_stream *p, pa_stream_notify_cb_t cb, void *userdata),
+ (p, cb, userdata))
+PROXY_STUB (pa_stream_write, int,
+ (pa_stream *p, const void *data, size_t bytes, pa_free_cb_t free_cb,
+ int64_t offset, pa_seek_mode_t seek),
+ (p, data, bytes, free_cb, offset, seek))
+PROXY_STUB_VOID(pa_stream_unref,
+ (pa_stream *s),
+ (s))
+PROXY_STUB (pa_stream_get_state, pa_stream_state_t,
+ (pa_stream *p),
+ (p))
+PROXY_STUB (pa_stream_get_latency, int,
+ (pa_stream *s, pa_usec_t *r_usec, int *negative),
+ (s, r_usec, negative))
+PROXY_STUB (pa_stream_get_timing_info, pa_timing_info*,
+ (pa_stream *s),
+ (s))
+PROXY_STUB (pa_stream_readable_size, size_t,
+ (pa_stream *p),
+ (p))
+PROXY_STUB (pa_stream_set_buffer_attr, pa_operation *,
+ (pa_stream *s, const pa_buffer_attr *attr, pa_stream_success_cb_t cb, void *userdata),
+ (s, attr, cb, userdata))
+PROXY_STUB_VOID(pa_stream_set_state_callback,
+ (pa_stream *s, pa_stream_notify_cb_t cb, void *userdata),
+ (s, cb, userdata))
+PROXY_STUB_VOID(pa_stream_set_underflow_callback,
+ (pa_stream *s, pa_stream_notify_cb_t cb, void *userdata),
+ (s, cb, userdata))
+PROXY_STUB_VOID(pa_stream_set_overflow_callback,
+ (pa_stream *s, pa_stream_notify_cb_t cb, void *userdata),
+ (s, cb, userdata))
+PROXY_STUB_VOID(pa_stream_set_write_callback,
+ (pa_stream *s, pa_stream_request_cb_t cb, void *userdata),
+ (s, cb, userdata))
+PROXY_STUB (pa_stream_flush, pa_operation*,
+ (pa_stream *s, pa_stream_success_cb_t cb, void *userdata),
+ (s, cb, userdata))
+PROXY_STUB (pa_stream_drain, pa_operation*,
+ (pa_stream *s, pa_stream_success_cb_t cb, void *userdata),
+ (s, cb, userdata))
+PROXY_STUB (pa_stream_trigger, pa_operation*,
+ (pa_stream *s, pa_stream_success_cb_t cb, void *userdata),
+ (s, cb, userdata))
+PROXY_STUB (pa_stream_new, pa_stream*,
+ (pa_context *c, const char *name, const pa_sample_spec *ss,
+ const pa_channel_map *map),
+ (c, name, ss, map))
+PROXY_STUB (pa_stream_get_buffer_attr, const pa_buffer_attr*,
+ (pa_stream *s),
+ (s))
+PROXY_STUB (pa_stream_peek, int,
+ (pa_stream *p, const void **data, size_t *bytes),
+ (p, data, bytes))
+PROXY_STUB (pa_stream_cork, pa_operation*,
+ (pa_stream *s, int b, pa_stream_success_cb_t cb, void *userdata),
+ (s, b, cb, userdata))
+PROXY_STUB (pa_stream_drop, int,
+ (pa_stream *p),
+ (p))
+PROXY_STUB (pa_stream_writable_size, size_t,
+ (pa_stream *p),
+ (p))
+
+PROXY_STUB_VOID(pa_threaded_mainloop_stop,
+ (pa_threaded_mainloop *m),
+ (m))
+PROXY_STUB (pa_threaded_mainloop_get_api, pa_mainloop_api*,
+ (pa_threaded_mainloop *m),
+ (m))
+PROXY_STUB_VOID(pa_threaded_mainloop_free,
+ (pa_threaded_mainloop* m),
+ (m))
+PROXY_STUB_VOID(pa_threaded_mainloop_signal,
+ (pa_threaded_mainloop *m, int wait_for_accept),
+ (m, wait_for_accept))
+PROXY_STUB_VOID(pa_threaded_mainloop_unlock,
+ (pa_threaded_mainloop *m),
+ (m))
+PROXY_STUB (pa_threaded_mainloop_new, pa_threaded_mainloop *,
+ (void),
+ ())
+PROXY_STUB_VOID(pa_threaded_mainloop_wait,
+ (pa_threaded_mainloop *m),
+ (m))
+PROXY_STUB (pa_threaded_mainloop_start, int,
+ (pa_threaded_mainloop *m),
+ (m))
+PROXY_STUB_VOID(pa_threaded_mainloop_lock,
+ (pa_threaded_mainloop *m),
+ (m))
+
+PROXY_STUB (pa_usec_to_bytes, size_t,
+ (pa_usec_t t, const pa_sample_spec *spec),
+ (t, spec))
+
+#define FUNC_ENTRY(function) { #function , (void (**)(void)) & g_pfn_ ## function }
+static struct
+{
+ const char *pszName;
+ void (**pfn)(void);
+} const g_aImportedFunctions[] =
+{
+ FUNC_ENTRY(pa_bytes_per_second),
+ FUNC_ENTRY(pa_bytes_to_usec),
+ FUNC_ENTRY(pa_channel_map_init_auto),
+
+ FUNC_ENTRY(pa_context_connect),
+ FUNC_ENTRY(pa_context_disconnect),
+ FUNC_ENTRY(pa_context_get_server_info),
+ FUNC_ENTRY(pa_context_get_sink_info_by_name),
+ FUNC_ENTRY(pa_context_get_sink_info_list),
+ FUNC_ENTRY(pa_context_get_source_info_by_name),
+ FUNC_ENTRY(pa_context_get_source_info_list),
+ FUNC_ENTRY(pa_context_get_state),
+ FUNC_ENTRY(pa_context_unref),
+ FUNC_ENTRY(pa_context_errno),
+ FUNC_ENTRY(pa_context_new),
+ FUNC_ENTRY(pa_context_set_state_callback),
+
+ FUNC_ENTRY(pa_frame_size),
+ FUNC_ENTRY(pa_get_library_version),
+ FUNC_ENTRY(pa_operation_unref),
+ FUNC_ENTRY(pa_operation_get_state),
+ FUNC_ENTRY(pa_operation_cancel),
+ FUNC_ENTRY(pa_rtclock_now),
+ FUNC_ENTRY(pa_sample_format_to_string),
+ FUNC_ENTRY(pa_sample_spec_valid),
+ FUNC_ENTRY(pa_strerror),
+
+ FUNC_ENTRY(pa_stream_connect_playback),
+ FUNC_ENTRY(pa_stream_connect_record),
+ FUNC_ENTRY(pa_stream_disconnect),
+ FUNC_ENTRY(pa_stream_get_sample_spec),
+ FUNC_ENTRY(pa_stream_set_latency_update_callback),
+ FUNC_ENTRY(pa_stream_write),
+ FUNC_ENTRY(pa_stream_unref),
+ FUNC_ENTRY(pa_stream_get_state),
+ FUNC_ENTRY(pa_stream_get_latency),
+ FUNC_ENTRY(pa_stream_get_timing_info),
+ FUNC_ENTRY(pa_stream_readable_size),
+ FUNC_ENTRY(pa_stream_set_buffer_attr),
+ FUNC_ENTRY(pa_stream_set_state_callback),
+ FUNC_ENTRY(pa_stream_set_underflow_callback),
+ FUNC_ENTRY(pa_stream_set_overflow_callback),
+ FUNC_ENTRY(pa_stream_set_write_callback),
+ FUNC_ENTRY(pa_stream_flush),
+ FUNC_ENTRY(pa_stream_drain),
+ FUNC_ENTRY(pa_stream_trigger),
+ FUNC_ENTRY(pa_stream_new),
+ FUNC_ENTRY(pa_stream_get_buffer_attr),
+ FUNC_ENTRY(pa_stream_peek),
+ FUNC_ENTRY(pa_stream_cork),
+ FUNC_ENTRY(pa_stream_drop),
+ FUNC_ENTRY(pa_stream_writable_size),
+
+ FUNC_ENTRY(pa_threaded_mainloop_stop),
+ FUNC_ENTRY(pa_threaded_mainloop_get_api),
+ FUNC_ENTRY(pa_threaded_mainloop_free),
+ FUNC_ENTRY(pa_threaded_mainloop_signal),
+ FUNC_ENTRY(pa_threaded_mainloop_unlock),
+ FUNC_ENTRY(pa_threaded_mainloop_new),
+ FUNC_ENTRY(pa_threaded_mainloop_wait),
+ FUNC_ENTRY(pa_threaded_mainloop_start),
+ FUNC_ENTRY(pa_threaded_mainloop_lock),
+
+ FUNC_ENTRY(pa_usec_to_bytes)
+};
+#undef FUNC_ENTRY
+
+/** Init once. */
+static RTONCE g_PulseAudioLibInitOnce = RTONCE_INITIALIZER;
+
+/** @callback_method_impl{FNRTONCE} */
+static DECLCALLBACK(int32_t) drvHostAudioPulseLibInitOnce(void *pvUser)
+{
+ RT_NOREF(pvUser);
+ LogFlowFunc(("\n"));
+
+ RTLDRMOD hMod = NIL_RTLDRMOD;
+ int rc = RTLdrLoadSystemEx(VBOX_PULSE_LIB, RTLDRLOAD_FLAGS_NO_UNLOAD, &hMod);
+ if (RT_SUCCESS(rc))
+ {
+ for (unsigned i = 0; i < RT_ELEMENTS(g_aImportedFunctions); i++)
+ {
+ rc = RTLdrGetSymbol(hMod, g_aImportedFunctions[i].pszName, (void **)g_aImportedFunctions[i].pfn);
+ if (RT_FAILURE(rc))
+ {
+ LogRelFunc(("Failed to resolve function #%u: '%s' (%Rrc)\n", i, g_aImportedFunctions[i].pszName, rc));
+ break;
+ }
+ }
+
+ RTLdrClose(hMod);
+ }
+ else
+ LogRelFunc(("Failed to load library %s: %Rrc\n", VBOX_PULSE_LIB, rc));
+ return rc;
+}
+
+/**
+ * Try to dynamically load the PulseAudio libraries.
+ *
+ * @returns VBox status code.
+ */
+int audioLoadPulseLib(void)
+{
+ LogFlowFunc(("\n"));
+ return RTOnce(&g_PulseAudioLibInitOnce, drvHostAudioPulseLibInitOnce, NULL);
+}
+