https://github.com/kinetiknz/cubeb/pull/539

diff --git media/libcubeb/gtest/moz.build media/libcubeb/gtest/moz.build
index 1ff0c02545251..ca364d1ef7845 100644
--- media/libcubeb/gtest/moz.build
+++ media/libcubeb/gtest/moz.build
@@ -67,13 +67,6 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'uikit':
       '-framework CoreFoundation',
       '-framework AudioToolbox',
     ]
-elif CONFIG['OS_TARGET'] == 'OpenBSD':
-    OS_LIBS += [
-        'sndio',
-    ]
-else:
-    OS_LIBS += CONFIG['MOZ_ALSA_LIBS']
-    OS_LIBS += CONFIG['MOZ_PULSEAUDIO_LIBS']
 
 if CONFIG['CC_TYPE'] in ('clang', 'gcc'):
     CXXFLAGS += ['-Wno-error=shadow']
diff --git media/libcubeb/src/cubeb.c media/libcubeb/src/cubeb.c
index 98a735f..db294b3 100644
--- media/libcubeb/src/cubeb.c
+++ media/libcubeb/src/cubeb.c
@@ -180,6 +180,9 @@ cubeb_init(cubeb ** context, char const * context_name, char const * backend_nam
 #if defined(USE_JACK)
     jack_init,
 #endif
+#if defined(USE_SNDIO)
+    sndio_init,
+#endif
 #if defined(USE_ALSA)
     alsa_init,
 #endif
@@ -192,9 +195,6 @@ cubeb_init(cubeb ** context, char const * context_name, char const * backend_nam
 #if defined(USE_WINMM)
     winmm_init,
 #endif
-#if defined(USE_SNDIO)
-    sndio_init,
-#endif
 #if defined(USE_OPENSL)
     opensl_init,
 #endif
diff --git media/libcubeb/src/cubeb_alsa.c media/libcubeb/src/cubeb_alsa.c
index bfd4d8f..a29eed0 100644
--- media/libcubeb/src/cubeb_alsa.c
+++ media/libcubeb/src/cubeb_alsa.c
@@ -14,10 +14,58 @@
 #include <limits.h>
 #include <poll.h>
 #include <unistd.h>
+#include <dlfcn.h>
 #include <alsa/asoundlib.h>
 #include "cubeb/cubeb.h"
 #include "cubeb-internal.h"
 
+#ifdef DISABLE_LIBASOUND_DLOPEN
+#define WRAP(x) x
+#else
+#define WRAP(x) cubeb_##x
+#define LIBASOUND_API_VISIT(X)                   \
+  X(snd_config)                                  \
+  X(snd_config_add)                              \
+  X(snd_config_copy)                             \
+  X(snd_config_delete)                           \
+  X(snd_config_get_id)                           \
+  X(snd_config_get_string)                       \
+  X(snd_config_imake_integer)                    \
+  X(snd_config_search)                           \
+  X(snd_config_search_definition)                \
+  X(snd_lib_error_set_handler)                   \
+  X(snd_pcm_avail_update)                        \
+  X(snd_pcm_close)                               \
+  X(snd_pcm_delay)                               \
+  X(snd_pcm_drain)                               \
+  X(snd_pcm_frames_to_bytes)                     \
+  X(snd_pcm_get_params)                          \
+  X(snd_pcm_hw_params_any)                       \
+  X(snd_pcm_hw_params_get_channels_max)          \
+  X(snd_pcm_hw_params_get_rate)                  \
+  X(snd_pcm_hw_params_set_rate_near)             \
+  X(snd_pcm_hw_params_sizeof)                    \
+  X(snd_pcm_nonblock)                            \
+  X(snd_pcm_open)                                \
+  X(snd_pcm_open_lconf)                          \
+  X(snd_pcm_pause)                               \
+  X(snd_pcm_poll_descriptors)                    \
+  X(snd_pcm_poll_descriptors_count)              \
+  X(snd_pcm_poll_descriptors_revents)            \
+  X(snd_pcm_readi)                               \
+  X(snd_pcm_recover)                             \
+  X(snd_pcm_set_params)                          \
+  X(snd_pcm_start)                               \
+  X(snd_pcm_state)                               \
+  X(snd_pcm_writei)                              \
+
+#define MAKE_TYPEDEF(x) static typeof(x) * cubeb_##x;
+LIBASOUND_API_VISIT(MAKE_TYPEDEF);
+#undef MAKE_TYPEDEF
+/* snd_pcm_hw_params_alloca is actually a macro */
+#define snd_pcm_hw_params_sizeof cubeb_snd_pcm_hw_params_sizeof
+#endif
+
 #define CUBEB_STREAM_MAX 16
 #define CUBEB_WATCHDOG_MS 10000
 
@@ -36,6 +84,7 @@ static struct cubeb_ops const alsa_ops;
 
 struct cubeb {
   struct cubeb_ops const * ops;
+  void * libasound;
 
   pthread_t thread;
 
@@ -245,8 +294,8 @@ set_timeout(struct timeval * timeout, unsigned int ms)
 static void
 stream_buffer_decrement(cubeb_stream * stm, long count)
 {
-  char * bufremains = stm->buffer + snd_pcm_frames_to_bytes(stm->pcm, count);
-  memmove(stm->buffer, bufremains, snd_pcm_frames_to_bytes(stm->pcm, stm->bufframes - count));
+  char * bufremains = stm->buffer + WRAP(snd_pcm_frames_to_bytes)(stm->pcm, count);
+  memmove(stm->buffer, bufremains, WRAP(snd_pcm_frames_to_bytes)(stm->pcm, stm->bufframes - count));
   stm->bufframes -= count;
 }
 
@@ -278,9 +327,9 @@ alsa_process_stream(cubeb_stream * stm)
   /* Call _poll_descriptors_revents() even if we don't use it
      to let underlying plugins clear null events.  Otherwise poll()
      may wake up again and again, producing unnecessary CPU usage. */
-  snd_pcm_poll_descriptors_revents(stm->pcm, stm->fds, stm->nfds, &revents);
+  WRAP(snd_pcm_poll_descriptors_revents)(stm->pcm, stm->fds, stm->nfds, &revents);
 
-  avail = snd_pcm_avail_update(stm->pcm);
+  avail = WRAP(snd_pcm_avail_update)(stm->pcm);
 
   /* Got null event? Bail and wait for another wakeup. */
   if (avail == 0) {
@@ -303,7 +352,7 @@ alsa_process_stream(cubeb_stream * stm)
       // TODO: should it be marked as DRAINING?
     }
 
-    got = snd_pcm_readi(stm->pcm, stm->buffer+stm->bufframes, avail);
+    got = WRAP(snd_pcm_readi)(stm->pcm, stm->buffer+stm->bufframes, avail);
 
     if (got < 0) {
       avail = got; // the error handler below will recover us
@@ -347,7 +396,7 @@ alsa_process_stream(cubeb_stream * stm)
       (!stm->other_stream || stm->other_stream->bufframes > 0)) {
     long got = avail - stm->bufframes;
     void * other_buffer = stm->other_stream ? stm->other_stream->buffer : NULL;
-    char * buftail = stm->buffer + snd_pcm_frames_to_bytes(stm->pcm, stm->bufframes);
+    char * buftail = stm->buffer + WRAP(snd_pcm_frames_to_bytes)(stm->pcm, stm->bufframes);
 
     /* Correct read size to the other stream available frames */
     if (stm->other_stream && got > (snd_pcm_sframes_t) stm->other_stream->bufframes) {
@@ -374,8 +423,8 @@ alsa_process_stream(cubeb_stream * stm)
     long drain_frames = avail - stm->bufframes;
     double drain_time = (double) drain_frames / stm->params.rate;
 
-    char * buftail = stm->buffer + snd_pcm_frames_to_bytes(stm->pcm, stm->bufframes);
-    memset(buftail, 0, snd_pcm_frames_to_bytes(stm->pcm, drain_frames));
+    char * buftail = stm->buffer + WRAP(snd_pcm_frames_to_bytes)(stm->pcm, stm->bufframes);
+    memset(buftail, 0, WRAP(snd_pcm_frames_to_bytes)(stm->pcm, drain_frames));
     stm->bufframes = avail;
 
     /* Mark as draining, unless we're waiting for capture */
@@ -402,7 +451,7 @@ alsa_process_stream(cubeb_stream * stm)
       }
     }
 
-    wrote = snd_pcm_writei(stm->pcm, stm->buffer, avail);
+    wrote = WRAP(snd_pcm_writei)(stm->pcm, stm->buffer, avail);
     if (wrote < 0) {
       avail = wrote; // the error handler below will recover us
     } else {
@@ -415,13 +464,13 @@ alsa_process_stream(cubeb_stream * stm)
 
   /* Got some error? Let's try to recover the stream. */
   if (avail < 0) {
-    avail = snd_pcm_recover(stm->pcm, avail, 0);
+    avail = WRAP(snd_pcm_recover)(stm->pcm, avail, 0);
 
     /* Capture pcm must be started after initial setup/recover */
     if (avail >= 0 &&
         stm->stream_type == SND_PCM_STREAM_CAPTURE &&
-        snd_pcm_state(stm->pcm) == SND_PCM_STATE_PREPARED) {
-      avail = snd_pcm_start(stm->pcm);
+        WRAP(snd_pcm_state)(stm->pcm) == SND_PCM_STATE_PREPARED) {
+      avail = WRAP(snd_pcm_start)(stm->pcm);
     }
   }
 
@@ -537,26 +586,26 @@ get_slave_pcm_node(snd_config_t * lconf, snd_config_t * root_pcm)
 
   slave_def = NULL;
 
-  r = snd_config_search(root_pcm, "slave", &slave_pcm);
+  r = WRAP(snd_config_search)(root_pcm, "slave", &slave_pcm);
   if (r < 0) {
     return NULL;
   }
 
-  r = snd_config_get_string(slave_pcm, &string);
+  r = WRAP(snd_config_get_string)(slave_pcm, &string);
   if (r >= 0) {
-    r = snd_config_search_definition(lconf, "pcm_slave", string, &slave_def);
+    r = WRAP(snd_config_search_definition)(lconf, "pcm_slave", string, &slave_def);
     if (r < 0) {
       return NULL;
     }
   }
 
   do {
-    r = snd_config_search(slave_def ? slave_def : slave_pcm, "pcm", &pcm);
+    r = WRAP(snd_config_search)(slave_def ? slave_def : slave_pcm, "pcm", &pcm);
     if (r < 0) {
       break;
     }
 
-    r = snd_config_get_string(slave_def ? slave_def : slave_pcm, &string);
+    r = WRAP(snd_config_get_string)(slave_def ? slave_def : slave_pcm, &string);
     if (r < 0) {
       break;
     }
@@ -565,7 +614,7 @@ get_slave_pcm_node(snd_config_t * lconf, snd_config_t * root_pcm)
     if (r < 0 || r > (int) sizeof(node_name)) {
       break;
     }
-    r = snd_config_search(lconf, node_name, &pcm);
+    r = WRAP(snd_config_search)(lconf, node_name, &pcm);
     if (r < 0) {
       break;
     }
@@ -574,7 +623,7 @@ get_slave_pcm_node(snd_config_t * lconf, snd_config_t * root_pcm)
   } while (0);
 
   if (slave_def) {
-    snd_config_delete(slave_def);
+    WRAP(snd_config_delete)(slave_def);
   }
 
   return NULL;
@@ -597,22 +646,22 @@ init_local_config_with_workaround(char const * pcm_name)
 
   lconf = NULL;
 
-  if (snd_config == NULL) {
+  if (*WRAP(snd_config) == NULL) {
     return NULL;
   }
 
-  r = snd_config_copy(&lconf, snd_config);
+  r = WRAP(snd_config_copy)(&lconf, *WRAP(snd_config));
   if (r < 0) {
     return NULL;
   }
 
   do {
-    r = snd_config_search_definition(lconf, "pcm", pcm_name, &pcm_node);
+    r = WRAP(snd_config_search_definition)(lconf, "pcm", pcm_name, &pcm_node);
     if (r < 0) {
       break;
     }
 
-    r = snd_config_get_id(pcm_node, &string);
+    r = WRAP(snd_config_get_id)(pcm_node, &string);
     if (r < 0) {
       break;
     }
@@ -621,7 +670,7 @@ init_local_config_with_workaround(char const * pcm_name)
     if (r < 0 || r > (int) sizeof(node_name)) {
       break;
     }
-    r = snd_config_search(lconf, node_name, &pcm_node);
+    r = WRAP(snd_config_search)(lconf, node_name, &pcm_node);
     if (r < 0) {
       break;
     }
@@ -632,12 +681,12 @@ init_local_config_with_workaround(char const * pcm_name)
     }
 
     /* Fetch the PCM node's type, and bail out if it's not the PulseAudio plugin. */
-    r = snd_config_search(pcm_node, "type", &node);
+    r = WRAP(snd_config_search)(pcm_node, "type", &node);
     if (r < 0) {
       break;
     }
 
-    r = snd_config_get_string(node, &string);
+    r = WRAP(snd_config_get_string)(node, &string);
     if (r < 0) {
       break;
     }
@@ -648,18 +697,18 @@ init_local_config_with_workaround(char const * pcm_name)
 
     /* Don't clobber an explicit existing handle_underrun value, set it only
        if it doesn't already exist. */
-    r = snd_config_search(pcm_node, "handle_underrun", &node);
+    r = WRAP(snd_config_search)(pcm_node, "handle_underrun", &node);
     if (r != -ENOENT) {
       break;
     }
 
     /* Disable pcm_pulse's asynchronous underrun handling. */
-    r = snd_config_imake_integer(&node, "handle_underrun", 0);
+    r = WRAP(snd_config_imake_integer)(&node, "handle_underrun", 0);
     if (r < 0) {
       break;
     }
 
-    r = snd_config_add(pcm_node, node);
+    r = WRAP(snd_config_add)(pcm_node, node);
     if (r < 0) {
       break;
     }
@@ -667,7 +716,7 @@ init_local_config_with_workaround(char const * pcm_name)
     return lconf;
   } while (0);
 
-  snd_config_delete(lconf);
+  WRAP(snd_config_delete)(lconf);
 
   return NULL;
 }
@@ -679,9 +728,9 @@ alsa_locked_pcm_open(snd_pcm_t ** pcm, char const * pcm_name, snd_pcm_stream_t s
 
   pthread_mutex_lock(&cubeb_alsa_mutex);
   if (local_config) {
-    r = snd_pcm_open_lconf(pcm, pcm_name, stream, SND_PCM_NONBLOCK, local_config);
+    r = WRAP(snd_pcm_open_lconf)(pcm, pcm_name, stream, SND_PCM_NONBLOCK, local_config);
   } else {
-    r = snd_pcm_open(pcm, pcm_name, stream, SND_PCM_NONBLOCK);
+    r = WRAP(snd_pcm_open)(pcm, pcm_name, stream, SND_PCM_NONBLOCK);
   }
   pthread_mutex_unlock(&cubeb_alsa_mutex);
 
@@ -694,7 +743,7 @@ alsa_locked_pcm_close(snd_pcm_t * pcm)
   int r;
 
   pthread_mutex_lock(&cubeb_alsa_mutex);
-  r = snd_pcm_close(pcm);
+  r = WRAP(snd_pcm_close)(pcm);
   pthread_mutex_unlock(&cubeb_alsa_mutex);
 
   return r;
@@ -750,6 +799,7 @@ silent_error_handler(char const * file, int line, char const * function,
 alsa_init(cubeb ** context, char const * context_name)
 {
   (void)context_name;
+  void * libasound = NULL;
   cubeb * ctx;
   int r;
   int i;
@@ -760,9 +810,27 @@ alsa_init(cubeb ** context, char const * context_name)
   assert(context);
   *context = NULL;
 
+#ifndef DISABLE_LIBASOUND_DLOPEN
+  libasound = dlopen("libasound.so", RTLD_LAZY);
+  if (!libasound) {
+    return CUBEB_ERROR;
+  }
+
+#define LOAD(x) {                               \
+    cubeb_##x = dlsym(libasound, #x);            \
+    if (!cubeb_##x) {                           \
+      dlclose(libasound);                        \
+      return CUBEB_ERROR;                       \
+    }                                           \
+  }
+
+  LIBASOUND_API_VISIT(LOAD);
+#undef LOAD
+#endif
+
   pthread_mutex_lock(&cubeb_alsa_mutex);
   if (!cubeb_alsa_error_handler_set) {
-    snd_lib_error_set_handler(silent_error_handler);
+    WRAP(snd_lib_error_set_handler)(silent_error_handler);
     cubeb_alsa_error_handler_set = 1;
   }
   pthread_mutex_unlock(&cubeb_alsa_mutex);
@@ -771,6 +839,7 @@ alsa_init(cubeb ** context, char const * context_name)
   assert(ctx);
 
   ctx->ops = &alsa_ops;
+  ctx->libasound = libasound;
 
   r = pthread_mutex_init(&ctx->mutex, NULL);
   assert(r == 0);
@@ -819,7 +888,7 @@ alsa_init(cubeb ** context, char const * context_name)
        config fails with EINVAL, the PA PCM is too old for this workaround. */
     if (r == -EINVAL) {
       pthread_mutex_lock(&cubeb_alsa_mutex);
-      snd_config_delete(ctx->local_config);
+      WRAP(snd_config_delete)(ctx->local_config);
       pthread_mutex_unlock(&cubeb_alsa_mutex);
       ctx->local_config = NULL;
     } else if (r >= 0) {
@@ -861,10 +930,14 @@ alsa_destroy(cubeb * ctx)
 
   if (ctx->local_config) {
     pthread_mutex_lock(&cubeb_alsa_mutex);
-    snd_config_delete(ctx->local_config);
+    WRAP(snd_config_delete)(ctx->local_config);
     pthread_mutex_unlock(&cubeb_alsa_mutex);
   }
 
+  if (ctx->libasound) {
+    dlclose(ctx->libasound);
+  }
+
   free(ctx);
 }
 
@@ -948,7 +1021,7 @@ alsa_stream_init_single(cubeb * ctx, cubeb_stream ** stream, char const * stream
     return CUBEB_ERROR;
   }
 
-  r = snd_pcm_nonblock(stm->pcm, 1);
+  r = WRAP(snd_pcm_nonblock)(stm->pcm, 1);
   assert(r == 0);
 
   latency_us = latency_frames * 1e6 / stm->params.rate;
@@ -961,7 +1034,7 @@ alsa_stream_init_single(cubeb * ctx, cubeb_stream ** stream, char const * stream
     latency_us = latency_us < min_latency ? min_latency: latency_us;
   }
 
-  r = snd_pcm_set_params(stm->pcm, format, SND_PCM_ACCESS_RW_INTERLEAVED,
+  r = WRAP(snd_pcm_set_params)(stm->pcm, format, SND_PCM_ACCESS_RW_INTERLEAVED,
                          stm->params.channels, stm->params.rate, 1,
                          latency_us);
   if (r < 0) {
@@ -969,20 +1042,20 @@ alsa_stream_init_single(cubeb * ctx, cubeb_stream ** stream, char const * stream
     return CUBEB_ERROR_INVALID_FORMAT;
   }
 
-  r = snd_pcm_get_params(stm->pcm, &stm->buffer_size, &period_size);
+  r = WRAP(snd_pcm_get_params)(stm->pcm, &stm->buffer_size, &period_size);
   assert(r == 0);
 
   /* Double internal buffer size to have enough space when waiting for the other side of duplex connection */
   stm->buffer_size *= 2;
-  stm->buffer = calloc(1, snd_pcm_frames_to_bytes(stm->pcm, stm->buffer_size));
+  stm->buffer = calloc(1, WRAP(snd_pcm_frames_to_bytes)(stm->pcm, stm->buffer_size));
   assert(stm->buffer);
 
-  stm->nfds = snd_pcm_poll_descriptors_count(stm->pcm);
+  stm->nfds = WRAP(snd_pcm_poll_descriptors_count)(stm->pcm);
   assert(stm->nfds > 0);
 
   stm->saved_fds = calloc(stm->nfds, sizeof(struct pollfd));
   assert(stm->saved_fds);
-  r = snd_pcm_poll_descriptors(stm->pcm, stm->saved_fds, stm->nfds);
+  r = WRAP(snd_pcm_poll_descriptors)(stm->pcm, stm->saved_fds, stm->nfds);
   assert((nfds_t) r == stm->nfds);
 
   if (alsa_register_stream(ctx, stm) != 0) {
@@ -1054,7 +1127,7 @@ alsa_stream_destroy(cubeb_stream * stm)
   pthread_mutex_lock(&stm->mutex);
   if (stm->pcm) {
     if (stm->state == DRAINING) {
-      snd_pcm_drain(stm->pcm);
+      WRAP(snd_pcm_drain)(stm->pcm);
     }
     alsa_locked_pcm_close(stm->pcm);
     stm->pcm = NULL;
@@ -1100,12 +1173,12 @@ alsa_get_max_channel_count(cubeb * ctx, uint32_t * max_channels)
 
   assert(stm);
 
-  r = snd_pcm_hw_params_any(stm->pcm, hw_params);
+  r = WRAP(snd_pcm_hw_params_any)(stm->pcm, hw_params);
   if (r < 0) {
     return CUBEB_ERROR;
   }
 
-  r = snd_pcm_hw_params_get_channels_max(hw_params, max_channels);
+  r = WRAP(snd_pcm_hw_params_get_channels_max)(hw_params, max_channels);
   if (r < 0) {
     return CUBEB_ERROR;
   }
@@ -1126,34 +1199,34 @@ alsa_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate) {
 
   /* get a pcm, disabling resampling, so we get a rate the
    * hardware/dmix/pulse/etc. supports. */
-  r = snd_pcm_open(&pcm, CUBEB_ALSA_PCM_NAME, SND_PCM_STREAM_PLAYBACK, SND_PCM_NO_AUTO_RESAMPLE);
+  r = WRAP(snd_pcm_open)(&pcm, CUBEB_ALSA_PCM_NAME, SND_PCM_STREAM_PLAYBACK, SND_PCM_NO_AUTO_RESAMPLE);
   if (r < 0) {
     return CUBEB_ERROR;
   }
 
-  r = snd_pcm_hw_params_any(pcm, hw_params);
+  r = WRAP(snd_pcm_hw_params_any)(pcm, hw_params);
   if (r < 0) {
-    snd_pcm_close(pcm);
+    WRAP(snd_pcm_close)(pcm);
     return CUBEB_ERROR;
   }
 
-  r = snd_pcm_hw_params_get_rate(hw_params, rate, &dir);
+  r = WRAP(snd_pcm_hw_params_get_rate)(hw_params, rate, &dir);
   if (r >= 0) {
     /* There is a default rate: use it. */
-    snd_pcm_close(pcm);
+    WRAP(snd_pcm_close)(pcm);
     return CUBEB_OK;
   }
 
   /* Use a common rate, alsa may adjust it based on hw/etc. capabilities. */
   *rate = 44100;
 
-  r = snd_pcm_hw_params_set_rate_near(pcm, hw_params, rate, NULL);
+  r = WRAP(snd_pcm_hw_params_set_rate_near)(pcm, hw_params, rate, NULL);
   if (r < 0) {
-    snd_pcm_close(pcm);
+    WRAP(snd_pcm_close)(pcm);
     return CUBEB_ERROR;
   }
 
-  snd_pcm_close(pcm);
+  WRAP(snd_pcm_close)(pcm);
 
   return CUBEB_OK;
 }
@@ -1186,10 +1259,10 @@ alsa_stream_start(cubeb_stream * stm)
   pthread_mutex_lock(&stm->mutex);
   /* Capture pcm must be started after initial setup/recover */
   if (stm->stream_type == SND_PCM_STREAM_CAPTURE &&
-      snd_pcm_state(stm->pcm) == SND_PCM_STATE_PREPARED) {
-    snd_pcm_start(stm->pcm);
+      WRAP(snd_pcm_state)(stm->pcm) == SND_PCM_STATE_PREPARED) {
+    WRAP(snd_pcm_start)(stm->pcm);
   }
-  snd_pcm_pause(stm->pcm, 0);
+  WRAP(snd_pcm_pause)(stm->pcm, 0);
   gettimeofday(&stm->last_activity, NULL);
   pthread_mutex_unlock(&stm->mutex);
 
@@ -1229,7 +1302,7 @@ alsa_stream_stop(cubeb_stream * stm)
   pthread_mutex_unlock(&ctx->mutex);
 
   pthread_mutex_lock(&stm->mutex);
-  snd_pcm_pause(stm->pcm, 1);
+  WRAP(snd_pcm_pause)(stm->pcm, 1);
   pthread_mutex_unlock(&stm->mutex);
 
   return CUBEB_OK;
@@ -1245,8 +1318,8 @@ alsa_stream_get_position(cubeb_stream * stm, uint64_t * position)
   pthread_mutex_lock(&stm->mutex);
 
   delay = -1;
-  if (snd_pcm_state(stm->pcm) != SND_PCM_STATE_RUNNING ||
-      snd_pcm_delay(stm->pcm, &delay) != 0) {
+  if (WRAP(snd_pcm_state)(stm->pcm) != SND_PCM_STATE_RUNNING ||
+      WRAP(snd_pcm_delay)(stm->pcm, &delay) != 0) {
     *position = stm->last_position;
     pthread_mutex_unlock(&stm->mutex);
     return CUBEB_OK;
@@ -1271,7 +1344,7 @@ alsa_stream_get_latency(cubeb_stream * stm, uint32_t * latency)
   snd_pcm_sframes_t delay;
   /* This function returns the delay in frames until a frame written using
      snd_pcm_writei is sent to the DAC. The DAC delay should be < 1ms anyways. */
-  if (snd_pcm_delay(stm->pcm, &delay)) {
+  if (WRAP(snd_pcm_delay)(stm->pcm, &delay)) {
     return CUBEB_ERROR;
   }
 
diff --git media/libcubeb/src/cubeb_sndio.c media/libcubeb/src/cubeb_sndio.c
index 9e99b2c..0559af4 100644
--- media/libcubeb/src/cubeb_sndio.c
+++ media/libcubeb/src/cubeb_sndio.c
@@ -12,6 +12,7 @@
 #include <stdbool.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <dlfcn.h>
 #include <assert.h>
 #include "cubeb/cubeb.h"
 #include "cubeb-internal.h"
@@ -22,10 +23,35 @@
 #define DPR(...) do {} while(0)
 #endif
 
+#ifdef DISABLE_LIBSNDIO_DLOPEN
+#define WRAP(x) x
+#else
+#define WRAP(x) cubeb_##x
+#define LIBSNDIO_API_VISIT(X)                   \
+  X(sio_close)                               \
+  X(sio_eof)                                 \
+  X(sio_getpar)                              \
+  X(sio_initpar)                             \
+  X(sio_onmove)                              \
+  X(sio_open)                                \
+  X(sio_pollfd)                              \
+  X(sio_read)                                \
+  X(sio_revents)                             \
+  X(sio_setpar)                              \
+  X(sio_start)                               \
+  X(sio_stop)                                \
+  X(sio_write)                               \
+
+#define MAKE_TYPEDEF(x) static typeof(x) * cubeb_##x;
+LIBSNDIO_API_VISIT(MAKE_TYPEDEF);
+#undef MAKE_TYPEDEF
+#endif
+
 static struct cubeb_ops const sndio_ops;
 
 struct cubeb {
   struct cubeb_ops const * ops;
+  void * libsndio;
 };
 
 struct cubeb_stream {
@@ -119,7 +145,7 @@ sndio_mainloop(void *arg)
   DPR("sndio_mainloop()\n");
   s->state_cb(s, s->arg, CUBEB_STATE_STARTED);
   pthread_mutex_lock(&s->mtx);
-  if (!sio_start(s->hdl)) {
+  if (!WRAP(sio_start)(s->hdl)) {
     pthread_mutex_unlock(&s->mtx);
     return NULL;
   }
@@ -203,7 +229,7 @@ sndio_mainloop(void *arg)
       events |= POLLIN;
     if ((s->mode & SIO_PLAY) && pstart < pend)
       events |= POLLOUT;
-    nfds = sio_pollfd(s->hdl, pfds, events);
+    nfds = WRAP(sio_pollfd)(s->hdl, pfds, events);
 
     if (nfds > 0) {
       pthread_mutex_unlock(&s->mtx);
@@ -213,7 +239,7 @@ sndio_mainloop(void *arg)
         continue;
     }
 
-    revents = sio_revents(s->hdl, pfds);
+    revents = WRAP(sio_revents)(s->hdl, pfds);
 
     if (revents & POLLHUP) {
       state = CUBEB_STATE_ERROR;
@@ -221,8 +247,8 @@ sndio_mainloop(void *arg)
     }
 
     if (revents & POLLOUT) {
-      n = sio_write(s->hdl, s->pbuf + pstart, pend - pstart);
-      if (n == 0 && sio_eof(s->hdl)) {
+      n = WRAP(sio_write)(s->hdl, s->pbuf + pstart, pend - pstart);
+      if (n == 0 && WRAP(sio_eof)(s->hdl)) {
         DPR("sndio_mainloop() werr\n");
         state = CUBEB_STATE_ERROR;
         break;
@@ -231,8 +257,8 @@ sndio_mainloop(void *arg)
     }
 
     if (revents & POLLIN) {
-      n = sio_read(s->hdl, s->rbuf + rstart, rend - rstart);
-      if (n == 0 && sio_eof(s->hdl)) {
+      n = WRAP(sio_read)(s->hdl, s->rbuf + rstart, rend - rstart);
+      if (n == 0 && WRAP(sio_eof)(s->hdl)) {
         DPR("sndio_mainloop() rerr\n");
         state = CUBEB_STATE_ERROR;
         break;
@@ -244,7 +270,7 @@ sndio_mainloop(void *arg)
     if (prime > 0 && (s->mode & SIO_REC))
       rstart = rend;
   }
-  sio_stop(s->hdl);
+  WRAP(sio_stop)(s->hdl);
   s->hwpos = s->swpos;
   pthread_mutex_unlock(&s->mtx);
   s->state_cb(s, s->arg, state);
@@ -254,8 +280,31 @@ sndio_mainloop(void *arg)
 /*static*/ int
 sndio_init(cubeb **context, char const *context_name)
 {
+  void * libsndio = NULL;
+
+#ifndef DISABLE_LIBSNDIO_DLOPEN
+  libsndio = dlopen("libsndio.so", RTLD_LAZY);
+  if (!libsndio) {
+    DPR("sndio_init(%s) failed dlopen(libsndio.so)\n", context_name);
+    return CUBEB_ERROR;
+  }
+
+#define LOAD(x) {                               \
+    cubeb_##x = dlsym(libsndio, #x);            \
+    if (!cubeb_##x) {                           \
+      DPR("sndio_init(%s) failed dlsym(%s)\n", context_name, #x); \
+      dlclose(libsndio);                        \
+      return CUBEB_ERROR;                       \
+    }                                           \
+  }
+
+  LIBSNDIO_API_VISIT(LOAD);
+#undef LOAD
+#endif
+
   DPR("sndio_init(%s)\n", context_name);
   *context = malloc(sizeof(*context));
+  (*context)->libsndio = libsndio;
   (*context)->ops = &sndio_ops;
   (void)context_name;
   return CUBEB_OK;
@@ -271,6 +320,8 @@ static void
 sndio_destroy(cubeb *context)
 {
   DPR("sndio_destroy()\n");
+  if (context->libsndio)
+    dlclose(context->libsndio);
   free(context);
 }
 
@@ -323,12 +374,12 @@ sndio_stream_init(cubeb * context,
     goto err;
   }
   s->context = context;
-  s->hdl = sio_open(NULL, s->mode, 1);
+  s->hdl = WRAP(sio_open)(NULL, s->mode, 1);
   if (s->hdl == NULL) {
     DPR("sndio_stream_init(), sio_open() failed\n");
     goto err;
   }
-  sio_initpar(&wpar);
+  WRAP(sio_initpar)(&wpar);
   wpar.sig = 1;
   wpar.bits = 16;
   switch (format) {
@@ -351,7 +402,7 @@ sndio_stream_init(cubeb * context,
   if (s->mode & SIO_PLAY)
     wpar.pchan = output_stream_params->channels;
   wpar.appbufsz = latency_frames;
-  if (!sio_setpar(s->hdl, &wpar) || !sio_getpar(s->hdl, &rpar)) {
+  if (!WRAP(sio_setpar)(s->hdl, &wpar) || !WRAP(sio_getpar)(s->hdl, &rpar)) {
     DPR("sndio_stream_init(), sio_setpar() failed\n");
     goto err;
   }
@@ -362,7 +413,7 @@ sndio_stream_init(cubeb * context,
     DPR("sndio_stream_init() unsupported params\n");
     goto err;
   }
-  sio_onmove(s->hdl, sndio_onmove, s);
+  WRAP(sio_onmove)(s->hdl, sndio_onmove, s);
   s->active = 0;
   s->nfr = rpar.round;
   s->rbpf = rpar.bps * rpar.rchan;
@@ -400,7 +451,7 @@ sndio_stream_init(cubeb * context,
   return CUBEB_OK;
 err:
   if (s->hdl)
-    sio_close(s->hdl);
+    WRAP(sio_close)(s->hdl);
   if (s->pbuf)
     free(s->pbuf);
   if (s->rbuf)
@@ -446,7 +497,7 @@ static void
 sndio_stream_destroy(cubeb_stream *s)
 {
   DPR("sndio_stream_destroy()\n");
-  sio_close(s->hdl);
+  WRAP(sio_close)(s->hdl);
   if (s->mode & SIO_PLAY)
     free(s->pbuf);
   if (s->mode & SIO_REC)
diff --git toolkit/library/moz.build toolkit/library/moz.build
index 8ce595ff96bff..c318e96a1fdfc 100644
--- toolkit/library/moz.build
+++ toolkit/library/moz.build
@@ -231,9 +231,6 @@ if CONFIG['MOZ_SYSTEM_LIBVPX']:
 if not CONFIG['MOZ_TREE_PIXMAN']:
     OS_LIBS += CONFIG['MOZ_PIXMAN_LIBS']
 
-if CONFIG['MOZ_ALSA']:
-    OS_LIBS += CONFIG['MOZ_ALSA_LIBS']
-
 if CONFIG['HAVE_CLOCK_MONOTONIC']:
     OS_LIBS += CONFIG['REALTIME_LIBS']
 
@@ -242,11 +239,6 @@ OS_LIBS += CONFIG['ICONV_LIBS']
 if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('cocoa', 'uikit'):
     OS_LIBS += CONFIG['TK_LIBS']
 
-if CONFIG['OS_ARCH'] == 'OpenBSD':
-    OS_LIBS += [
-        'sndio',
-    ]
-
 if CONFIG['MOZ_ENABLE_DBUS']:
     OS_LIBS += CONFIG['MOZ_DBUS_GLIB_LIBS']
 
