[26289] | 1 | /* $Id: DrvHostAudioPulseAudioStubs.cpp 89426 2021-06-01 10:24:18Z vboxsync $ */
|
---|
[6127] | 2 | /** @file
|
---|
| 3 | * Stubs for libpulse.
|
---|
| 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[82968] | 7 | * Copyright (C) 2006-2020 Oracle Corporation
|
---|
[6127] | 8 | *
|
---|
| 9 | * This file is part of VirtualBox Open Source Edition (OSE), as
|
---|
| 10 | * available from http://www.virtualbox.org. This file is free software;
|
---|
| 11 | * you can redistribute it and/or modify it under the terms of the GNU
|
---|
| 12 | * General Public License (GPL) as published by the Free Software
|
---|
| 13 | * Foundation, in version 2 as it comes in the "COPYING" file of the
|
---|
| 14 | * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
|
---|
| 15 | * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
|
---|
| 16 | */
|
---|
[69119] | 17 |
|
---|
[86496] | 18 |
|
---|
| 19 | /*********************************************************************************************************************************
|
---|
| 20 | * Header Files *
|
---|
| 21 | *********************************************************************************************************************************/
|
---|
[56648] | 22 | #define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
|
---|
[6127] | 23 | #include <iprt/assert.h>
|
---|
[89426] | 24 | #include <iprt/errcore.h>
|
---|
[6127] | 25 | #include <iprt/ldr.h>
|
---|
| 26 | #include <VBox/log.h>
|
---|
[89422] | 27 | #include <iprt/once.h>
|
---|
[6127] | 28 |
|
---|
| 29 | #include <pulse/pulseaudio.h>
|
---|
| 30 |
|
---|
[88226] | 31 | #include "DrvHostAudioPulseAudioStubs.h"
|
---|
[6127] | 32 |
|
---|
[86496] | 33 |
|
---|
| 34 | /*********************************************************************************************************************************
|
---|
| 35 | * Defined Constants And Macros *
|
---|
| 36 | *********************************************************************************************************************************/
|
---|
[6127] | 37 | #define VBOX_PULSE_LIB "libpulse.so.0"
|
---|
| 38 |
|
---|
| 39 | #define PROXY_STUB(function, rettype, signature, shortsig) \
|
---|
[26289] | 40 | static rettype (*g_pfn_ ## function) signature; \
|
---|
| 41 | \
|
---|
[88226] | 42 | extern "C" rettype VBox_##function signature; \
|
---|
[45136] | 43 | rettype VBox_##function signature \
|
---|
[26289] | 44 | { \
|
---|
| 45 | return g_pfn_ ## function shortsig; \
|
---|
| 46 | }
|
---|
[6127] | 47 |
|
---|
| 48 | #define PROXY_STUB_VOID(function, signature, shortsig) \
|
---|
[26289] | 49 | static void (*g_pfn_ ## function) signature; \
|
---|
| 50 | \
|
---|
[88226] | 51 | extern "C" void VBox_##function signature; \
|
---|
[45136] | 52 | void VBox_##function signature \
|
---|
[26289] | 53 | { \
|
---|
| 54 | g_pfn_ ## function shortsig; \
|
---|
| 55 | }
|
---|
[6127] | 56 |
|
---|
[67952] | 57 | PROXY_STUB (pa_bytes_per_second, size_t,
|
---|
| 58 | (const pa_sample_spec *spec),
|
---|
| 59 | (spec))
|
---|
| 60 | PROXY_STUB (pa_bytes_to_usec, pa_usec_t,
|
---|
| 61 | (uint64_t l, const pa_sample_spec *spec),
|
---|
| 62 | (l, spec))
|
---|
| 63 | PROXY_STUB (pa_channel_map_init_auto, pa_channel_map*,
|
---|
| 64 | (pa_channel_map *m, unsigned channels, pa_channel_map_def_t def),
|
---|
| 65 | (m, channels, def))
|
---|
| 66 |
|
---|
| 67 | PROXY_STUB (pa_context_connect, int,
|
---|
| 68 | (pa_context *c, const char *server, pa_context_flags_t flags,
|
---|
| 69 | const pa_spawn_api *api),
|
---|
| 70 | (c, server, flags, api))
|
---|
| 71 | PROXY_STUB_VOID(pa_context_disconnect,
|
---|
| 72 | (pa_context *c),
|
---|
| 73 | (c))
|
---|
| 74 | PROXY_STUB (pa_context_get_server_info, pa_operation*,
|
---|
| 75 | (pa_context *c, pa_server_info_cb_t cb, void *userdata),
|
---|
| 76 | (c, cb, userdata))
|
---|
| 77 | PROXY_STUB (pa_context_get_sink_info_by_name, pa_operation*,
|
---|
| 78 | (pa_context *c, const char *name, pa_sink_info_cb_t cb, void *userdata),
|
---|
| 79 | (c, name, cb, userdata))
|
---|
[88478] | 80 | PROXY_STUB (pa_context_get_sink_info_list, pa_operation *,
|
---|
| 81 | (pa_context *c, pa_sink_info_cb_t cb, void *userdata),
|
---|
| 82 | (c, cb, userdata))
|
---|
[67952] | 83 | PROXY_STUB (pa_context_get_source_info_by_name, pa_operation*,
|
---|
| 84 | (pa_context *c, const char *name, pa_source_info_cb_t cb, void *userdata),
|
---|
| 85 | (c, name, cb, userdata))
|
---|
[88478] | 86 | PROXY_STUB (pa_context_get_source_info_list, pa_operation *,
|
---|
| 87 | (pa_context *c, pa_source_info_cb_t cb, void *userdata),
|
---|
| 88 | (c, cb, userdata))
|
---|
[67952] | 89 | PROXY_STUB (pa_context_get_state, pa_context_state_t,
|
---|
| 90 | (pa_context *c),
|
---|
| 91 | (c))
|
---|
| 92 | PROXY_STUB_VOID(pa_context_unref,
|
---|
| 93 | (pa_context *c),
|
---|
| 94 | (c))
|
---|
| 95 | PROXY_STUB (pa_context_errno, int,
|
---|
| 96 | (pa_context *c),
|
---|
| 97 | (c))
|
---|
| 98 | PROXY_STUB (pa_context_new, pa_context*,
|
---|
| 99 | (pa_mainloop_api *mainloop, const char *name),
|
---|
| 100 | (mainloop, name))
|
---|
| 101 | PROXY_STUB_VOID(pa_context_set_state_callback,
|
---|
| 102 | (pa_context *c, pa_context_notify_cb_t cb, void *userdata),
|
---|
| 103 | (c, cb, userdata))
|
---|
| 104 |
|
---|
| 105 | PROXY_STUB (pa_frame_size, size_t,
|
---|
| 106 | (const pa_sample_spec *spec),
|
---|
| 107 | (spec))
|
---|
[73462] | 108 | PROXY_STUB (pa_get_library_version, const char *, (void), ())
|
---|
[67952] | 109 | PROXY_STUB_VOID(pa_operation_unref,
|
---|
| 110 | (pa_operation *o),
|
---|
| 111 | (o))
|
---|
| 112 | PROXY_STUB (pa_operation_get_state, pa_operation_state_t,
|
---|
| 113 | (pa_operation *o),
|
---|
| 114 | (o))
|
---|
| 115 | PROXY_STUB_VOID(pa_operation_cancel,
|
---|
| 116 | (pa_operation *o),
|
---|
| 117 | (o))
|
---|
| 118 |
|
---|
| 119 | PROXY_STUB (pa_rtclock_now, pa_usec_t,
|
---|
| 120 | (void),
|
---|
| 121 | ())
|
---|
| 122 | PROXY_STUB (pa_sample_format_to_string, const char*,
|
---|
| 123 | (pa_sample_format_t f),
|
---|
| 124 | (f))
|
---|
| 125 | PROXY_STUB (pa_sample_spec_valid, int,
|
---|
| 126 | (const pa_sample_spec *spec),
|
---|
| 127 | (spec))
|
---|
| 128 | PROXY_STUB (pa_strerror, const char*,
|
---|
| 129 | (int error),
|
---|
| 130 | (error))
|
---|
| 131 |
|
---|
[22647] | 132 | #if PA_PROTOCOL_VERSION >= 16
|
---|
[6127] | 133 | PROXY_STUB (pa_stream_connect_playback, int,
|
---|
| 134 | (pa_stream *s, const char *dev, const pa_buffer_attr *attr,
|
---|
[22647] | 135 | pa_stream_flags_t flags, const pa_cvolume *volume, pa_stream *sync_stream),
|
---|
| 136 | (s, dev, attr, flags, volume, sync_stream))
|
---|
| 137 | #else
|
---|
| 138 | PROXY_STUB (pa_stream_connect_playback, int,
|
---|
| 139 | (pa_stream *s, const char *dev, const pa_buffer_attr *attr,
|
---|
[6127] | 140 | pa_stream_flags_t flags, pa_cvolume *volume, pa_stream *sync_stream),
|
---|
| 141 | (s, dev, attr, flags, volume, sync_stream))
|
---|
[22647] | 142 | #endif
|
---|
[6127] | 143 | PROXY_STUB (pa_stream_connect_record, int,
|
---|
| 144 | (pa_stream *s, const char *dev, const pa_buffer_attr *attr,
|
---|
| 145 | pa_stream_flags_t flags),
|
---|
| 146 | (s, dev, attr, flags))
|
---|
| 147 | PROXY_STUB (pa_stream_disconnect, int,
|
---|
| 148 | (pa_stream *s),
|
---|
| 149 | (s))
|
---|
| 150 | PROXY_STUB (pa_stream_get_sample_spec, const pa_sample_spec*,
|
---|
| 151 | (pa_stream *s),
|
---|
| 152 | (s))
|
---|
| 153 | PROXY_STUB_VOID(pa_stream_set_latency_update_callback,
|
---|
| 154 | (pa_stream *p, pa_stream_notify_cb_t cb, void *userdata),
|
---|
| 155 | (p, cb, userdata))
|
---|
| 156 | PROXY_STUB (pa_stream_write, int,
|
---|
| 157 | (pa_stream *p, const void *data, size_t bytes, pa_free_cb_t free_cb,
|
---|
| 158 | int64_t offset, pa_seek_mode_t seek),
|
---|
| 159 | (p, data, bytes, free_cb, offset, seek))
|
---|
| 160 | PROXY_STUB_VOID(pa_stream_unref,
|
---|
| 161 | (pa_stream *s),
|
---|
| 162 | (s))
|
---|
| 163 | PROXY_STUB (pa_stream_get_state, pa_stream_state_t,
|
---|
| 164 | (pa_stream *p),
|
---|
| 165 | (p))
|
---|
[67951] | 166 | PROXY_STUB (pa_stream_get_latency, int,
|
---|
| 167 | (pa_stream *s, pa_usec_t *r_usec, int *negative),
|
---|
| 168 | (s, r_usec, negative))
|
---|
| 169 | PROXY_STUB (pa_stream_get_timing_info, pa_timing_info*,
|
---|
| 170 | (pa_stream *s),
|
---|
| 171 | (s))
|
---|
[67952] | 172 | PROXY_STUB (pa_stream_readable_size, size_t,
|
---|
| 173 | (pa_stream *p),
|
---|
| 174 | (p))
|
---|
[67951] | 175 | PROXY_STUB (pa_stream_set_buffer_attr, pa_operation *,
|
---|
| 176 | (pa_stream *s, const pa_buffer_attr *attr, pa_stream_success_cb_t cb, void *userdata),
|
---|
| 177 | (s, attr, cb, userdata))
|
---|
[6127] | 178 | PROXY_STUB_VOID(pa_stream_set_state_callback,
|
---|
| 179 | (pa_stream *s, pa_stream_notify_cb_t cb, void *userdata),
|
---|
| 180 | (s, cb, userdata))
|
---|
[67951] | 181 | PROXY_STUB_VOID(pa_stream_set_underflow_callback,
|
---|
| 182 | (pa_stream *s, pa_stream_notify_cb_t cb, void *userdata),
|
---|
| 183 | (s, cb, userdata))
|
---|
[68039] | 184 | PROXY_STUB_VOID(pa_stream_set_overflow_callback,
|
---|
| 185 | (pa_stream *s, pa_stream_notify_cb_t cb, void *userdata),
|
---|
| 186 | (s, cb, userdata))
|
---|
[67951] | 187 | PROXY_STUB_VOID(pa_stream_set_write_callback,
|
---|
| 188 | (pa_stream *s, pa_stream_request_cb_t cb, void *userdata),
|
---|
| 189 | (s, cb, userdata))
|
---|
[26783] | 190 | PROXY_STUB (pa_stream_flush, pa_operation*,
|
---|
| 191 | (pa_stream *s, pa_stream_success_cb_t cb, void *userdata),
|
---|
| 192 | (s, cb, userdata))
|
---|
[25678] | 193 | PROXY_STUB (pa_stream_drain, pa_operation*,
|
---|
[6127] | 194 | (pa_stream *s, pa_stream_success_cb_t cb, void *userdata),
|
---|
| 195 | (s, cb, userdata))
|
---|
[25678] | 196 | PROXY_STUB (pa_stream_trigger, pa_operation*,
|
---|
| 197 | (pa_stream *s, pa_stream_success_cb_t cb, void *userdata),
|
---|
[26506] | 198 | (s, cb, userdata))
|
---|
[6127] | 199 | PROXY_STUB (pa_stream_new, pa_stream*,
|
---|
| 200 | (pa_context *c, const char *name, const pa_sample_spec *ss,
|
---|
| 201 | const pa_channel_map *map),
|
---|
| 202 | (c, name, ss, map))
|
---|
| 203 | PROXY_STUB (pa_stream_get_buffer_attr, const pa_buffer_attr*,
|
---|
| 204 | (pa_stream *s),
|
---|
| 205 | (s))
|
---|
| 206 | PROXY_STUB (pa_stream_peek, int,
|
---|
| 207 | (pa_stream *p, const void **data, size_t *bytes),
|
---|
| 208 | (p, data, bytes))
|
---|
| 209 | PROXY_STUB (pa_stream_cork, pa_operation*,
|
---|
| 210 | (pa_stream *s, int b, pa_stream_success_cb_t cb, void *userdata),
|
---|
| 211 | (s, b, cb, userdata))
|
---|
| 212 | PROXY_STUB (pa_stream_drop, int,
|
---|
| 213 | (pa_stream *p),
|
---|
| 214 | (p))
|
---|
| 215 | PROXY_STUB (pa_stream_writable_size, size_t,
|
---|
| 216 | (pa_stream *p),
|
---|
| 217 | (p))
|
---|
[67952] | 218 |
|
---|
[6127] | 219 | PROXY_STUB_VOID(pa_threaded_mainloop_stop,
|
---|
| 220 | (pa_threaded_mainloop *m),
|
---|
| 221 | (m))
|
---|
| 222 | PROXY_STUB (pa_threaded_mainloop_get_api, pa_mainloop_api*,
|
---|
| 223 | (pa_threaded_mainloop *m),
|
---|
| 224 | (m))
|
---|
| 225 | PROXY_STUB_VOID(pa_threaded_mainloop_free,
|
---|
| 226 | (pa_threaded_mainloop* m),
|
---|
| 227 | (m))
|
---|
| 228 | PROXY_STUB_VOID(pa_threaded_mainloop_signal,
|
---|
| 229 | (pa_threaded_mainloop *m, int wait_for_accept),
|
---|
| 230 | (m, wait_for_accept))
|
---|
| 231 | PROXY_STUB_VOID(pa_threaded_mainloop_unlock,
|
---|
| 232 | (pa_threaded_mainloop *m),
|
---|
| 233 | (m))
|
---|
| 234 | PROXY_STUB (pa_threaded_mainloop_new, pa_threaded_mainloop *,
|
---|
| 235 | (void),
|
---|
| 236 | ())
|
---|
| 237 | PROXY_STUB_VOID(pa_threaded_mainloop_wait,
|
---|
| 238 | (pa_threaded_mainloop *m),
|
---|
| 239 | (m))
|
---|
| 240 | PROXY_STUB (pa_threaded_mainloop_start, int,
|
---|
| 241 | (pa_threaded_mainloop *m),
|
---|
| 242 | (m))
|
---|
| 243 | PROXY_STUB_VOID(pa_threaded_mainloop_lock,
|
---|
| 244 | (pa_threaded_mainloop *m),
|
---|
| 245 | (m))
|
---|
[67952] | 246 |
|
---|
[67951] | 247 | PROXY_STUB (pa_usec_to_bytes, size_t,
|
---|
| 248 | (pa_usec_t t, const pa_sample_spec *spec),
|
---|
| 249 | (t, spec))
|
---|
[6127] | 250 |
|
---|
[86496] | 251 | #define FUNC_ENTRY(function) { #function , (void (**)(void)) & g_pfn_ ## function }
|
---|
| 252 | static struct
|
---|
[6127] | 253 | {
|
---|
[86496] | 254 | const char *pszName;
|
---|
| 255 | void (**pfn)(void);
|
---|
| 256 | } const g_aImportedFunctions[] =
|
---|
[6127] | 257 | {
|
---|
[86496] | 258 | FUNC_ENTRY(pa_bytes_per_second),
|
---|
| 259 | FUNC_ENTRY(pa_bytes_to_usec),
|
---|
| 260 | FUNC_ENTRY(pa_channel_map_init_auto),
|
---|
[67952] | 261 |
|
---|
[86496] | 262 | FUNC_ENTRY(pa_context_connect),
|
---|
| 263 | FUNC_ENTRY(pa_context_disconnect),
|
---|
| 264 | FUNC_ENTRY(pa_context_get_server_info),
|
---|
| 265 | FUNC_ENTRY(pa_context_get_sink_info_by_name),
|
---|
[88478] | 266 | FUNC_ENTRY(pa_context_get_sink_info_list),
|
---|
[86496] | 267 | FUNC_ENTRY(pa_context_get_source_info_by_name),
|
---|
[88478] | 268 | FUNC_ENTRY(pa_context_get_source_info_list),
|
---|
[86496] | 269 | FUNC_ENTRY(pa_context_get_state),
|
---|
| 270 | FUNC_ENTRY(pa_context_unref),
|
---|
| 271 | FUNC_ENTRY(pa_context_errno),
|
---|
| 272 | FUNC_ENTRY(pa_context_new),
|
---|
| 273 | FUNC_ENTRY(pa_context_set_state_callback),
|
---|
[67952] | 274 |
|
---|
[86496] | 275 | FUNC_ENTRY(pa_frame_size),
|
---|
| 276 | FUNC_ENTRY(pa_get_library_version),
|
---|
| 277 | FUNC_ENTRY(pa_operation_unref),
|
---|
| 278 | FUNC_ENTRY(pa_operation_get_state),
|
---|
| 279 | FUNC_ENTRY(pa_operation_cancel),
|
---|
| 280 | FUNC_ENTRY(pa_rtclock_now),
|
---|
| 281 | FUNC_ENTRY(pa_sample_format_to_string),
|
---|
| 282 | FUNC_ENTRY(pa_sample_spec_valid),
|
---|
| 283 | FUNC_ENTRY(pa_strerror),
|
---|
[67952] | 284 |
|
---|
[86496] | 285 | FUNC_ENTRY(pa_stream_connect_playback),
|
---|
| 286 | FUNC_ENTRY(pa_stream_connect_record),
|
---|
| 287 | FUNC_ENTRY(pa_stream_disconnect),
|
---|
| 288 | FUNC_ENTRY(pa_stream_get_sample_spec),
|
---|
| 289 | FUNC_ENTRY(pa_stream_set_latency_update_callback),
|
---|
| 290 | FUNC_ENTRY(pa_stream_write),
|
---|
| 291 | FUNC_ENTRY(pa_stream_unref),
|
---|
| 292 | FUNC_ENTRY(pa_stream_get_state),
|
---|
| 293 | FUNC_ENTRY(pa_stream_get_latency),
|
---|
| 294 | FUNC_ENTRY(pa_stream_get_timing_info),
|
---|
| 295 | FUNC_ENTRY(pa_stream_readable_size),
|
---|
| 296 | FUNC_ENTRY(pa_stream_set_buffer_attr),
|
---|
| 297 | FUNC_ENTRY(pa_stream_set_state_callback),
|
---|
| 298 | FUNC_ENTRY(pa_stream_set_underflow_callback),
|
---|
| 299 | FUNC_ENTRY(pa_stream_set_overflow_callback),
|
---|
| 300 | FUNC_ENTRY(pa_stream_set_write_callback),
|
---|
| 301 | FUNC_ENTRY(pa_stream_flush),
|
---|
| 302 | FUNC_ENTRY(pa_stream_drain),
|
---|
| 303 | FUNC_ENTRY(pa_stream_trigger),
|
---|
| 304 | FUNC_ENTRY(pa_stream_new),
|
---|
| 305 | FUNC_ENTRY(pa_stream_get_buffer_attr),
|
---|
| 306 | FUNC_ENTRY(pa_stream_peek),
|
---|
| 307 | FUNC_ENTRY(pa_stream_cork),
|
---|
| 308 | FUNC_ENTRY(pa_stream_drop),
|
---|
| 309 | FUNC_ENTRY(pa_stream_writable_size),
|
---|
[67952] | 310 |
|
---|
[86496] | 311 | FUNC_ENTRY(pa_threaded_mainloop_stop),
|
---|
| 312 | FUNC_ENTRY(pa_threaded_mainloop_get_api),
|
---|
| 313 | FUNC_ENTRY(pa_threaded_mainloop_free),
|
---|
| 314 | FUNC_ENTRY(pa_threaded_mainloop_signal),
|
---|
| 315 | FUNC_ENTRY(pa_threaded_mainloop_unlock),
|
---|
| 316 | FUNC_ENTRY(pa_threaded_mainloop_new),
|
---|
| 317 | FUNC_ENTRY(pa_threaded_mainloop_wait),
|
---|
| 318 | FUNC_ENTRY(pa_threaded_mainloop_start),
|
---|
| 319 | FUNC_ENTRY(pa_threaded_mainloop_lock),
|
---|
[67952] | 320 |
|
---|
[86496] | 321 | FUNC_ENTRY(pa_usec_to_bytes)
|
---|
[6127] | 322 | };
|
---|
[86496] | 323 | #undef FUNC_ENTRY
|
---|
[6127] | 324 |
|
---|
[89422] | 325 | /** Init once. */
|
---|
[89424] | 326 | static RTONCE g_PulseAudioLibInitOnce = RTONCE_INITIALIZER;
|
---|
[89422] | 327 |
|
---|
| 328 | /** @callback_method_impl{FNRTONCE} */
|
---|
[89424] | 329 | static DECLCALLBACK(int32_t) drvHostAudioPulseLibInitOnce(void *pvUser)
|
---|
[6127] | 330 | {
|
---|
[89422] | 331 | RT_NOREF(pvUser);
|
---|
[6127] | 332 | LogFlowFunc(("\n"));
|
---|
[86496] | 333 |
|
---|
[89424] | 334 | RTLDRMOD hMod = NIL_RTLDRMOD;
|
---|
| 335 | int rc = RTLdrLoadSystemEx(VBOX_PULSE_LIB, RTLDRLOAD_FLAGS_NO_UNLOAD, &hMod);
|
---|
[86496] | 336 | if (RT_SUCCESS(rc))
|
---|
[6127] | 337 | {
|
---|
[89422] | 338 | for (unsigned i = 0; i < RT_ELEMENTS(g_aImportedFunctions); i++)
|
---|
[86496] | 339 | {
|
---|
[89424] | 340 | rc = RTLdrGetSymbol(hMod, g_aImportedFunctions[i].pszName, (void **)g_aImportedFunctions[i].pfn);
|
---|
[86496] | 341 | if (RT_FAILURE(rc))
|
---|
| 342 | {
|
---|
| 343 | LogRelFunc(("Failed to resolve function #%u: '%s' (%Rrc)\n", i, g_aImportedFunctions[i].pszName, rc));
|
---|
| 344 | break;
|
---|
| 345 | }
|
---|
| 346 | }
|
---|
[6127] | 347 | }
|
---|
[86496] | 348 | else
|
---|
| 349 | LogRelFunc(("Failed to load library %s: %Rrc\n", VBOX_PULSE_LIB, rc));
|
---|
[6127] | 350 | return rc;
|
---|
| 351 | }
|
---|
[67951] | 352 |
|
---|
[89422] | 353 | /**
|
---|
| 354 | * Try to dynamically load the PulseAudio libraries.
|
---|
| 355 | *
|
---|
[89424] | 356 | * @returns VBox status code.
|
---|
[89422] | 357 | */
|
---|
| 358 | int audioLoadPulseLib(void)
|
---|
| 359 | {
|
---|
| 360 | LogFlowFunc(("\n"));
|
---|
[89424] | 361 | return RTOnce(&g_PulseAudioLibInitOnce, drvHostAudioPulseLibInitOnce, NULL);
|
---|
[89422] | 362 | }
|
---|
| 363 |
|
---|