Bug 1440538 - P4: Update cubeb-pulse-rs to commit f58dc34. r?kinetik draft
authorDan Glastonbury <dan.glastonbury@gmail.com>
Fri, 23 Feb 2018 12:54:14 +1000
changeset 758838 2e5bf62152c354631092073f3f5326af3e6ff83a
parent 758837 161cc5e219c3545047c03dea1d49b7a466626e26
child 758839 71b344bf123e7f4007c524366d2672d8c0558447
child 759616 83a78e274691bb8c19b4fb30ee7936df57c481ac
push id100192
push userbmo:dglastonbury@mozilla.com
push dateFri, 23 Feb 2018 04:06:09 +0000
reviewerskinetik
bugs1440538
milestone60.0a1
Bug 1440538 - P4: Update cubeb-pulse-rs to commit f58dc34. r?kinetik MozReview-Commit-ID: 5eQV3nUceQe
media/libcubeb/cubeb-pulse-rs/Cargo.toml
media/libcubeb/cubeb-pulse-rs/README_MOZILLA
media/libcubeb/cubeb-pulse-rs/cubeb-ffi/Cargo.toml
media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/ffi.rs
media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/lib.rs
media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/log.rs
media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/mixer.rs
media/libcubeb/cubeb-pulse-rs/src/backend/context.rs
media/libcubeb/cubeb-pulse-rs/src/backend/cork_state.rs
media/libcubeb/cubeb-pulse-rs/src/backend/intern.rs
media/libcubeb/cubeb-pulse-rs/src/backend/mixer.rs
media/libcubeb/cubeb-pulse-rs/src/backend/mod.rs
media/libcubeb/cubeb-pulse-rs/src/backend/stream.rs
media/libcubeb/cubeb-pulse-rs/src/capi.rs
media/libcubeb/cubeb-pulse-rs/src/lib.rs
--- a/media/libcubeb/cubeb-pulse-rs/Cargo.toml
+++ b/media/libcubeb/cubeb-pulse-rs/Cargo.toml
@@ -1,17 +1,17 @@
 [package]
 name = "cubeb-pulse"
-version = "0.0.2"
+version = "0.1.1"
 authors = ["Dan Glastonbury <dglastonbury@mozilla.com>"]
 description = "Cubeb backed for PulseAudio written in Rust"
 
 [features]
 pulse-dlopen = ["pulse-ffi/dlopen"]
 
 [lib]
 crate-type = ["staticlib", "rlib"]
 
 [dependencies]
-cubeb-ffi = { path = "cubeb-ffi" }
+cubeb-backend = "0.4"
 pulse-ffi = { path = "pulse-ffi" }
 pulse = { path = "pulse-rs" }
 semver = "^0.6"
--- a/media/libcubeb/cubeb-pulse-rs/README_MOZILLA
+++ b/media/libcubeb/cubeb-pulse-rs/README_MOZILLA
@@ -1,8 +1,8 @@
 The source from this directory was copied from the cubeb-pulse-rs
 git repository using the update.sh script.  The only changes
 made were those applied by update.sh and the addition of
 Makefile.in build files for the Mozilla build system.
 
 The cubeb-pulse-rs git repository is: https://github.com/djg/cubeb-pulse-rs.git
 
-The git commit ID used was deadde7d14e0010628471e33a538a0a1e59765ff (2018-01-25 10:00:16 +1000)
+The git commit ID used was f58dc34c5af519352aed4b4cd79bb34060e59c65 (2018-02-23 11:16:40 +1000)
deleted file mode 100644
--- a/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/Cargo.toml
+++ /dev/null
@@ -1,8 +0,0 @@
-[package]
-name = "cubeb-ffi"
-version = "0.0.2"
-authors = ["Dan Glastonbury <dglastonbury@mozilla.com>"]
-description = "FFI bindings for implementing cubeb backends"
-
-[dependencies]
-bitflags = "1.0"
deleted file mode 100644
--- a/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/ffi.rs
+++ /dev/null
@@ -1,508 +0,0 @@
-// Copyright © 2017 Mozilla Foundation
-//
-// This program is made available under an ISC-style license.  See the
-// accompanying file LICENSE for details.
-
-use std::default::Default;
-use std::os::raw::{c_char, c_int, c_long, c_uint, c_void};
-use std::ptr;
-
-pub enum Context {}
-pub enum Stream {}
-
-// These need to match cubeb_sample_format
-pub type SampleFormat = c_int;
-pub const SAMPLE_S16LE: SampleFormat = 0;
-pub const SAMPLE_S16BE: SampleFormat = 1;
-pub const SAMPLE_FLOAT32LE: SampleFormat = 2;
-pub const SAMPLE_FLOAT32BE: SampleFormat = 3;
-
-#[cfg(target_endian = "little")]
-pub const SAMPLE_S16NE: SampleFormat = SAMPLE_S16LE;
-#[cfg(target_endian = "little")]
-pub const SAMPLE_FLOAT32NE: SampleFormat = SAMPLE_FLOAT32LE;
-#[cfg(target_endian = "big")]
-pub const SAMPLE_S16NE: SampleFormat = SAMPLE_S16BE;
-#[cfg(target_endian = "big")]
-pub const SAMPLE_FLOAT32NE: SampleFormat = SAMPLE_FLOAT32BE;
-
-pub type DeviceId = *const c_void;
-
-// These need to match cubeb_channel_layout
-pub type ChannelLayout = c_int;
-pub const LAYOUT_UNDEFINED: ChannelLayout = 0;
-pub const LAYOUT_DUAL_MONO: ChannelLayout = 1;
-pub const LAYOUT_DUAL_MONO_LFE: ChannelLayout = 2;
-pub const LAYOUT_MONO: ChannelLayout = 3;
-pub const LAYOUT_MONO_LFE: ChannelLayout = 4;
-pub const LAYOUT_STEREO: ChannelLayout = 5;
-pub const LAYOUT_STEREO_LFE: ChannelLayout = 6;
-pub const LAYOUT_3F: ChannelLayout = 7;
-pub const LAYOUT_3F_LFE: ChannelLayout = 8;
-pub const LAYOUT_2F1: ChannelLayout = 9;
-pub const LAYOUT_2F1_LFE: ChannelLayout = 10;
-pub const LAYOUT_3F1: ChannelLayout = 11;
-pub const LAYOUT_3F1_LFE: ChannelLayout = 12;
-pub const LAYOUT_2F2: ChannelLayout = 13;
-pub const LAYOUT_2F2_LFE: ChannelLayout = 14;
-pub const LAYOUT_3F2: ChannelLayout = 15;
-pub const LAYOUT_3F2_LFE: ChannelLayout = 16;
-pub const LAYOUT_3F3R_LFE: ChannelLayout = 17;
-pub const LAYOUT_3F4_LFE: ChannelLayout = 18;
-pub const LAYOUT_MAX: ChannelLayout = 256;
-
-
-// These need to match cubeb_device_type
-bitflags! {
-    #[repr(C)]
-    pub struct StreamPrefs : u32 {
-        const STREAM_PREF_NONE = 0x00;
-        const STREAM_PREF_LOOPBACK = 0x01;
-    }
-}
-
-#[repr(C)]
-#[derive(Clone, Copy, Debug)]
-pub struct StreamParams {
-    pub format: SampleFormat,
-    pub rate: u32,
-    pub channels: u32,
-    pub layout: ChannelLayout,
-    pub prefs: StreamPrefs,
-}
-
-#[repr(C)]
-#[derive(Clone, Copy, Debug)]
-pub struct Device {
-    pub output_name: *mut c_char,
-    pub input_name: *mut c_char,
-}
-
-impl Default for Device {
-    fn default() -> Self {
-        Device {
-            output_name: ptr::null_mut(),
-            input_name: ptr::null_mut(),
-        }
-    }
-}
-
-// These need to match cubeb_state
-pub type State = c_int;
-pub const STATE_STARTED: State = 0;
-pub const STATE_STOPPED: State = 1;
-pub const STATE_DRAINED: State = 2;
-pub const STATE_ERROR: State = 3;
-
-pub const OK: i32 = 0;
-pub const ERROR: i32 = -1;
-pub const ERROR_INVALID_FORMAT: i32 = -2;
-pub const ERROR_INVALID_PARAMETER: i32 = -3;
-pub const ERROR_NOT_SUPPORTED: i32 = -4;
-pub const ERROR_DEVICE_UNAVAILABLE: i32 = -5;
-
-// These need to match cubeb_device_type
-bitflags! {
-    #[repr(C)]
-    pub struct DeviceType : u32 {
-        const UNKNOWN = 0b00;
-        const INPUT = 0b01;
-        const OUTPUT = 0b10;
-        const ALL = 0b11;
-    }
-}
-
-#[repr(C)]
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
-pub enum DeviceState {
-    Disabled = 0,
-    Unplugged = 1,
-    Enabled = 2,
-}
-
-// These need to match cubeb_device_fmt
-bitflags! {
-    #[repr(C)]
-    pub struct DeviceFmt: u32 {
-        const S16LE = 0x0010;
-        const S16BE = 0x0020;
-        const S16NE = {
-            #[cfg(target_endian = "little")] { DeviceFmt::S16LE }
-            #[cfg(target_endian = "big")] { DeviceFmt::S16BE }
-        }.bits;
-        const F32LE = 0x1000;
-        const F32BE = 0x2000;
-        const F32NE = {
-            #[cfg(target_endian = "little")] { DeviceFmt::F32LE }
-            #[cfg(target_endian = "big")] { DeviceFmt::F32BE }
-        }.bits;
-        const S16_MASK = DeviceFmt::S16LE.bits | DeviceFmt::S16BE.bits;
-        const F32_MASK = DeviceFmt::F32LE.bits | DeviceFmt::F32BE.bits;
-        const ALL = DeviceFmt::S16_MASK.bits | DeviceFmt::F32_MASK.bits;
-    }
-}
-
-// These need to match cubeb_device_pref
-bitflags! {
-    #[repr(C)]
-    pub struct DevicePref : u32 {
-        const MULTIMEDIA = 0x1;
-        const VOICE = 0x2;
-        const NOTIFICATION = 0x4;
-        const ALL = 0xF;
-    }
-}
-
-#[repr(C)]
-#[derive(Clone, Copy, Debug)]
-pub struct DeviceInfo {
-    pub devid: DeviceId,
-    pub device_id: *const c_char,
-    pub friendly_name: *const c_char,
-    pub group_id: *const c_char,
-    pub vendor_name: *const c_char,
-    pub devtype: DeviceType,
-    pub state: DeviceState,
-    pub preferred: DevicePref,
-    pub format: DeviceFmt,
-    pub default_format: DeviceFmt,
-    pub max_channels: u32,
-    pub default_rate: u32,
-    pub max_rate: u32,
-    pub min_rate: u32,
-    pub latency_lo: u32,
-    pub latency_hi: u32,
-}
-
-#[repr(C)]
-#[derive(Clone, Copy, Debug)]
-pub struct DeviceCollection {
-    /// Array of device info.
-    pub device: *const DeviceInfo,
-    /// Device count in collection.
-    pub count: usize,
-}
-
-pub type DataCallback = Option<unsafe extern "C" fn(stream: *mut Stream,
-                                                    user_ptr: *mut c_void,
-                                                    input_buffer: *const c_void,
-                                                    output_buffer: *mut c_void,
-                                                    nframes: c_long)
-                                                    -> c_long>;
-pub type StateCallback = Option<unsafe extern "C" fn(stream: *mut Stream, user_ptr: *mut c_void, state: State)>;
-pub type DeviceChangedCallback = Option<unsafe extern "C" fn(user_ptr: *mut c_void)>;
-pub type DeviceCollectionChangedCallback = Option<unsafe extern "C" fn(context: *mut Context, user_ptr: *mut c_void)>;
-
-pub type StreamInitFn = Option<unsafe extern "C" fn(context: *mut Context,
-                                                    stream: *mut *mut Stream,
-                                                    stream_name: *const c_char,
-                                                    input_device: DeviceId,
-                                                    input_stream_params: *mut StreamParams,
-                                                    output_device: DeviceId,
-                                                    output_stream_params: *mut StreamParams,
-                                                    latency: u32,
-                                                    data_callback: DataCallback,
-                                                    state_callback: StateCallback,
-                                                    user_ptr: *mut c_void)
-                                                    -> i32>;
-
-pub type RegisterDeviceCollectionChangedFn = Option<unsafe extern "C" fn(context: *mut Context,
-                                                                         devtype: DeviceType,
-                                                                         callback: DeviceCollectionChangedCallback,
-                                                                         user_ptr: *mut c_void)
-                                                                         -> i32>;
-
-#[repr(C)]
-pub struct Ops {
-    pub init: Option<unsafe extern "C" fn(context: *mut *mut Context, context_name: *const c_char) -> i32>,
-    pub get_backend_id: Option<unsafe extern "C" fn(context: *mut Context) -> *const c_char>,
-    pub get_max_channel_count: Option<unsafe extern "C" fn(context: *mut Context, max_channels: *mut u32) -> i32>,
-    pub get_min_latency: Option<unsafe extern "C" fn(context: *mut Context,
-                                                     params: StreamParams,
-                                                     latency_ms: *mut u32)
-                                                     -> i32>,
-    pub get_preferred_sample_rate: Option<unsafe extern "C" fn(context: *mut Context, rate: *mut u32) -> i32>,
-    pub get_preferred_channel_layout:
-        Option<unsafe extern "C" fn(context: *mut Context, layout: *mut ChannelLayout) -> i32>,
-    pub enumerate_devices: Option<unsafe extern "C" fn(context: *mut Context,
-                                                       devtype: DeviceType,
-                                                       collection: *mut DeviceCollection)
-                                                       -> i32>,
-    pub device_collection_destroy:
-        Option<unsafe extern "C" fn(context: *mut Context, collection: *mut DeviceCollection) -> i32>,
-    pub destroy: Option<unsafe extern "C" fn(context: *mut Context)>,
-    pub stream_init: StreamInitFn,
-    pub stream_destroy: Option<unsafe extern "C" fn(stream: *mut Stream)>,
-    pub stream_start: Option<unsafe extern "C" fn(stream: *mut Stream) -> i32>,
-    pub stream_stop: Option<unsafe extern "C" fn(stream: *mut Stream) -> i32>,
-    pub stream_reset_default_device: Option<unsafe extern "C" fn(stream: *mut Stream) -> i32>,
-    pub stream_get_position: Option<unsafe extern "C" fn(stream: *mut Stream, position: *mut u64) -> i32>,
-    pub stream_get_latency: Option<unsafe extern "C" fn(stream: *mut Stream, latency: *mut u32) -> i32>,
-    pub stream_set_volume: Option<unsafe extern "C" fn(stream: *mut Stream, volumes: f32) -> i32>,
-    pub stream_set_panning: Option<unsafe extern "C" fn(stream: *mut Stream, panning: f32) -> i32>,
-    pub stream_get_current_device: Option<unsafe extern "C" fn(stream: *mut Stream, device: *mut *const Device) -> i32>,
-    pub stream_device_destroy: Option<unsafe extern "C" fn(stream: *mut Stream, device: *mut Device) -> i32>,
-    pub stream_register_device_changed_callback:
-        Option<unsafe extern "C" fn(stream: *mut Stream,
-                                    device_changed_callback: DeviceChangedCallback)
-                                    -> i32>,
-    pub register_device_collection_changed: RegisterDeviceCollectionChangedFn,
-}
-
-#[repr(C)]
-#[derive(Clone, Copy, Debug)]
-pub struct LayoutMap {
-    pub name: *const c_char,
-    pub channels: u32,
-    pub layout: ChannelLayout,
-}
-
-// cubeb_mixer.h
-pub type Channel = c_int;
-
-// These need to match cubeb_channel
-pub const CHANNEL_INVALID: Channel = -1;
-pub const CHANNEL_MONO: Channel = 0;
-pub const CHANNEL_LEFT: Channel = 1;
-pub const CHANNEL_RIGHT: Channel = 2;
-pub const CHANNEL_CENTER: Channel = 3;
-pub const CHANNEL_LS: Channel = 4;
-pub const CHANNEL_RS: Channel = 5;
-pub const CHANNEL_RLS: Channel = 6;
-pub const CHANNEL_RCENTER: Channel = 7;
-pub const CHANNEL_RRS: Channel = 8;
-pub const CHANNEL_LFE: Channel = 9;
-pub const CHANNEL_MAX: Channel = 10;
-
-#[repr(C)]
-#[derive(Clone, Copy, Debug)]
-pub struct ChannelMap {
-    pub channels: c_uint,
-    pub map: [Channel; CHANNEL_MAX as usize],
-}
-impl ::std::default::Default for ChannelMap {
-    fn default() -> Self {
-        ChannelMap {
-            channels: 0,
-            map: [CHANNEL_INVALID,
-                  CHANNEL_INVALID,
-                  CHANNEL_INVALID,
-                  CHANNEL_INVALID,
-                  CHANNEL_INVALID,
-                  CHANNEL_INVALID,
-                  CHANNEL_INVALID,
-                  CHANNEL_INVALID,
-                  CHANNEL_INVALID,
-                  CHANNEL_INVALID],
-        }
-    }
-}
-
-extern "C" {
-    pub fn cubeb_channel_map_to_layout(channel_map: *const ChannelMap) -> ChannelLayout;
-    pub fn cubeb_should_upmix(stream: *const StreamParams, mixer: *const StreamParams) -> bool;
-    pub fn cubeb_should_downmix(stream: *const StreamParams, mixer: *const StreamParams) -> bool;
-    pub fn cubeb_downmix_float(input: *const f32,
-                               inframes: c_long,
-                               output: *mut f32,
-                               in_channels: u32,
-                               out_channels: u32,
-                               in_layout: ChannelLayout,
-                               out_layout: ChannelLayout);
-    pub fn cubeb_upmix_float(input: *const f32,
-                             inframes: c_long,
-                             output: *mut f32,
-                             in_channels: u32,
-                             out_channels: u32);
-}
-
-#[test]
-fn bindgen_test_layout_stream_params() {
-    assert_eq!(::std::mem::size_of::<StreamParams>(),
-               20usize,
-               concat!("Size of: ", stringify!(StreamParams)));
-    assert_eq!(::std::mem::align_of::<StreamParams>(),
-               4usize,
-               concat!("Alignment of ", stringify!(StreamParams)));
-    assert_eq!(unsafe { &(*(0 as *const StreamParams)).format as *const _ as usize },
-               0usize,
-               concat!("Alignment of field: ",
-                       stringify!(StreamParams),
-                       "::",
-                       stringify!(format)));
-    assert_eq!(unsafe { &(*(0 as *const StreamParams)).rate as *const _ as usize },
-               4usize,
-               concat!("Alignment of field: ",
-                       stringify!(StreamParams),
-                       "::",
-                       stringify!(rate)));
-    assert_eq!(unsafe { &(*(0 as *const StreamParams)).channels as *const _ as usize },
-               8usize,
-               concat!("Alignment of field: ",
-                       stringify!(StreamParams),
-                       "::",
-                       stringify!(channels)));
-    assert_eq!(unsafe { &(*(0 as *const StreamParams)).layout as *const _ as usize },
-               12usize,
-               concat!("Alignment of field: ",
-                       stringify!(StreamParams),
-                       "::",
-                       stringify!(layout)));
-    assert_eq!(unsafe { &(*(0 as *const StreamParams)).prefs as *const _ as usize },
-               16usize,
-               concat!("Alignment of field: ",
-                       stringify!(StreamParams),
-                       "::",
-                       stringify!(layout)));
-}
-
-#[test]
-fn bindgen_test_layout_cubeb_device() {
-    assert_eq!(::std::mem::size_of::<Device>(),
-               16usize,
-               concat!("Size of: ", stringify!(Device)));
-    assert_eq!(::std::mem::align_of::<Device>(),
-               8usize,
-               concat!("Alignment of ", stringify!(Device)));
-    assert_eq!(unsafe { &(*(0 as *const Device)).output_name as *const _ as usize },
-               0usize,
-               concat!("Alignment of field: ",
-                       stringify!(Device),
-                       "::",
-                       stringify!(output_name)));
-    assert_eq!(unsafe { &(*(0 as *const Device)).input_name as *const _ as usize },
-               8usize,
-               concat!("Alignment of field: ",
-                       stringify!(Device),
-                       "::",
-                       stringify!(input_name)));
-}
-
-#[test]
-fn bindgen_test_layout_cubeb_device_info() {
-    assert_eq!(::std::mem::size_of::<DeviceInfo>(),
-               88usize,
-               concat!("Size of: ", stringify!(DeviceInfo)));
-    assert_eq!(::std::mem::align_of::<DeviceInfo>(),
-               8usize,
-               concat!("Alignment of ", stringify!(DeviceInfo)));
-    assert_eq!(unsafe { &(*(0 as *const DeviceInfo)).devid as *const _ as usize },
-               0usize,
-               concat!("Alignment of field: ",
-                       stringify!(DeviceInfo),
-                       "::",
-                       stringify!(devid)));
-    assert_eq!(unsafe { &(*(0 as *const DeviceInfo)).device_id as *const _ as usize },
-               8usize,
-               concat!("Alignment of field: ",
-                       stringify!(DeviceInfo),
-                       "::",
-                       stringify!(device_id)));
-    assert_eq!(unsafe { &(*(0 as *const DeviceInfo)).friendly_name as *const _ as usize },
-               16usize,
-               concat!("Alignment of field: ",
-                       stringify!(DeviceInfo),
-                       "::",
-                       stringify!(friendly_name)));
-    assert_eq!(unsafe { &(*(0 as *const DeviceInfo)).group_id as *const _ as usize },
-               24usize,
-               concat!("Alignment of field: ",
-                       stringify!(DeviceInfo),
-                       "::",
-                       stringify!(group_id)));
-    assert_eq!(unsafe { &(*(0 as *const DeviceInfo)).vendor_name as *const _ as usize },
-               32usize,
-               concat!("Alignment of field: ",
-                       stringify!(DeviceInfo),
-                       "::",
-                       stringify!(vendor_name)));
-    assert_eq!(unsafe { &(*(0 as *const DeviceInfo)).devtype as *const _ as usize },
-               40usize,
-               concat!("Alignment of field: ",
-                       stringify!(DeviceInfo),
-                       "::",
-                       stringify!(type_)));
-    assert_eq!(unsafe { &(*(0 as *const DeviceInfo)).state as *const _ as usize },
-               44usize,
-               concat!("Alignment of field: ",
-                       stringify!(DeviceInfo),
-                       "::",
-                       stringify!(state)));
-    assert_eq!(unsafe { &(*(0 as *const DeviceInfo)).preferred as *const _ as usize },
-               48usize,
-               concat!("Alignment of field: ",
-                       stringify!(DeviceInfo),
-                       "::",
-                       stringify!(preferred)));
-    assert_eq!(unsafe { &(*(0 as *const DeviceInfo)).format as *const _ as usize },
-               52usize,
-               concat!("Alignment of field: ",
-                       stringify!(DeviceInfo),
-                       "::",
-                       stringify!(format)));
-    assert_eq!(unsafe { &(*(0 as *const DeviceInfo)).default_format as *const _ as usize },
-               56usize,
-               concat!("Alignment of field: ",
-                       stringify!(DeviceInfo),
-                       "::",
-                       stringify!(default_format)));
-    assert_eq!(unsafe { &(*(0 as *const DeviceInfo)).max_channels as *const _ as usize },
-               60usize,
-               concat!("Alignment of field: ",
-                       stringify!(DeviceInfo),
-                       "::",
-                       stringify!(max_channels)));
-    assert_eq!(unsafe { &(*(0 as *const DeviceInfo)).default_rate as *const _ as usize },
-               64usize,
-               concat!("Alignment of field: ",
-                       stringify!(DeviceInfo),
-                       "::",
-                       stringify!(default_rate)));
-    assert_eq!(unsafe { &(*(0 as *const DeviceInfo)).max_rate as *const _ as usize },
-               68usize,
-               concat!("Alignment of field: ",
-                       stringify!(DeviceInfo),
-                       "::",
-                       stringify!(max_rate)));
-    assert_eq!(unsafe { &(*(0 as *const DeviceInfo)).min_rate as *const _ as usize },
-               72usize,
-               concat!("Alignment of field: ",
-                       stringify!(DeviceInfo),
-                       "::",
-                       stringify!(min_rate)));
-    assert_eq!(unsafe { &(*(0 as *const DeviceInfo)).latency_lo as *const _ as usize },
-               76usize,
-               concat!("Alignment of field: ",
-                       stringify!(DeviceInfo),
-                       "::",
-                       stringify!(latency_lo)));
-    assert_eq!(unsafe { &(*(0 as *const DeviceInfo)).latency_hi as *const _ as usize },
-               80usize,
-               concat!("Alignment of field: ",
-                       stringify!(DeviceInfo),
-                       "::",
-                       stringify!(latency_hi)));
-}
-
-#[test]
-fn bindgen_test_layout_cubeb_device_collection() {
-    assert_eq!(::std::mem::size_of::<DeviceCollection>(),
-               8usize,
-               concat!("Size of: ", stringify!(DeviceCollection)));
-    assert_eq!(::std::mem::align_of::<DeviceCollection>(),
-               8usize,
-               concat!("Alignment of ", stringify!(DeviceCollection)));
-    assert_eq!(unsafe { &(*(0 as *const DeviceCollection)).count as *const _ as usize },
-               0usize,
-               concat!("Alignment of field: ",
-                       stringify!(DeviceCollection),
-                       "::",
-                       stringify!(count)));
-    assert_eq!(unsafe { &(*(0 as *const DeviceCollection)).device as *const _ as usize },
-               8usize,
-               concat!("Alignment of field: ",
-                       stringify!(DeviceCollection),
-                       "::",
-                       stringify!(device)));
-
-}
deleted file mode 100644
--- a/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/lib.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright © 2017 Mozilla Foundation
-//
-// This program is made available under an ISC-style license.  See the
-// accompanying file LICENSE for details.
-
-#[macro_use]
-extern crate bitflags;
-
-mod ffi;
-mod log;
-pub mod mixer;
-
-pub use ffi::*;
-pub use log::*;
deleted file mode 100644
--- a/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/log.rs
+++ /dev/null
@@ -1,75 +0,0 @@
-use std::os::raw::c_char;
-
-#[macro_export]
-macro_rules! log_internal {
-    ($level: expr, $msg: expr) => {
-        #[allow(unused_unsafe)]
-        unsafe {
-            if $level <= $crate::g_cubeb_log_level {
-                if let Some(log_callback) = $crate::g_cubeb_log_callback {
-                    let cstr = ::std::ffi::CString::new(concat!("%s:%d: ", $msg, "\n")).unwrap();
-                    log_callback(cstr.as_ptr(), file!(), line!());
-                }
-            }
-        }
-    };
-    ($level: expr, $fmt: expr, $($arg:tt)+) => {
-        #[allow(unused_unsafe)]
-        unsafe {
-            if $level <= $crate::g_cubeb_log_level {
-                if let Some(log_callback) = $crate::g_cubeb_log_callback {
-                    let cstr = ::std::ffi::CString::new(format!(concat!("%s:%d: ", $fmt, "\n"), $($arg)+)).unwrap();
-                    log_callback(cstr.as_ptr(), file!(), line!());
-                }
-            }
-        }
-    }
-}
-
-#[macro_export]
-macro_rules! logv {
-    ($msg: expr) => (log_internal!($crate::LogLevel::Verbose, $msg));
-    ($fmt: expr, $($arg: tt)+) => (log_internal!($crate::LogLevel::Verbose, $fmt, $($arg)*));
-}
-
-#[macro_export]
-macro_rules! log {
-    ($msg: expr) => (log_internal!($crate::LogLevel::Normal, $msg));
-    ($fmt: expr, $($arg: tt)+) => (log_internal!($crate::LogLevel::Normal, $fmt, $($arg)*));
-}
-
-#[repr(C)]
-#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub enum LogLevel {
-    Disabled = 0,
-    Normal = 1,
-    Verbose = 2,
-}
-
-pub type LogCallback = Option<unsafe extern "C" fn(fmt: *const c_char, ...)>;
-
-extern "C" {
-    pub static g_cubeb_log_level: LogLevel;
-    pub static g_cubeb_log_callback: LogCallback;
-}
-
-pub fn log_enabled() -> bool {
-    unsafe { g_cubeb_log_level != LogLevel::Disabled }
-}
-
-#[test]
-fn test_normal_logging() {
-    log!("This is log at normal level");
-    log!("Formatted log %d", 1);
-}
-
-#[test]
-fn test_verbose_logging() {
-    logv!("This is a log at verbose level");
-    logv!("Formatted log %d", 1);
-}
-
-#[test]
-fn test_logging_disabled_by_default() {
-    assert!(!log_enabled());
-}
deleted file mode 100644
--- a/media/libcubeb/cubeb-pulse-rs/cubeb-ffi/src/mixer.rs
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright © 2017 Mozilla Foundation
-//
-// This program is made available under an ISC-style license.  See the
-// accompanying file LICENSE for details.
-
-use ::*;
-
-static CHANNEL_LAYOUT_UNDEFINED: &'static [Channel] = &[CHANNEL_INVALID];
-static CHANNEL_LAYOUT_DUAL_MONO: &'static [Channel] = &[CHANNEL_LEFT, CHANNEL_RIGHT];
-static CHANNEL_LAYOUT_DUAL_MONO_LFE: &'static [Channel] = &[CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_LFE];
-static CHANNEL_LAYOUT_MONO: &'static [Channel] = &[CHANNEL_MONO];
-static CHANNEL_LAYOUT_MONO_LFE: &'static [Channel] = &[CHANNEL_MONO, CHANNEL_LFE];
-static CHANNEL_LAYOUT_STEREO: &'static [Channel] = &[CHANNEL_LEFT, CHANNEL_RIGHT];
-static CHANNEL_LAYOUT_STEREO_LFE: &'static [Channel] = &[CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_LFE];
-static CHANNEL_LAYOUT_3F: &'static [Channel] = &[CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER];
-static CHANNEL_LAYOUT_3FLFE: &'static [Channel] = &[CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER, CHANNEL_LFE];
-static CHANNEL_LAYOUT_2F1: &'static [Channel] = &[CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_RCENTER];
-static CHANNEL_LAYOUT_2F1LFE: &'static [Channel] = &[CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_LFE, CHANNEL_RCENTER];
-static CHANNEL_LAYOUT_3F1: &'static [Channel] = &[CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER, CHANNEL_RCENTER];
-static CHANNEL_LAYOUT_3F1LFE: &'static [Channel] = &[CHANNEL_LEFT,
-                                                     CHANNEL_RIGHT,
-                                                     CHANNEL_CENTER,
-                                                     CHANNEL_LFE,
-                                                     CHANNEL_RCENTER];
-static CHANNEL_LAYOUT_2F2: &'static [Channel] = &[CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_LS, CHANNEL_RS];
-static CHANNEL_LAYOUT_2F2LFE: &'static [Channel] = &[CHANNEL_LEFT,
-                                                     CHANNEL_RIGHT,
-                                                     CHANNEL_LFE,
-                                                     CHANNEL_LS,
-                                                     CHANNEL_RS];
-static CHANNEL_LAYOUT_3F2: &'static [Channel] = &[CHANNEL_LEFT,
-                                                  CHANNEL_RIGHT,
-                                                  CHANNEL_CENTER,
-                                                  CHANNEL_LS,
-                                                  CHANNEL_RS];
-static CHANNEL_LAYOUT_3F2LFE: &'static [Channel] = &[CHANNEL_LEFT,
-                                                     CHANNEL_RIGHT,
-                                                     CHANNEL_CENTER,
-                                                     CHANNEL_LFE,
-                                                     CHANNEL_LS,
-                                                     CHANNEL_RS];
-static CHANNEL_LAYOUT_3F3RLFE: &'static [Channel] = &[CHANNEL_LEFT,
-                                                      CHANNEL_RIGHT,
-                                                      CHANNEL_CENTER,
-                                                      CHANNEL_LFE,
-                                                      CHANNEL_RCENTER,
-                                                      CHANNEL_LS,
-                                                      CHANNEL_RS];
-static CHANNEL_LAYOUT_3F4LFE: &'static [Channel] = &[CHANNEL_LEFT,
-                                                     CHANNEL_RIGHT,
-                                                     CHANNEL_CENTER,
-                                                     CHANNEL_LFE,
-                                                     CHANNEL_RLS,
-                                                     CHANNEL_RRS,
-                                                     CHANNEL_LS,
-                                                     CHANNEL_RS];
-
-pub fn channel_index_to_order(layout: ChannelLayout) -> &'static [Channel] {
-    match layout {
-        LAYOUT_DUAL_MONO => CHANNEL_LAYOUT_DUAL_MONO,
-        LAYOUT_DUAL_MONO_LFE => CHANNEL_LAYOUT_DUAL_MONO_LFE,
-        LAYOUT_MONO => CHANNEL_LAYOUT_MONO,
-        LAYOUT_MONO_LFE => CHANNEL_LAYOUT_MONO_LFE,
-        LAYOUT_STEREO => CHANNEL_LAYOUT_STEREO,
-        LAYOUT_STEREO_LFE => CHANNEL_LAYOUT_STEREO_LFE,
-        LAYOUT_3F => CHANNEL_LAYOUT_3F,
-        LAYOUT_3F_LFE => CHANNEL_LAYOUT_3FLFE,
-        LAYOUT_2F1 => CHANNEL_LAYOUT_2F1,
-        LAYOUT_2F1_LFE => CHANNEL_LAYOUT_2F1LFE,
-        LAYOUT_3F1 => CHANNEL_LAYOUT_3F1,
-        LAYOUT_3F1_LFE => CHANNEL_LAYOUT_3F1LFE,
-        LAYOUT_2F2 => CHANNEL_LAYOUT_2F2,
-        LAYOUT_2F2_LFE => CHANNEL_LAYOUT_2F2LFE,
-        LAYOUT_3F2 => CHANNEL_LAYOUT_3F2,
-        LAYOUT_3F2_LFE => CHANNEL_LAYOUT_3F2LFE,
-        LAYOUT_3F3R_LFE => CHANNEL_LAYOUT_3F3RLFE,
-        LAYOUT_3F4_LFE => CHANNEL_LAYOUT_3F4LFE,
-        _ => CHANNEL_LAYOUT_UNDEFINED,
-    }
-}
--- a/media/libcubeb/cubeb-pulse-rs/src/backend/context.rs
+++ b/media/libcubeb/cubeb-pulse-rs/src/backend/context.rs
@@ -1,160 +1,166 @@
-// Copyright © 2017 Mozilla Foundation
+// Copyright © 2017-2018 Mozilla Foundation
 //
 // This program is made available under an ISC-style license.  See the
 // accompanying file LICENSE for details.
 
 use backend::*;
-use capi::PULSE_OPS;
-use cubeb;
+use cubeb_backend::{ffi, log_enabled, ChannelLayout, Context, ContextOps, DeviceCollectionRef,
+                    DeviceId, DeviceType, Error, Ops, Result, Stream, StreamParams,
+                    StreamParamsRef};
 use pulse::{self, ProplistExt};
 use pulse_ffi::*;
 use semver;
+use std::cell::RefCell;
 use std::default::Default;
 use std::ffi::{CStr, CString};
 use std::mem;
-use std::os::raw::{c_char, c_void};
+use std::os::raw::c_void;
 use std::ptr;
-use std::cell::RefCell;
 
-fn pa_channel_to_cubeb_channel(channel: pulse::ChannelPosition) -> cubeb::Channel {
+fn pa_channel_to_cubeb_channel(channel: pulse::ChannelPosition) -> ffi::cubeb_channel {
+    use cubeb_backend::ffi::*;
     use pulse::ChannelPosition;
     assert_ne!(channel, ChannelPosition::Invalid);
     match channel {
-        ChannelPosition::Mono => cubeb::CHANNEL_MONO,
-        ChannelPosition::FrontLeft => cubeb::CHANNEL_LEFT,
-        ChannelPosition::FrontRight => cubeb::CHANNEL_RIGHT,
-        ChannelPosition::FrontCenter => cubeb::CHANNEL_CENTER,
-        ChannelPosition::SideLeft => cubeb::CHANNEL_LS,
-        ChannelPosition::SideRight => cubeb::CHANNEL_RS,
-        ChannelPosition::RearLeft => cubeb::CHANNEL_RLS,
-        ChannelPosition::RearCenter => cubeb::CHANNEL_RCENTER,
-        ChannelPosition::RearRight => cubeb::CHANNEL_RRS,
-        ChannelPosition::LowFreqEffects => cubeb::CHANNEL_LFE,
-        _ => cubeb::CHANNEL_INVALID,
+        ChannelPosition::Mono => CHANNEL_MONO,
+        ChannelPosition::FrontLeft => CHANNEL_LEFT,
+        ChannelPosition::FrontRight => CHANNEL_RIGHT,
+        ChannelPosition::FrontCenter => CHANNEL_CENTER,
+        ChannelPosition::SideLeft => CHANNEL_LS,
+        ChannelPosition::SideRight => CHANNEL_RS,
+        ChannelPosition::RearLeft => CHANNEL_RLS,
+        ChannelPosition::RearCenter => CHANNEL_RCENTER,
+        ChannelPosition::RearRight => CHANNEL_RRS,
+        ChannelPosition::LowFreqEffects => CHANNEL_LFE,
+        _ => CHANNEL_INVALID,
     }
 }
 
-fn channel_map_to_layout(cm: &pulse::ChannelMap) -> cubeb::ChannelLayout {
+fn channel_map_to_layout(cm: &pulse::ChannelMap) -> ChannelLayout {
+    use cubeb_backend::ffi::{cubeb_channel_map, cubeb_channel_map_to_layout};
     use pulse::ChannelPosition;
-    let mut cubeb_map: cubeb::ChannelMap = Default::default();
+    let mut cubeb_map: cubeb_channel_map = unsafe { mem::zeroed() };
     cubeb_map.channels = u32::from(cm.channels);
     for i in 0usize..cm.channels as usize {
-        cubeb_map.map[i] = pa_channel_to_cubeb_channel(ChannelPosition::try_from(cm.map[i])
-                                                           .unwrap_or(ChannelPosition::Invalid));
+        cubeb_map.map[i] = pa_channel_to_cubeb_channel(
+            ChannelPosition::try_from(cm.map[i]).unwrap_or(ChannelPosition::Invalid),
+        );
     }
-    unsafe { cubeb::cubeb_channel_map_to_layout(&cubeb_map) }
+    ChannelLayout::from(unsafe { cubeb_channel_map_to_layout(&cubeb_map) })
 }
 
 #[derive(Debug)]
 pub struct DefaultInfo {
     pub sample_spec: pulse::SampleSpec,
     pub channel_map: pulse::ChannelMap,
     pub flags: pulse::SinkFlags,
 }
 
+pub const PULSE_OPS: Ops = capi_new!(PulseContext, PulseStream);
+
 #[derive(Debug)]
-pub struct Context {
-    pub ops: *const cubeb::Ops,
+pub struct PulseContext {
+    _ops: *const Ops,
     pub mainloop: pulse::ThreadedMainloop,
     pub context: Option<pulse::Context>,
     pub default_sink_info: Option<DefaultInfo>,
     pub context_name: Option<CString>,
-    pub collection_changed_callback: cubeb::DeviceCollectionChangedCallback,
+    pub collection_changed_callback: ffi::cubeb_device_collection_changed_callback,
     pub collection_changed_user_ptr: *mut c_void,
     pub error: bool,
     pub version_2_0_0: bool,
     pub version_0_9_8: bool,
-    #[cfg(feature = "pulse-dlopen")]
-    pub libpulse: LibLoader,
+    #[cfg(feature = "pulse-dlopen")] pub libpulse: LibLoader,
     devids: RefCell<Intern>,
 }
 
-impl Drop for Context {
-    fn drop(&mut self) {
-        self.destroy();
-    }
-}
-
-impl Context {
+impl PulseContext {
     #[cfg(feature = "pulse-dlopen")]
     fn _new(name: Option<CString>) -> Result<Box<Self>> {
         let libpulse = unsafe { open() };
         if libpulse.is_none() {
-            return Err(cubeb::ERROR);
+            return Err(Error::error());
         }
 
-        let ctx = Box::new(Context {
-                               ops: &PULSE_OPS,
-                               libpulse: libpulse.unwrap(),
-                               mainloop: pulse::ThreadedMainloop::new(),
-                               context: None,
-                               default_sink_info: None,
-                               context_name: name,
-                               collection_changed_callback: None,
-                               collection_changed_user_ptr: ptr::null_mut(),
-                               error: true,
-                               version_0_9_8: false,
-                               version_2_0_0: false,
-                               devids: RefCell::new(Intern::new()),
-                           });
+        let ctx = Box::new(PulseContext {
+            _ops: &PULSE_OPS,
+            libpulse: libpulse.unwrap(),
+            mainloop: pulse::ThreadedMainloop::new(),
+            context: None,
+            default_sink_info: None,
+            context_name: name,
+            collection_changed_callback: None,
+            collection_changed_user_ptr: ptr::null_mut(),
+            error: true,
+            version_0_9_8: false,
+            version_2_0_0: false,
+            devids: RefCell::new(Intern::new()),
+        });
 
         Ok(ctx)
     }
 
     #[cfg(not(feature = "pulse-dlopen"))]
     fn _new(name: Option<CString>) -> Result<Box<Self>> {
-        Ok(Box::new(Context {
-                        ops: &PULSE_OPS,
-                        mainloop: pulse::ThreadedMainloop::new(),
-                        context: None,
-                        default_sink_info: None,
-                        context_name: name,
-                        collection_changed_callback: None,
-                        collection_changed_user_ptr: ptr::null_mut(),
-                        error: true,
-                        version_0_9_8: false,
-                        version_2_0_0: false,
-                        devids: RefCell::new(Intern::new()),
-                    }))
+        Ok(Box::new(PulseContext {
+            _ops: &PULSE_OPS,
+            mainloop: pulse::ThreadedMainloop::new(),
+            context: None,
+            default_sink_info: None,
+            context_name: name,
+            collection_changed_callback: None,
+            collection_changed_user_ptr: ptr::null_mut(),
+            error: true,
+            version_0_9_8: false,
+            version_2_0_0: false,
+            devids: RefCell::new(Intern::new()),
+        }))
     }
 
-    pub fn new(name: *const c_char) -> Result<Box<Self>> {
+    fn new(name: Option<&CStr>) -> Result<Box<Self>> {
         fn server_info_cb(context: &pulse::Context, info: &pulse::ServerInfo, u: *mut c_void) {
-            fn sink_info_cb(_: &pulse::Context, i: *const pulse::SinkInfo, eol: i32, u: *mut c_void) {
-                let ctx = unsafe { &mut *(u as *mut Context) };
+            fn sink_info_cb(
+                _: &pulse::Context,
+                i: *const pulse::SinkInfo,
+                eol: i32,
+                u: *mut c_void,
+            ) {
+                let ctx = unsafe { &mut *(u as *mut PulseContext) };
                 if eol == 0 {
                     let info = unsafe { &*i };
                     let flags = pulse::SinkFlags::from_bits_truncate(info.flags);
                     ctx.default_sink_info = Some(DefaultInfo {
-                                                     sample_spec: info.sample_spec,
-                                                     channel_map: info.channel_map,
-                                                     flags: flags,
-                                                 });
+                        sample_spec: info.sample_spec,
+                        channel_map: info.channel_map,
+                        flags: flags,
+                    });
                 }
                 ctx.mainloop.signal();
             }
 
-            let _ = context.get_sink_info_by_name(try_cstr_from(info.default_sink_name),
-                                                  sink_info_cb,
-                                                  u);
+            let _ = context.get_sink_info_by_name(
+                try_cstr_from(info.default_sink_name),
+                sink_info_cb,
+                u,
+            );
         }
 
-        let name = super::try_cstr_from(name).map(|s| s.to_owned());
-        let mut ctx = try!(Context::_new(name));
+        let name = name.map(|s| s.to_owned());
+        let mut ctx = try!(PulseContext::_new(name));
 
         if ctx.mainloop.start().is_err() {
             ctx.destroy();
-            return Err(cubeb::ERROR);
+            return Err(Error::error());
         }
 
-        if ctx.context_init() != cubeb::OK {
+        if ctx.context_init().is_err() {
             ctx.destroy();
-            return Err(cubeb::ERROR);
+            return Err(Error::error());
         }
 
         ctx.mainloop.lock();
         /* server_info_callback performs a second async query,
          * which is responsible for initializing default_sink_info
          * and signalling the mainloop to end the wait. */
         let user_data: *mut c_void = ctx.as_mut() as *mut _ as *mut _;
         if let Some(ref context) = ctx.context {
@@ -170,73 +176,65 @@ impl Context {
 
     pub fn destroy(&mut self) {
         self.context_destroy();
 
         if !self.mainloop.is_null() {
             self.mainloop.stop();
         }
     }
+}
 
-    #[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
-    pub fn new_stream(&mut self,
-                      stream_name: &CStr,
-                      input_device: cubeb::DeviceId,
-                      input_stream_params: Option<cubeb::StreamParams>,
-                      output_device: cubeb::DeviceId,
-                      output_stream_params: Option<cubeb::StreamParams>,
-                      latency_frames: u32,
-                      data_callback: cubeb::DataCallback,
-                      state_callback: cubeb::StateCallback,
-                      user_ptr: *mut c_void)
-                      -> Result<Box<Stream>> {
-        if self.error && self.context_init() != 0 {
-            return Err(cubeb::ERROR);
-        }
-
-        Stream::new(self,
-                    stream_name,
-                    input_device,
-                    input_stream_params,
-                    output_device,
-                    output_stream_params,
-                    latency_frames,
-                    data_callback,
-                    state_callback,
-                    user_ptr)
+impl ContextOps for PulseContext {
+    fn init(context_name: Option<&CStr>) -> Result<Context> {
+        let ctx = try!(PulseContext::new(context_name));
+        Ok(unsafe { Context::from_ptr(Box::into_raw(ctx) as *mut _) })
     }
 
-    pub fn max_channel_count(&self) -> Result<u32> {
+    fn backend_id(&mut self) -> &'static CStr {
+        unsafe { CStr::from_ptr(b"pulse-rust\0".as_ptr() as *const _) }
+    }
+
+    fn max_channel_count(&mut self) -> Result<u32> {
         match self.default_sink_info {
             Some(ref info) => Ok(u32::from(info.channel_map.channels)),
-            None => Err(cubeb::ERROR),
+            None => Err(Error::error()),
         }
     }
 
-    pub fn preferred_sample_rate(&self) -> Result<u32> {
+    fn min_latency(&mut self, params: StreamParams) -> Result<u32> {
+        // According to PulseAudio developers, this is a safe minimum.
+        Ok(25 * params.rate() / 1000)
+    }
+
+    fn preferred_sample_rate(&mut self) -> Result<u32> {
         match self.default_sink_info {
             Some(ref info) => Ok(info.sample_spec.rate),
-            None => Err(cubeb::ERROR),
+            None => Err(Error::error()),
         }
     }
 
-    pub fn min_latency(&self, params: &cubeb::StreamParams) -> Result<u32> {
-        // According to PulseAudio developers, this is a safe minimum.
-        Ok(25 * params.rate / 1000)
-    }
-
-    pub fn preferred_channel_layout(&self) -> Result<cubeb::ChannelLayout> {
+    fn preferred_channel_layout(&mut self) -> Result<ChannelLayout> {
         match self.default_sink_info {
             Some(ref info) => Ok(channel_map_to_layout(&info.channel_map)),
-            None => Err(cubeb::ERROR),
+            None => Err(Error::error()),
         }
     }
 
-    pub fn enumerate_devices(&self, devtype: cubeb::DeviceType) -> Result<cubeb::DeviceCollection> {
-        fn add_output_device(_: &pulse::Context, i: *const pulse::SinkInfo, eol: i32, user_data: *mut c_void) {
+    fn enumerate_devices(
+        &mut self,
+        devtype: DeviceType,
+        collection: &DeviceCollectionRef,
+    ) -> Result<()> {
+        fn add_output_device(
+            _: &pulse::Context,
+            i: *const pulse::SinkInfo,
+            eol: i32,
+            user_data: *mut c_void,
+        ) {
             let list_data = unsafe { &mut *(user_data as *mut PulseDevListData) };
             let ctx = &(*list_data.context);
 
             if eol != 0 {
                 ctx.mainloop.signal();
                 return;
             }
 
@@ -254,45 +252,50 @@ impl Context {
                 Some(p) => p.to_owned().into_raw(),
                 _ => ptr::null_mut(),
             };
 
             let info_name = unsafe { CStr::from_ptr(info.name) };
             let info_description = unsafe { CStr::from_ptr(info.description) }.to_owned();
 
             let preferred = if *info_name == *list_data.default_sink_name {
-                cubeb::DevicePref::ALL
+                ffi::CUBEB_DEVICE_PREF_ALL
             } else {
-                cubeb::DevicePref::empty()
+                ffi::CUBEB_DEVICE_PREF_NONE
             };
 
             let device_id = ctx.devids.borrow_mut().add(info_name);
             let friendly_name = info_description.into_raw();
-            let devinfo = cubeb::DeviceInfo {
+            let devinfo = ffi::cubeb_device_info {
                 device_id: device_id,
-                devid: device_id as cubeb::DeviceId,
+                devid: device_id as ffi::cubeb_devid,
                 friendly_name: friendly_name,
                 group_id: group_id,
                 vendor_name: vendor_name,
-                devtype: cubeb::DeviceType::OUTPUT,
+                device_type: ffi::CUBEB_DEVICE_TYPE_OUTPUT,
                 state: ctx.state_from_port(info.active_port),
                 preferred: preferred,
-                format: cubeb::DeviceFmt::all(),
+                format: ffi::CUBEB_DEVICE_FMT_ALL,
                 default_format: pulse_format_to_cubeb_format(info.sample_spec.format),
                 max_channels: u32::from(info.channel_map.channels),
                 min_rate: 1,
                 max_rate: PA_RATE_MAX,
                 default_rate: info.sample_spec.rate,
                 latency_lo: 0,
                 latency_hi: 0,
             };
             list_data.devinfo.push(devinfo);
         }
 
-        fn add_input_device(_: &pulse::Context, i: *const pulse::SourceInfo, eol: i32, user_data: *mut c_void) {
+        fn add_input_device(
+            _: &pulse::Context,
+            i: *const pulse::SourceInfo,
+            eol: i32,
+            user_data: *mut c_void,
+        ) {
             let list_data = unsafe { &mut *(user_data as *mut PulseDevListData) };
             let ctx = &(*list_data.context);
 
             if eol != 0 {
                 ctx.mainloop.signal();
                 return;
             }
 
@@ -310,46 +313,50 @@ impl Context {
                 Some(p) => p.to_owned().into_raw(),
                 _ => ptr::null_mut(),
             };
 
             let info_name = unsafe { CStr::from_ptr(info.name) };
             let info_description = unsafe { CStr::from_ptr(info.description) }.to_owned();
 
             let preferred = if *info_name == *list_data.default_source_name {
-                cubeb::DevicePref::ALL
+                ffi::CUBEB_DEVICE_PREF_ALL
             } else {
-                cubeb::DevicePref::empty()
+                ffi::CUBEB_DEVICE_PREF_NONE
             };
 
             let device_id = ctx.devids.borrow_mut().add(info_name);
             let friendly_name = info_description.into_raw();
-            let devinfo = cubeb::DeviceInfo {
+            let devinfo = ffi::cubeb_device_info {
                 device_id: device_id,
-                devid: device_id as cubeb::DeviceId,
+                devid: device_id as ffi::cubeb_devid,
                 friendly_name: friendly_name,
                 group_id: group_id,
                 vendor_name: vendor_name,
-                devtype: cubeb::DeviceType::INPUT,
+                device_type: ffi::CUBEB_DEVICE_TYPE_INPUT,
                 state: ctx.state_from_port(info.active_port),
                 preferred: preferred,
-                format: cubeb::DeviceFmt::all(),
+                format: ffi::CUBEB_DEVICE_FMT_ALL,
                 default_format: pulse_format_to_cubeb_format(info.sample_spec.format),
                 max_channels: u32::from(info.channel_map.channels),
                 min_rate: 1,
                 max_rate: PA_RATE_MAX,
                 default_rate: info.sample_spec.rate,
                 latency_lo: 0,
                 latency_hi: 0,
             };
 
             list_data.devinfo.push(devinfo);
         }
 
-        fn default_device_names(_: &pulse::Context, info: &pulse::ServerInfo, user_data: *mut c_void) {
+        fn default_device_names(
+            _: &pulse::Context,
+            info: &pulse::ServerInfo,
+            user_data: *mut c_void,
+        ) {
             let list_data = unsafe { &mut *(user_data as *mut PulseDevListData) };
 
             list_data.default_sink_name = super::try_cstr_from(info.default_sink_name)
                 .map(|s| s.to_owned())
                 .unwrap_or_default();
             list_data.default_source_name = super::try_cstr_from(info.default_source_name)
                 .map(|s| s.to_owned())
                 .unwrap_or_default();
@@ -357,156 +364,210 @@ impl Context {
             (*list_data.context).mainloop.signal();
         }
 
         let mut user_data = PulseDevListData::new(self);
 
         if let Some(ref context) = self.context {
             self.mainloop.lock();
 
-            if let Ok(o) = context.get_server_info(default_device_names, &mut user_data as *mut _ as *mut _) {
+            if let Ok(o) =
+                context.get_server_info(default_device_names, &mut user_data as *mut _ as *mut _)
+            {
                 self.operation_wait(None, &o);
             }
 
-            if devtype.contains(cubeb::DeviceType::OUTPUT) {
-                if let Ok(o) = context.get_sink_info_list(add_output_device, &mut user_data as *mut _ as *mut _) {
+            if devtype.contains(DeviceType::OUTPUT) {
+                if let Ok(o) = context
+                    .get_sink_info_list(add_output_device, &mut user_data as *mut _ as *mut _)
+                {
                     self.operation_wait(None, &o);
                 }
             }
 
-            if devtype.contains(cubeb::DeviceType::INPUT) {
-                if let Ok(o) = context.get_source_info_list(add_input_device, &mut user_data as *mut _ as *mut _) {
+            if devtype.contains(DeviceType::INPUT) {
+                if let Ok(o) = context
+                    .get_source_info_list(add_input_device, &mut user_data as *mut _ as *mut _)
+                {
                     self.operation_wait(None, &o);
                 }
             }
 
             self.mainloop.unlock();
         }
 
         // Extract the array of cubeb_device_info from
         // PulseDevListData and convert it into C representation.
         let mut tmp = Vec::new();
         mem::swap(&mut user_data.devinfo, &mut tmp);
-        let devices = tmp.into_boxed_slice();
-        let coll = cubeb::DeviceCollection {
-            device: devices.as_ptr(),
-            count: devices.len(),
-        };
+        let mut devices = tmp.into_boxed_slice();
+        let coll = unsafe { &mut *collection.as_ptr() };
+        coll.device = devices.as_mut_ptr();
+        coll.count = devices.len();
 
         // Giving away the memory owned by devices.  Don't free it!
         mem::forget(devices);
-        Ok(coll)
+        Ok(())
     }
 
-    pub fn device_collection_destroy(&self, collection: *mut cubeb::DeviceCollection) {
-        debug_assert!(!collection.is_null());
+    fn device_collection_destroy(&mut self, collection: &mut DeviceCollectionRef) -> Result<()> {
+        debug_assert!(!collection.as_ptr().is_null());
         unsafe {
-            let coll = *collection;
-            let mut devices = Vec::from_raw_parts(coll.device as *mut cubeb::DeviceInfo,
-                                                  coll.count,
-                                                  coll.count);
+            let coll = &mut *collection.as_ptr();
+            let mut devices = Vec::from_raw_parts(
+                coll.device as *mut ffi::cubeb_device_info,
+                coll.count,
+                coll.count,
+            );
             for dev in &mut devices {
                 if !dev.group_id.is_null() {
                     let _ = CString::from_raw(dev.group_id as *mut _);
                 }
                 if !dev.vendor_name.is_null() {
                     let _ = CString::from_raw(dev.vendor_name as *mut _);
                 }
                 if !dev.friendly_name.is_null() {
                     let _ = CString::from_raw(dev.friendly_name as *mut _);
                 }
             }
+            coll.device = ptr::null_mut();
+            coll.count = 0;
         }
+        Ok(())
     }
 
-    pub fn register_device_collection_changed(&mut self,
-                                              devtype: cubeb::DeviceType,
-                                              cb: cubeb::DeviceCollectionChangedCallback,
-                                              user_ptr: *mut c_void)
-                                              -> i32 {
-        fn update_collection(_: &pulse::Context, event: pulse::SubscriptionEvent, index: u32, user_data: *mut c_void) {
-            let ctx = unsafe { &mut *(user_data as *mut Context) };
+    #[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
+    fn stream_init(
+        &mut self,
+        stream_name: Option<&CStr>,
+        input_device: DeviceId,
+        input_stream_params: Option<&StreamParamsRef>,
+        output_device: DeviceId,
+        output_stream_params: Option<&StreamParamsRef>,
+        latency_frames: u32,
+        data_callback: ffi::cubeb_data_callback,
+        state_callback: ffi::cubeb_state_callback,
+        user_ptr: *mut c_void,
+    ) -> Result<Stream> {
+        if self.error {
+            let _ = try!(self.context_init());
+        }
+
+        let stm = try!(PulseStream::new(
+            self,
+            stream_name,
+            input_device,
+            input_stream_params,
+            output_device,
+            output_stream_params,
+            latency_frames,
+            data_callback,
+            state_callback,
+            user_ptr,
+        ));
+        Ok(unsafe { Stream::from_ptr(Box::into_raw(stm) as *mut _) })
+    }
+
+    fn register_device_collection_changed(
+        &mut self,
+        devtype: DeviceType,
+        cb: ffi::cubeb_device_collection_changed_callback,
+        user_ptr: *mut c_void,
+    ) -> Result<()> {
+        fn update_collection(
+            _: &pulse::Context,
+            event: pulse::SubscriptionEvent,
+            index: u32,
+            user_data: *mut c_void,
+        ) {
+            let ctx = unsafe { &mut *(user_data as *mut PulseContext) };
 
             let (f, t) = (event.event_facility(), event.event_type());
-            match f {
-                pulse::SubscriptionEventFacility::Source |
-                pulse::SubscriptionEventFacility::Sink => {
-                    match t {
-                        pulse::SubscriptionEventType::Remove |
-                        pulse::SubscriptionEventType::New => {
-                            if cubeb::log_enabled() {
-                                let op = if t == pulse::SubscriptionEventType::New {
-                                    "Adding"
-                                } else {
-                                    "Removing"
-                                };
-                                let dev = if f == pulse::SubscriptionEventFacility::Sink {
-                                    "sink"
-                                } else {
-                                    "source "
-                                };
-                                log!("{} {} index {}", op, dev, index);
-
-                                unsafe {
-                                    ctx.collection_changed_callback.unwrap()(ctx as *mut _ as *mut _,
-                                                                             ctx.collection_changed_user_ptr);
-                                }
-                            }
-                        },
-                        _ => {},
+            if (f == pulse::SubscriptionEventFacility::Source)
+                | (f == pulse::SubscriptionEventFacility::Sink)
+            {
+                if (t == pulse::SubscriptionEventType::Remove)
+                    | (t == pulse::SubscriptionEventType::New)
+                {
+                    if log_enabled() {
+                        let op = if t == pulse::SubscriptionEventType::New {
+                            "Adding"
+                        } else {
+                            "Removing"
+                        };
+                        let dev = if f == pulse::SubscriptionEventFacility::Sink {
+                            "sink"
+                        } else {
+                            "source "
+                        };
+                        cubeb_log!("{} {} index {}", op, dev, index);
                     }
-                },
-                _ => {},
+                    unsafe {
+                        ctx.collection_changed_callback.unwrap()(
+                            ctx as *mut _ as *mut _,
+                            ctx.collection_changed_user_ptr,
+                        );
+                    }
+                }
             }
         }
 
         fn success(_: &pulse::Context, success: i32, user_data: *mut c_void) {
-            let ctx = unsafe { &*(user_data as *mut Context) };
+            let ctx = unsafe { &*(user_data as *mut PulseContext) };
             debug_assert_ne!(success, 0);
             ctx.mainloop.signal();
         }
 
         self.collection_changed_callback = cb;
         self.collection_changed_user_ptr = user_ptr;
 
-        let user_data: *mut c_void = self as *mut _ as *mut _;
+        let user_data: *mut c_void = self as *const _ as *mut _;
         if let Some(ref context) = self.context {
             self.mainloop.lock();
 
             let mut mask = pulse::SubscriptionMask::empty();
             if self.collection_changed_callback.is_none() {
                 // Unregister subscription
                 context.clear_subscribe_callback();
             } else {
                 context.set_subscribe_callback(update_collection, user_data);
-                if devtype.contains(cubeb::DeviceType::INPUT) {
+                if devtype.contains(DeviceType::INPUT) {
                     mask |= pulse::SubscriptionMask::SOURCE
                 };
-                if devtype.contains(cubeb::DeviceType::OUTPUT) {
+                if devtype.contains(DeviceType::OUTPUT) {
                     mask = pulse::SubscriptionMask::SINK
                 };
             }
 
             if let Ok(o) = context.subscribe(mask, success, self as *const _ as *mut _) {
                 self.operation_wait(None, &o);
             } else {
                 self.mainloop.unlock();
-                log!("Context subscribe failed");
-                return cubeb::ERROR;
+                cubeb_log!("Context subscribe failed");
+                return Err(Error::error());
             }
 
             self.mainloop.unlock();
         }
 
-        cubeb::OK
+        Ok(())
     }
+}
 
-    pub fn context_init(&mut self) -> i32 {
+impl Drop for PulseContext {
+    fn drop(&mut self) {
+        self.destroy();
+    }
+}
+
+impl PulseContext {
+    /* Initialize PulseAudio Context */
+    fn context_init(&mut self) -> Result<()> {
         fn error_state(c: &pulse::Context, u: *mut c_void) {
-            let ctx = unsafe { &mut *(u as *mut Context) };
+            let ctx = unsafe { &mut *(u as *mut PulseContext) };
             if !c.get_state().is_good() {
                 ctx.error = true;
             }
             ctx.mainloop.signal();
         }
 
         if self.context.is_some() {
             debug_assert!(self.error);
@@ -518,47 +579,49 @@ impl Context {
                 Some(s) => Some(s.as_ref()),
                 None => None,
             };
             pulse::Context::new(&self.mainloop.get_api(), name)
         };
 
         let context_ptr: *mut c_void = self as *mut _ as *mut _;
         if self.context.is_none() {
-            return cubeb::ERROR;
+            return Err(Error::error());
         }
 
         self.mainloop.lock();
         if let Some(ref context) = self.context {
             context.set_state_callback(error_state, context_ptr);
             let _ = context.connect(None, pulse::ContextFlags::empty(), ptr::null());
         }
 
         if !self.wait_until_context_ready() {
             self.mainloop.unlock();
             self.context_destroy();
-            return cubeb::ERROR;
+            return Err(Error::error());
         }
 
         self.mainloop.unlock();
 
         let version_str = unsafe { CStr::from_ptr(pulse::library_version()) };
         if let Ok(version) = semver::Version::parse(&version_str.to_string_lossy()) {
-            self.version_0_9_8 = version >= semver::Version::parse("0.9.8").expect("Failed to parse version");
-            self.version_2_0_0 = version >= semver::Version::parse("2.0.0").expect("Failed to parse version");
+            self.version_0_9_8 =
+                version >= semver::Version::parse("0.9.8").expect("Failed to parse version");
+            self.version_2_0_0 =
+                version >= semver::Version::parse("2.0.0").expect("Failed to parse version");
         }
 
         self.error = false;
 
-        cubeb::OK
+        Ok(())
     }
 
     fn context_destroy(&mut self) {
         fn drain_complete(_: &pulse::Context, u: *mut c_void) {
-            let ctx = unsafe { &*(u as *mut Context) };
+            let ctx = unsafe { &*(u as *mut PulseContext) };
             ctx.mainloop.signal();
         }
 
         let context_ptr: *mut c_void = self as *mut _ as *mut _;
         if let Some(ctx) = self.context.take() {
             self.mainloop.lock();
             if let Ok(o) = ctx.drain(drain_complete, context_ptr) {
                 self.operation_wait(None, &o);
@@ -566,17 +629,18 @@ impl Context {
             ctx.clear_state_callback();
             ctx.disconnect();
             ctx.unref();
             self.mainloop.unlock();
         }
     }
 
     pub fn operation_wait<'a, S>(&self, s: S, o: &pulse::Operation) -> bool
-        where S: Into<Option<&'a pulse::Stream>>
+    where
+        S: Into<Option<&'a pulse::Stream>>,
     {
         let stream = s.into();
         while o.get_state() == PA_OPERATION_RUNNING {
             self.mainloop.wait();
             if let Some(ref context) = self.context {
                 if !context.get_state().is_good() {
                     return false;
                 }
@@ -604,40 +668,41 @@ impl Context {
                 }
                 self.mainloop.wait();
             }
         }
 
         true
     }
 
-    fn state_from_port(&self, i: *const pa_port_info) -> cubeb::DeviceState {
+    fn state_from_port(&self, i: *const pa_port_info) -> ffi::cubeb_device_state {
         if !i.is_null() {
             let info = unsafe { *i };
             if self.version_2_0_0 && info.available == PA_PORT_AVAILABLE_NO {
-                cubeb::DeviceState::Unplugged
+                ffi::CUBEB_DEVICE_STATE_UNPLUGGED
             } else {
-                cubeb::DeviceState::Enabled
+                ffi::CUBEB_DEVICE_STATE_ENABLED
             }
         } else {
-            cubeb::DeviceState::Enabled
+            ffi::CUBEB_DEVICE_STATE_ENABLED
         }
     }
 }
 
 struct PulseDevListData<'a> {
     default_sink_name: CString,
     default_source_name: CString,
-    devinfo: Vec<cubeb::DeviceInfo>,
-    context: &'a Context,
+    devinfo: Vec<ffi::cubeb_device_info>,
+    context: &'a PulseContext,
 }
 
 impl<'a> PulseDevListData<'a> {
-    pub fn new<'b>(context: &'b Context) -> Self
-        where 'b: 'a
+    pub fn new<'b>(context: &'b PulseContext) -> Self
+    where
+        'b: 'a,
     {
         PulseDevListData {
             default_sink_name: CString::default(),
             default_source_name: CString::default(),
             devinfo: Vec::new(),
             context: context,
         }
     }
@@ -646,18 +711,18 @@ impl<'a> PulseDevListData<'a> {
 impl<'a> Drop for PulseDevListData<'a> {
     fn drop(&mut self) {
         for elem in &mut self.devinfo {
             let _ = unsafe { Box::from_raw(elem) };
         }
     }
 }
 
-fn pulse_format_to_cubeb_format(format: pa_sample_format_t) -> cubeb::DeviceFmt {
+fn pulse_format_to_cubeb_format(format: pa_sample_format_t) -> ffi::cubeb_device_fmt {
     match format {
-        PA_SAMPLE_S16LE => cubeb::DeviceFmt::S16LE,
-        PA_SAMPLE_S16BE => cubeb::DeviceFmt::S16BE,
-        PA_SAMPLE_FLOAT32LE => cubeb::DeviceFmt::F32LE,
-        PA_SAMPLE_FLOAT32BE => cubeb::DeviceFmt::F32BE,
+        PA_SAMPLE_S16LE => ffi::CUBEB_DEVICE_FMT_S16LE,
+        PA_SAMPLE_S16BE => ffi::CUBEB_DEVICE_FMT_S16BE,
+        PA_SAMPLE_FLOAT32LE => ffi::CUBEB_DEVICE_FMT_F32LE,
+        PA_SAMPLE_FLOAT32BE => ffi::CUBEB_DEVICE_FMT_F32BE,
         // Unsupported format, return F32NE
-        _ => cubeb::DeviceFmt::F32NE,
+        _ => ffi::CUBEB_DEVICE_FMT_F32NE,
     }
 }
--- a/media/libcubeb/cubeb-pulse-rs/src/backend/cork_state.rs
+++ b/media/libcubeb/cubeb-pulse-rs/src/backend/cork_state.rs
@@ -1,9 +1,9 @@
-// Copyright © 2017 Mozilla Foundation
+// Copyright © 2017-2018 Mozilla Foundation
 //
 // This program is made available under an ISC-style license.  See the
 // accompanying file LICENSE for details.
 
 use std::ops;
 
 #[repr(C)]
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
--- a/media/libcubeb/cubeb-pulse-rs/src/backend/intern.rs
+++ b/media/libcubeb/cubeb-pulse-rs/src/backend/intern.rs
@@ -1,45 +1,45 @@
-// Copyright © 2017 Mozilla Foundation
+// Copyright © 2017-2018 Mozilla Foundation
 //
 // This program is made available under an ISC-style license.  See the
 // accompanying file LICENSE for details.
 
 use std::ffi::{CStr, CString};
 use std::os::raw::c_char;
 
 #[derive(Debug)]
 pub struct Intern {
-    vec: Vec<Box<CString>>
+    vec: Vec<Box<CString>>,
 }
 
 impl Intern {
     pub fn new() -> Intern {
-        Intern {
-            vec: Vec::new()
-        }
+        Intern { vec: Vec::new() }
     }
 
     pub fn add(&mut self, string: &CStr) -> *const c_char {
-        fn eq(s1: &CStr, s2: &CStr) -> bool { s1 == s2 }
+        fn eq(s1: &CStr, s2: &CStr) -> bool {
+            s1 == s2
+        }
         for s in &self.vec {
             if eq(s, string) {
                 return s.as_ptr();
             }
         }
 
         self.vec.push(Box::new(string.to_owned()));
         self.vec.last().unwrap().as_ptr()
     }
 }
 
 #[cfg(test)]
 mod tests {
+    use super::Intern;
     use std::ffi::CStr;
-    use super::Intern;
 
     #[test]
     fn intern() {
         fn cstr(str: &[u8]) -> &CStr {
             CStr::from_bytes_with_nul(str).unwrap()
         }
 
         let mut intern = Intern::new();
new file mode 100644
--- /dev/null
+++ b/media/libcubeb/cubeb-pulse-rs/src/backend/mixer.rs
@@ -0,0 +1,99 @@
+// Copyright © 2017-2018 Mozilla Foundation
+//
+// This program is made available under an ISC-style license.  See the
+// accompanying file LICENSE for details.
+
+use cubeb_backend::ffi::*;
+
+static CHANNEL_LAYOUT_UNDEFINED: &'static [cubeb_channel] = &[CHANNEL_INVALID];
+static CHANNEL_LAYOUT_DUAL_MONO: &'static [cubeb_channel] = &[CHANNEL_LEFT, CHANNEL_RIGHT];
+static CHANNEL_LAYOUT_DUAL_MONO_LFE: &'static [cubeb_channel] =
+    &[CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_LFE];
+static CHANNEL_LAYOUT_MONO: &'static [cubeb_channel] = &[CHANNEL_MONO];
+static CHANNEL_LAYOUT_MONO_LFE: &'static [cubeb_channel] = &[CHANNEL_MONO, CHANNEL_LFE];
+static CHANNEL_LAYOUT_STEREO: &'static [cubeb_channel] = &[CHANNEL_LEFT, CHANNEL_RIGHT];
+static CHANNEL_LAYOUT_STEREO_LFE: &'static [cubeb_channel] =
+    &[CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_LFE];
+static CHANNEL_LAYOUT_3F: &'static [cubeb_channel] = &[CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER];
+static CHANNEL_LAYOUT_3FLFE: &'static [cubeb_channel] =
+    &[CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER, CHANNEL_LFE];
+static CHANNEL_LAYOUT_2F1: &'static [cubeb_channel] =
+    &[CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_RCENTER];
+static CHANNEL_LAYOUT_2F1LFE: &'static [cubeb_channel] =
+    &[CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_LFE, CHANNEL_RCENTER];
+static CHANNEL_LAYOUT_3F1: &'static [cubeb_channel] =
+    &[CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER, CHANNEL_RCENTER];
+static CHANNEL_LAYOUT_3F1LFE: &'static [cubeb_channel] = &[
+    CHANNEL_LEFT,
+    CHANNEL_RIGHT,
+    CHANNEL_CENTER,
+    CHANNEL_LFE,
+    CHANNEL_RCENTER,
+];
+static CHANNEL_LAYOUT_2F2: &'static [cubeb_channel] =
+    &[CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_LS, CHANNEL_RS];
+static CHANNEL_LAYOUT_2F2LFE: &'static [cubeb_channel] = &[
+    CHANNEL_LEFT,
+    CHANNEL_RIGHT,
+    CHANNEL_LFE,
+    CHANNEL_LS,
+    CHANNEL_RS,
+];
+static CHANNEL_LAYOUT_3F2: &'static [cubeb_channel] = &[
+    CHANNEL_LEFT,
+    CHANNEL_RIGHT,
+    CHANNEL_CENTER,
+    CHANNEL_LS,
+    CHANNEL_RS,
+];
+static CHANNEL_LAYOUT_3F2LFE: &'static [cubeb_channel] = &[
+    CHANNEL_LEFT,
+    CHANNEL_RIGHT,
+    CHANNEL_CENTER,
+    CHANNEL_LFE,
+    CHANNEL_LS,
+    CHANNEL_RS,
+];
+static CHANNEL_LAYOUT_3F3RLFE: &'static [cubeb_channel] = &[
+    CHANNEL_LEFT,
+    CHANNEL_RIGHT,
+    CHANNEL_CENTER,
+    CHANNEL_LFE,
+    CHANNEL_RCENTER,
+    CHANNEL_LS,
+    CHANNEL_RS,
+];
+static CHANNEL_LAYOUT_3F4LFE: &'static [cubeb_channel] = &[
+    CHANNEL_LEFT,
+    CHANNEL_RIGHT,
+    CHANNEL_CENTER,
+    CHANNEL_LFE,
+    CHANNEL_RLS,
+    CHANNEL_RRS,
+    CHANNEL_LS,
+    CHANNEL_RS,
+];
+
+pub fn channel_index_to_order(layout: cubeb_channel_layout) -> &'static [cubeb_channel] {
+    match layout {
+        CUBEB_LAYOUT_DUAL_MONO => CHANNEL_LAYOUT_DUAL_MONO,
+        CUBEB_LAYOUT_DUAL_MONO_LFE => CHANNEL_LAYOUT_DUAL_MONO_LFE,
+        CUBEB_LAYOUT_MONO => CHANNEL_LAYOUT_MONO,
+        CUBEB_LAYOUT_MONO_LFE => CHANNEL_LAYOUT_MONO_LFE,
+        CUBEB_LAYOUT_STEREO => CHANNEL_LAYOUT_STEREO,
+        CUBEB_LAYOUT_STEREO_LFE => CHANNEL_LAYOUT_STEREO_LFE,
+        CUBEB_LAYOUT_3F => CHANNEL_LAYOUT_3F,
+        CUBEB_LAYOUT_3F_LFE => CHANNEL_LAYOUT_3FLFE,
+        CUBEB_LAYOUT_2F1 => CHANNEL_LAYOUT_2F1,
+        CUBEB_LAYOUT_2F1_LFE => CHANNEL_LAYOUT_2F1LFE,
+        CUBEB_LAYOUT_3F1 => CHANNEL_LAYOUT_3F1,
+        CUBEB_LAYOUT_3F1_LFE => CHANNEL_LAYOUT_3F1LFE,
+        CUBEB_LAYOUT_2F2 => CHANNEL_LAYOUT_2F2,
+        CUBEB_LAYOUT_2F2_LFE => CHANNEL_LAYOUT_2F2LFE,
+        CUBEB_LAYOUT_3F2 => CHANNEL_LAYOUT_3F2,
+        CUBEB_LAYOUT_3F2_LFE => CHANNEL_LAYOUT_3F2LFE,
+        CUBEB_LAYOUT_3F3R_LFE => CHANNEL_LAYOUT_3F3RLFE,
+        CUBEB_LAYOUT_3F4_LFE => CHANNEL_LAYOUT_3F4LFE,
+        _ => CHANNEL_LAYOUT_UNDEFINED,
+    }
+}
--- a/media/libcubeb/cubeb-pulse-rs/src/backend/mod.rs
+++ b/media/libcubeb/cubeb-pulse-rs/src/backend/mod.rs
@@ -1,24 +1,26 @@
-// Copyright © 2017 Mozilla Foundation
+// Copyright © 2017-2018 Mozilla Foundation
 //
 // This program is made available under an ISC-style license.  See the
 // accompanying file LICENSE for details.
 
 mod context;
 mod cork_state;
+mod mixer;
 mod stream;
 mod intern;
 
-use std::os::raw::c_char;
+pub use self::context::PulseContext;
+use self::intern::Intern;
+pub use self::stream::Device;
+pub use self::stream::PulseStream;
 use std::ffi::CStr;
-
-pub type Result<T> = ::std::result::Result<T, i32>;
-
-pub use self::context::Context;
-pub use self::stream::Device;
-pub use self::stream::Stream;
-use self::intern::Intern;
+use std::os::raw::c_char;
 
 // helper to convert *const c_char to Option<CStr>
 fn try_cstr_from<'str>(s: *const c_char) -> Option<&'str CStr> {
-    if s.is_null() { None } else { Some(unsafe { CStr::from_ptr(s) }) }
+    if s.is_null() {
+        None
+    } else {
+        Some(unsafe { CStr::from_ptr(s) })
+    }
 }
--- a/media/libcubeb/cubeb-pulse-rs/src/backend/stream.rs
+++ b/media/libcubeb/cubeb-pulse-rs/src/backend/stream.rs
@@ -1,133 +1,125 @@
-// Copyright © 2017 Mozilla Foundation
+// Copyright © 2017-2018 Mozilla Foundation
 //
 // This program is made available under an ISC-style license.  See the
 // accompanying file LICENSE for details.
 
 use backend::*;
 use backend::cork_state::CorkState;
-use cubeb;
+use cubeb_backend::{ffi, log_enabled, ChannelLayout, DeviceId, DeviceRef, Error, Result,
+                    SampleFormat, StreamOps, StreamParamsRef, StreamPrefs};
 use pulse::{self, CVolumeExt, ChannelMapExt, SampleSpecExt, StreamLatency, USecExt};
 use pulse_ffi::*;
+use std::{mem, ptr};
 use std::ffi::{CStr, CString};
 use std::os::raw::{c_long, c_void};
-use std::ptr;
 
 const PULSE_NO_GAIN: f32 = -1.0;
 
-fn cubeb_channel_to_pa_channel(channel: cubeb::Channel) -> pa_channel_position_t {
-    assert_ne!(channel, cubeb::CHANNEL_INVALID);
+fn cubeb_channel_to_pa_channel(channel: ffi::cubeb_channel) -> pa_channel_position_t {
+    use cubeb_backend::ffi::*;
+    assert_ne!(channel, CHANNEL_INVALID);
 
-    // This variable may be used for multiple times, so we should avoid to
-    // allocate it in stack, or it will be created and removed repeatedly.
-    // Use static to allocate this local variable in data space instead of stack.
-    static MAP: [pa_channel_position_t; 10] = [
-        // PA_CHANNEL_POSITION_INVALID,      // CHANNEL_INVALID
-        PA_CHANNEL_POSITION_MONO,         // CHANNEL_MONO
-        PA_CHANNEL_POSITION_FRONT_LEFT,   // CHANNEL_LEFT
-        PA_CHANNEL_POSITION_FRONT_RIGHT,  // CHANNEL_RIGHT
-        PA_CHANNEL_POSITION_FRONT_CENTER, // CHANNEL_CENTER
-        PA_CHANNEL_POSITION_SIDE_LEFT,    // CHANNEL_LS
-        PA_CHANNEL_POSITION_SIDE_RIGHT,   // CHANNEL_RS
-        PA_CHANNEL_POSITION_REAR_LEFT,    // CHANNEL_RLS
-        PA_CHANNEL_POSITION_REAR_CENTER,  // CHANNEL_RCENTER
-        PA_CHANNEL_POSITION_REAR_RIGHT,   // CHANNEL_RRS
-        PA_CHANNEL_POSITION_LFE           // CHANNEL_LFE
-    ];
-
-    let idx: i32 = channel;
-    MAP[idx as usize]
+    match channel {
+        CHANNEL_LEFT => PA_CHANNEL_POSITION_FRONT_LEFT,
+        CHANNEL_RIGHT => PA_CHANNEL_POSITION_FRONT_RIGHT,
+        CHANNEL_CENTER => PA_CHANNEL_POSITION_FRONT_CENTER,
+        CHANNEL_LS => PA_CHANNEL_POSITION_SIDE_LEFT,
+        CHANNEL_RS => PA_CHANNEL_POSITION_SIDE_RIGHT,
+        CHANNEL_RLS => PA_CHANNEL_POSITION_REAR_LEFT,
+        CHANNEL_RCENTER => PA_CHANNEL_POSITION_REAR_CENTER,
+        CHANNEL_RRS => PA_CHANNEL_POSITION_REAR_RIGHT,
+        CHANNEL_LFE => PA_CHANNEL_POSITION_LFE,
+        // Also handles CHANNEL_MONO case
+        _ => PA_CHANNEL_POSITION_MONO,
+    }
 }
 
-fn layout_to_channel_map(layout: cubeb::ChannelLayout) -> pulse::ChannelMap {
-    assert_ne!(layout, cubeb::LAYOUT_UNDEFINED);
+fn layout_to_channel_map(layout: ChannelLayout) -> pulse::ChannelMap {
+    assert_ne!(layout, ChannelLayout::Undefined);
 
-    let order = cubeb::mixer::channel_index_to_order(layout);
+    let order = mixer::channel_index_to_order(layout.into());
 
     let mut cm = pulse::ChannelMap::init();
     cm.channels = order.len() as u8;
     for (s, d) in order.iter().zip(cm.map.iter_mut()) {
         *d = cubeb_channel_to_pa_channel(*s);
     }
     cm
 }
 
-pub struct Device(cubeb::Device);
+pub struct Device(ffi::cubeb_device);
 
 impl Drop for Device {
     fn drop(&mut self) {
         unsafe {
             if !self.0.input_name.is_null() {
-                let _ = CString::from_raw(self.0.input_name);
+                let _ = CString::from_raw(self.0.input_name as *mut _);
             }
             if !self.0.output_name.is_null() {
-                let _ = CString::from_raw(self.0.output_name);
+                let _ = CString::from_raw(self.0.output_name as *mut _);
             }
         }
     }
 }
 
 #[derive(Debug)]
-pub struct Stream<'ctx> {
-    context: &'ctx Context,
+pub struct PulseStream<'ctx> {
+    context: &'ctx PulseContext,
+    user_ptr: *mut c_void,
     output_stream: Option<pulse::Stream>,
     input_stream: Option<pulse::Stream>,
-    data_callback: cubeb::DataCallback,
-    state_callback: cubeb::StateCallback,
-    user_ptr: *mut c_void,
+    data_callback: ffi::cubeb_data_callback,
+    state_callback: ffi::cubeb_state_callback,
     drain_timer: *mut pa_time_event,
     output_sample_spec: pulse::SampleSpec,
     input_sample_spec: pulse::SampleSpec,
     shutdown: bool,
     volume: f32,
-    state: cubeb::State,
-}
-
-impl<'ctx> Drop for Stream<'ctx> {
-    fn drop(&mut self) {
-        self.destroy();
-    }
+    state: ffi::cubeb_state,
 }
 
-impl<'ctx> Stream<'ctx> {
+impl<'ctx> PulseStream<'ctx> {
     #[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
-    pub fn new(context: &'ctx Context,
-               stream_name: &CStr,
-               input_device: cubeb::DeviceId,
-               input_stream_params: Option<cubeb::StreamParams>,
-               output_device: cubeb::DeviceId,
-               output_stream_params: Option<cubeb::StreamParams>,
-               latency_frames: u32,
-               data_callback: cubeb::DataCallback,
-               state_callback: cubeb::StateCallback,
-               user_ptr: *mut c_void)
-               -> Result<Box<Stream<'ctx>>> {
-
+    pub fn new(
+        context: &'ctx PulseContext,
+        stream_name: Option<&CStr>,
+        input_device: DeviceId,
+        input_stream_params: Option<&StreamParamsRef>,
+        output_device: DeviceId,
+        output_stream_params: Option<&StreamParamsRef>,
+        latency_frames: u32,
+        data_callback: ffi::cubeb_data_callback,
+        state_callback: ffi::cubeb_state_callback,
+        user_ptr: *mut c_void,
+    ) -> Result<Box<Self>> {
         fn check_error(s: &pulse::Stream, u: *mut c_void) {
-            let stm = unsafe { &mut *(u as *mut Stream) };
+            let stm = unsafe { &mut *(u as *mut PulseStream) };
             if !s.get_state().is_good() {
-                stm.state_change_callback(cubeb::STATE_ERROR);
+                stm.state_change_callback(ffi::CUBEB_STATE_ERROR);
             }
             stm.context.mainloop.signal();
         }
 
         fn read_data(s: &pulse::Stream, nbytes: usize, u: *mut c_void) {
-            fn read_from_input(s: &pulse::Stream, buffer: *mut *const c_void, size: *mut usize) -> i32 {
-                let readable_size: i32 = s.readable_size()
-                    .and_then(|s| Ok(s as i32))
-                    .unwrap_or(-1);
+            fn read_from_input(
+                s: &pulse::Stream,
+                buffer: *mut *const c_void,
+                size: *mut usize,
+            ) -> i32 {
+                let readable_size: i32 = s.readable_size().and_then(|s| Ok(s as i32)).unwrap_or(-1);
                 if readable_size > 0 && unsafe { s.peek(buffer, size).is_err() } {
                     return -1;
                 }
                 readable_size
             }
 
-            logv!("Input callback buffer size {}", nbytes);
-            let stm = unsafe { &mut *(u as *mut Stream) };
+            cubeb_logv!("Input callback buffer size {}", nbytes);
+            let stm = unsafe { &mut *(u as *mut PulseStream) };
             if stm.shutdown {
                 return;
             }
 
             let mut read_data: *const c_void = ptr::null();
             let mut read_size: usize = 0;
             while read_from_input(s, &mut read_data, &mut read_size) > 0 {
                 /* read_data can be NULL in case of a hole. */
@@ -139,21 +131,23 @@ impl<'ctx> Stream<'ctx> {
                         // input/capture + output/playback operation
                         let out_frame_size = stm.output_sample_spec.frame_size();
                         let write_size = read_frames * out_frame_size;
                         // Offer full duplex data for writing
                         stm.trigger_user_callback(read_data, write_size);
                     } else {
                         // input/capture only operation. Call callback directly
                         let got = unsafe {
-                            stm.data_callback.unwrap()(stm as *mut _ as *mut _,
-                                                       stm.user_ptr,
-                                                       read_data,
-                                                       ptr::null_mut(),
-                                                       read_frames as c_long)
+                            stm.data_callback.unwrap()(
+                                stm as *mut _ as *mut _,
+                                stm.user_ptr,
+                                read_data,
+                                ptr::null_mut(),
+                                read_frames as c_long,
+                            )
                         };
 
                         if got < 0 || got as usize != read_frames {
                             let _ = s.cancel_write();
                             stm.shutdown = true;
                             break;
                         }
                     }
@@ -165,179 +159,196 @@ impl<'ctx> Stream<'ctx> {
 
                 if stm.shutdown {
                     return;
                 }
             }
         }
 
         fn write_data(_: &pulse::Stream, nbytes: usize, u: *mut c_void) {
-            logv!("Output callback to be written buffer size {}", nbytes);
-            let stm = unsafe { &mut *(u as *mut Stream) };
-            if stm.shutdown || stm.state != cubeb::STATE_STARTED {
+            cubeb_logv!("Output callback to be written buffer size {}", nbytes);
+            let stm = unsafe { &mut *(u as *mut PulseStream) };
+            if stm.shutdown || stm.state != ffi::CUBEB_STATE_STARTED {
                 return;
             }
 
             if stm.input_stream.is_none() {
                 // Output/playback only operation.
                 // Write directly to output
                 debug_assert!(stm.output_stream.is_some());
                 stm.trigger_user_callback(ptr::null(), nbytes);
             }
         }
 
-        let mut stm = Box::new(Stream {
-                                   context: context,
-                                   output_stream: None,
-                                   input_stream: None,
-                                   data_callback: data_callback,
-                                   state_callback: state_callback,
-                                   user_ptr: user_ptr,
-                                   drain_timer: ptr::null_mut(),
-                                   output_sample_spec: pulse::SampleSpec::default(),
-                                   input_sample_spec: pulse::SampleSpec::default(),
-                                   shutdown: false,
-                                   volume: PULSE_NO_GAIN,
-                                   state: cubeb::STATE_ERROR,
-                               });
+        let mut stm = Box::new(PulseStream {
+            context: context,
+            output_stream: None,
+            input_stream: None,
+            data_callback: data_callback,
+            state_callback: state_callback,
+            user_ptr: user_ptr,
+            drain_timer: ptr::null_mut(),
+            output_sample_spec: pulse::SampleSpec::default(),
+            input_sample_spec: pulse::SampleSpec::default(),
+            shutdown: false,
+            volume: PULSE_NO_GAIN,
+            state: ffi::CUBEB_STATE_ERROR,
+        });
 
         if let Some(ref context) = stm.context.context {
             stm.context.mainloop.lock();
 
             // Setup output stream
-            if let Some(ref stream_params) = output_stream_params {
-                match Stream::stream_init(context, stream_params, stream_name) {
+            if let Some(stream_params) = output_stream_params {
+                match PulseStream::stream_init(context, stream_params, stream_name) {
                     Ok(s) => {
                         stm.output_sample_spec = *s.get_sample_spec();
 
                         s.set_state_callback(check_error, stm.as_mut() as *mut _ as *mut _);
                         s.set_write_callback(write_data, stm.as_mut() as *mut _ as *mut _);
 
-                        let battr = set_buffering_attribute(latency_frames, &stm.output_sample_spec);
+                        let battr =
+                            set_buffering_attribute(latency_frames, &stm.output_sample_spec);
                         let device_name = super::try_cstr_from(output_device as *const _);
-                        let _ = s.connect_playback(device_name,
-                                                   &battr,
-                                                   pulse::StreamFlags::AUTO_TIMING_UPDATE | pulse::StreamFlags::INTERPOLATE_TIMING |
-                                                   pulse::StreamFlags::START_CORKED |
-                                                   pulse::StreamFlags::ADJUST_LATENCY,
-                                                   None,
-                                                   None);
+                        let _ = s.connect_playback(
+                            device_name,
+                            &battr,
+                            pulse::StreamFlags::AUTO_TIMING_UPDATE
+                                | pulse::StreamFlags::INTERPOLATE_TIMING
+                                | pulse::StreamFlags::START_CORKED
+                                | pulse::StreamFlags::ADJUST_LATENCY,
+                            None,
+                            None,
+                        );
 
                         stm.output_stream = Some(s);
-                    },
+                    }
                     Err(e) => {
                         stm.context.mainloop.unlock();
                         stm.destroy();
                         return Err(e);
-                    },
+                    }
                 }
             }
 
             // Set up input stream
             if let Some(ref stream_params) = input_stream_params {
-                match Stream::stream_init(context, stream_params, stream_name) {
+                match PulseStream::stream_init(context, stream_params, stream_name) {
                     Ok(s) => {
                         stm.input_sample_spec = *s.get_sample_spec();
 
                         s.set_state_callback(check_error, stm.as_mut() as *mut _ as *mut _);
                         s.set_read_callback(read_data, stm.as_mut() as *mut _ as *mut _);
 
                         let battr = set_buffering_attribute(latency_frames, &stm.input_sample_spec);
                         let device_name = super::try_cstr_from(input_device as *const _);
-                        let _ = s.connect_record(device_name,
-                                                 &battr,
-                                                 pulse::StreamFlags::AUTO_TIMING_UPDATE | pulse::StreamFlags::INTERPOLATE_TIMING |
-                                                 pulse::StreamFlags::START_CORKED |
-                                                 pulse::StreamFlags::ADJUST_LATENCY);
+                        let _ = s.connect_record(
+                            device_name,
+                            &battr,
+                            pulse::StreamFlags::AUTO_TIMING_UPDATE
+                                | pulse::StreamFlags::INTERPOLATE_TIMING
+                                | pulse::StreamFlags::START_CORKED
+                                | pulse::StreamFlags::ADJUST_LATENCY,
+                        );
 
                         stm.input_stream = Some(s);
-                    },
+                    }
                     Err(e) => {
                         stm.context.mainloop.unlock();
                         stm.destroy();
                         return Err(e);
-                    },
+                    }
                 }
             }
 
             let r = if stm.wait_until_ready() {
                 /* force a timing update now, otherwise timing info does not become valid
                 until some point after initialization has completed. */
                 stm.update_timing_info()
             } else {
                 false
             };
 
             stm.context.mainloop.unlock();
 
             if !r {
                 stm.destroy();
-                return Err(cubeb::ERROR);
+                return Err(Error::error());
             }
 
-            if cubeb::log_enabled() {
+            // TODO:
+            if log_enabled() {
                 if let Some(ref output_stream) = stm.output_stream {
                     let output_att = output_stream.get_buffer_attr();
-                    log!("Output buffer attributes maxlength {}, tlength {}, \
+                    cubeb_log!(
+                        "Output buffer attributes maxlength {}, tlength {}, \
                          prebuf {}, minreq {}, fragsize {}",
-                         output_att.maxlength,
-                         output_att.tlength,
-                         output_att.prebuf,
-                         output_att.minreq,
-                         output_att.fragsize);
+                        output_att.maxlength,
+                        output_att.tlength,
+                        output_att.prebuf,
+                        output_att.minreq,
+                        output_att.fragsize
+                    );
                 }
 
                 if let Some(ref input_stream) = stm.input_stream {
                     let input_att = input_stream.get_buffer_attr();
-                    log!("Input buffer attributes maxlength {}, tlength {}, \
-                          prebuf {}, minreq {}, fragsize {}",
-                         input_att.maxlength,
-                         input_att.tlength,
-                         input_att.prebuf,
-                         input_att.minreq,
-                         input_att.fragsize);
+                    cubeb_log!(
+                        "Input buffer attributes maxlength {}, tlength {}, \
+                         prebuf {}, minreq {}, fragsize {}",
+                        input_att.maxlength,
+                        input_att.tlength,
+                        input_att.prebuf,
+                        input_att.minreq,
+                        input_att.fragsize
+                    );
                 }
             }
         }
 
         Ok(stm)
     }
 
     fn destroy(&mut self) {
         self.cork(CorkState::cork());
 
         self.context.mainloop.lock();
         {
             if let Some(stm) = self.output_stream.take() {
                 if !self.drain_timer.is_null() {
                     /* there's no pa_rttime_free, so use this instead. */
-                    self.context
-                        .mainloop
-                        .get_api()
-                        .time_free(self.drain_timer);
+                    self.context.mainloop.get_api().time_free(self.drain_timer);
                 }
                 stm.clear_state_callback();
                 stm.clear_write_callback();
                 let _ = stm.disconnect();
                 stm.unref();
             }
 
             if let Some(stm) = self.input_stream.take() {
                 stm.clear_state_callback();
                 stm.clear_read_callback();
                 let _ = stm.disconnect();
                 stm.unref();
             }
         }
         self.context.mainloop.unlock();
     }
+}
 
-    pub fn start(&mut self) -> i32 {
+impl<'ctx> Drop for PulseStream<'ctx> {
+    fn drop(&mut self) {
+        self.destroy();
+    }
+}
+
+impl<'ctx> StreamOps for PulseStream<'ctx> {
+    fn start(&mut self) -> Result<()> {
         fn output_preroll(_: &pulse::MainloopApi, u: *mut c_void) {
-            let stm = unsafe { &mut *(u as *mut Stream) };
+            let stm = unsafe { &mut *(u as *mut PulseStream) };
             if !stm.shutdown {
                 let size = stm.output_stream
                     .as_ref()
                     .map_or(0, |s| s.writable_size().unwrap_or(0));
                 stm.trigger_user_callback(ptr::null_mut(), size);
             }
         }
 
@@ -347,86 +358,89 @@ impl<'ctx> Stream<'ctx> {
         if self.output_stream.is_some() && self.input_stream.is_none() {
             /* On output only case need to manually call user cb once in order to make
              * things roll. This is done via a defer event in order to execute it
              * from PA server thread. */
             self.context.mainloop.lock();
             self.context
                 .mainloop
                 .get_api()
-                .once(output_preroll, self as *mut _ as *mut _);
+                .once(output_preroll, self as *const _ as *mut _);
             self.context.mainloop.unlock();
         }
 
-        cubeb::OK
+        Ok(())
     }
 
-    pub fn stop(&mut self) -> i32 {
+    fn stop(&mut self) -> Result<()> {
         {
             self.context.mainloop.lock();
             self.shutdown = true;
             // If draining is taking place wait to finish
             while !self.drain_timer.is_null() {
                 self.context.mainloop.wait();
             }
             self.context.mainloop.unlock();
         }
         self.cork(CorkState::cork() | CorkState::notify());
 
-        cubeb::OK
+        Ok(())
     }
 
-    pub fn position(&self) -> Result<u64> {
+    fn reset_default_device(&mut self) -> Result<()> {
+        Err(not_supported())
+    }
+
+    fn position(&mut self) -> Result<u64> {
         let in_thread = self.context.mainloop.in_thread();
 
         if !in_thread {
             self.context.mainloop.lock();
         }
 
-        let r = match self.output_stream {
-            None => Err(cubeb::ERROR),
-            Some(ref stm) => {
-                match stm.get_time() {
-                    Ok(r_usec) => {
-                        let bytes = r_usec.to_bytes(&self.output_sample_spec);
-                        Ok((bytes / self.output_sample_spec.frame_size()) as u64)
-                    },
-                    Err(_) => Err(cubeb::ERROR),
-                }
-            },
+        if self.output_stream.is_none() {
+            return Err(Error::error());
+        }
+
+        let stm = self.output_stream.as_ref().unwrap();
+        let r = match stm.get_time() {
+            Ok(r_usec) => {
+                let bytes = r_usec.to_bytes(&self.output_sample_spec);
+                Ok((bytes / self.output_sample_spec.frame_size()) as u64)
+            }
+            Err(_) => Err(Error::error()),
         };
 
         if !in_thread {
             self.context.mainloop.unlock();
         }
 
         r
     }
 
-    pub fn latency(&self) -> Result<u32> {
+    fn latency(&mut self) -> Result<u32> {
         match self.output_stream {
-            None => Err(cubeb::ERROR),
-            Some(ref stm) => {
-                match stm.get_latency() {
-                    Ok(StreamLatency::Positive(r_usec)) => {
-                        let latency = (r_usec * pa_usec_t::from(self.output_sample_spec.rate) / PA_USEC_PER_SEC) as u32;
-                        Ok(latency)
-                    },
-                    Ok(_) => {
-                        panic!("Can not handle negative latency values.");
-                    },
-                    Err(_) => Err(cubeb::ERROR),
+            None => Err(Error::error()),
+            Some(ref stm) => match stm.get_latency() {
+                Ok(StreamLatency::Positive(r_usec)) => {
+                    let latency = (r_usec * pa_usec_t::from(self.output_sample_spec.rate)
+                        / PA_USEC_PER_SEC) as u32;
+                    Ok(latency)
                 }
+                Ok(_) => {
+                    panic!("Can not handle negative latency values.");
+                }
+                Err(_) => Err(Error::error()),
             },
         }
     }
 
-    pub fn set_volume(&mut self, volume: f32) -> i32 {
+    fn set_volume(&mut self, volume: f32) -> Result<()> {
         match self.output_stream {
-            None => cubeb::ERROR,
+            None => Err(Error::error()),
             Some(ref stm) => {
                 if let Some(ref context) = self.context.context {
                     self.context.mainloop.lock();
 
                     let mut cvol: pa_cvolume = Default::default();
 
                     /* if the pulse daemon is configured to use flat
                      * volumes, apply our own gain instead of changing
@@ -443,185 +457,218 @@ impl<'ctx> Stream<'ctx> {
                     } else {
                         let channels = stm.get_sample_spec().channels;
                         let vol = pulse::sw_volume_from_linear(f64::from(volume));
                         cvol.set(u32::from(channels), vol);
 
                         let index = stm.get_index();
 
                         let context_ptr = self.context as *const _ as *mut _;
-                        if let Ok(o) = context.set_sink_input_volume(index, &cvol, context_success, context_ptr) {
+                        if let Ok(o) = context.set_sink_input_volume(
+                            index,
+                            &cvol,
+                            context_success,
+                            context_ptr,
+                        ) {
                             self.context.operation_wait(stm, &o);
                         }
                     }
 
                     self.context.mainloop.unlock();
-                    cubeb::OK
+                    Ok(())
                 } else {
-                    cubeb::ERROR
+                    Err(Error::error())
                 }
-            },
+            }
         }
     }
 
-    pub fn set_panning(&mut self, panning: f32) -> i32 {
+    fn set_panning(&mut self, panning: f32) -> Result<()> {
         #[repr(C)]
         struct SinkInputInfoResult<'a> {
             pub cvol: pulse::CVolume,
             pub mainloop: &'a pulse::ThreadedMainloop,
         }
 
-        fn get_input_volume(_: &pulse::Context, info: *const pulse::SinkInputInfo, eol: i32, u: *mut c_void) {
+        fn get_input_volume(
+            _: &pulse::Context,
+            info: *const pulse::SinkInputInfo,
+            eol: i32,
+            u: *mut c_void,
+        ) {
             let r = unsafe { &mut *(u as *mut SinkInputInfoResult) };
             if eol == 0 {
                 let info = unsafe { *info };
                 r.cvol = info.volume;
             }
             r.mainloop.signal();
         }
 
-        match self.output_stream {
-            None => cubeb::ERROR,
-            Some(ref stm) => {
-                if let Some(ref context) = self.context.context {
-                    self.context.mainloop.lock();
+        if self.output_stream.is_none() {
+            return Err(Error::error());
+        }
+
+        let stm = self.output_stream.as_ref().unwrap();
 
-                    let map = stm.get_channel_map();
-                    if !map.can_balance() {
-                        self.context.mainloop.unlock();
-                        return cubeb::ERROR;
-                    }
+        if let Some(ref context) = self.context.context {
+            self.context.mainloop.lock();
 
-                    let index = stm.get_index();
+            let map = stm.get_channel_map();
+            if !map.can_balance() {
+                self.context.mainloop.unlock();
+                return Err(Error::error());
+            }
 
-                    let mut r = SinkInputInfoResult {
-                        cvol: pulse::CVolume::default(),
-                        mainloop: &self.context.mainloop,
-                    };
+            let index = stm.get_index();
 
-                    if let Ok(o) = context.get_sink_input_info(index, get_input_volume, &mut r as *mut _ as *mut _) {
-                        self.context.operation_wait(stm, &o);
-                    }
+            let mut r = SinkInputInfoResult {
+                cvol: pulse::CVolume::default(),
+                mainloop: &self.context.mainloop,
+            };
 
-                    r.cvol.set_balance(map, panning);
+            if let Ok(o) =
+                context.get_sink_input_info(index, get_input_volume, &mut r as *mut _ as *mut _)
+            {
+                self.context.operation_wait(stm, &o);
+            }
+
+            r.cvol.set_balance(map, panning);
 
-                    let context_ptr = self.context as *const _ as *mut _;
-                    if let Ok(o) = context.set_sink_input_volume(index, &r.cvol, context_success, context_ptr) {
-                        self.context.operation_wait(stm, &o);
-                    }
+            let context_ptr = self.context as *const _ as *mut _;
+            if let Ok(o) =
+                context.set_sink_input_volume(index, &r.cvol, context_success, context_ptr)
+            {
+                self.context.operation_wait(stm, &o);
+            }
 
-                    self.context.mainloop.unlock();
+            self.context.mainloop.unlock();
 
-                    cubeb::OK
-                } else {
-                    cubeb::ERROR
-                }
-            },
+            Ok(())
+        } else {
+            Err(Error::error())
         }
     }
 
-    pub fn current_device(&self) -> Result<Box<cubeb::Device>> {
+    fn current_device(&mut self) -> Result<&DeviceRef> {
         if self.context.version_0_9_8 {
-            let mut dev = Box::new(cubeb::Device::default());
+            let mut dev: Box<ffi::cubeb_device> = Box::new(unsafe { mem::zeroed() });
 
-            if self.input_stream.is_some() {
-                if let Some(ref stm) = self.input_stream {
-                    dev.input_name = match stm.get_device_name() {
-                        Ok(name) => name.to_owned().into_raw(),
-                        Err(_) => {
-                            return Err(cubeb::ERROR);
-                        },
+            if let Some(ref stm) = self.input_stream {
+                dev.input_name = match stm.get_device_name() {
+                    Ok(name) => name.to_owned().into_raw(),
+                    Err(_) => {
+                        return Err(Error::error());
                     }
                 }
             }
 
-            if !self.output_stream.is_some() {
-                if let Some(ref stm) = self.output_stream {
-                    dev.output_name = match stm.get_device_name() {
-                        Ok(name) => name.to_owned().into_raw(),
-                        Err(_) => {
-                            return Err(cubeb::ERROR);
-                        },
+            if let Some(ref stm) = self.output_stream {
+                dev.output_name = match stm.get_device_name() {
+                    Ok(name) => name.to_owned().into_raw(),
+                    Err(_) => {
+                        return Err(Error::error());
                     }
                 }
             }
 
-            Ok(dev)
+            Ok(unsafe { DeviceRef::from_ptr(Box::into_raw(dev) as *mut _) })
         } else {
-            Err(cubeb::ERROR_NOT_SUPPORTED)
+            Err(not_supported())
+        }
+    }
+
+    fn device_destroy(&mut self, device: &DeviceRef) -> Result<()> {
+        if device.as_ptr().is_null() {
+            Err(Error::error())
+        } else {
+            unsafe {
+                let _: Box<Device> = Box::from_raw(device.as_ptr() as *mut _);
+            }
+            Ok(())
         }
     }
 
-    fn stream_init(context: &pulse::Context,
-                   stream_params: &cubeb::StreamParams,
-                   stream_name: &CStr)
-                   -> Result<pulse::Stream> {
+    fn register_device_changed_callback(
+        &mut self,
+        _: ffi::cubeb_device_changed_callback,
+    ) -> Result<()> {
+        Err(Error::error())
+    }
+}
 
-        if stream_params.prefs == cubeb::StreamPrefs::STREAM_PREF_LOOPBACK {
-            return Err(cubeb::ERROR_NOT_SUPPORTED);
+impl<'ctx> PulseStream<'ctx> {
+    fn stream_init(
+        context: &pulse::Context,
+        stream_params: &StreamParamsRef,
+        stream_name: Option<&CStr>,
+    ) -> Result<pulse::Stream> {
+        if stream_params.prefs() == StreamPrefs::LOOPBACK {
+            return Err(not_supported());
         }
 
-        fn to_pulse_format(format: cubeb::SampleFormat) -> pulse::SampleFormat {
+        fn to_pulse_format(format: SampleFormat) -> pulse::SampleFormat {
             match format {
-                cubeb::SAMPLE_S16LE => pulse::SampleFormat::Signed16LE,
-                cubeb::SAMPLE_S16BE => pulse::SampleFormat::Signed16BE,
-                cubeb::SAMPLE_FLOAT32LE => pulse::SampleFormat::Float32LE,
-                cubeb::SAMPLE_FLOAT32BE => pulse::SampleFormat::Float32BE,
+                SampleFormat::S16LE => pulse::SampleFormat::Signed16LE,
+                SampleFormat::S16BE => pulse::SampleFormat::Signed16BE,
+                SampleFormat::Float32LE => pulse::SampleFormat::Float32LE,
+                SampleFormat::Float32BE => pulse::SampleFormat::Float32BE,
                 _ => pulse::SampleFormat::Invalid,
             }
         }
 
-        let fmt = to_pulse_format(stream_params.format);
+        let fmt = to_pulse_format(stream_params.format());
         if fmt == pulse::SampleFormat::Invalid {
-            return Err(cubeb::ERROR_INVALID_FORMAT);
+            return Err(invalid_format());
         }
 
         let ss = pulse::SampleSpec {
-            channels: stream_params.channels as u8,
+            channels: stream_params.channels() as u8,
             format: fmt.into(),
-            rate: stream_params.rate,
+            rate: stream_params.rate(),
         };
 
-        let cm: Option<pa_channel_map> = match stream_params.layout {
-            cubeb::LAYOUT_UNDEFINED => None,
-            _ => Some(layout_to_channel_map(stream_params.layout)),
+        let cm: Option<pa_channel_map> = match stream_params.layout() {
+            ChannelLayout::Undefined => None,
+            _ => Some(layout_to_channel_map(stream_params.layout())),
         };
 
-        let stream = pulse::Stream::new(context, stream_name, &ss, cm.as_ref());
+        let stream = pulse::Stream::new(context, stream_name.unwrap(), &ss, cm.as_ref());
 
         match stream {
-            None => Err(cubeb::ERROR),
+            None => Err(Error::error()),
             Some(stm) => Ok(stm),
         }
     }
 
     pub fn cork_stream(&self, stream: Option<&pulse::Stream>, state: CorkState) {
         if let Some(stm) = stream {
-            if let Ok(o) = stm.cork(state.is_cork() as i32,
-                                    stream_success,
-                                    self as *const _ as *mut _) {
+            if let Ok(o) = stm.cork(
+                state.is_cork() as i32,
+                stream_success,
+                self as *const _ as *mut _,
+            ) {
                 self.context.operation_wait(stream, &o);
             }
         }
     }
 
     fn cork(&mut self, state: CorkState) {
         {
             self.context.mainloop.lock();
             self.cork_stream(self.output_stream.as_ref(), state);
             self.cork_stream(self.input_stream.as_ref(), state);
             self.context.mainloop.unlock()
         }
 
         if state.is_notify() {
             self.state_change_callback(if state.is_cork() {
-                                           cubeb::STATE_STOPPED
-                                       } else {
-                                           cubeb::STATE_STARTED
-                                       });
+                ffi::CUBEB_STATE_STOPPED
+            } else {
+                ffi::CUBEB_STATE_STARTED
+            });
         }
     }
 
     fn update_timing_info(&self) -> bool {
         let mut r = false;
 
         if let Some(ref stm) = self.output_stream {
             if let Ok(o) = stm.update_timing_info(stream_success, self as *const _ as *mut _) {
@@ -637,25 +684,32 @@ impl<'ctx> Stream<'ctx> {
             if let Ok(o) = stm.update_timing_info(stream_success, self as *const _ as *mut _) {
                 r = self.context.operation_wait(stm, &o);
             }
         }
 
         r
     }
 
-    pub fn state_change_callback(&mut self, s: cubeb::State) {
+    pub fn state_change_callback(&mut self, s: ffi::cubeb_state) {
         self.state = s;
         unsafe {
-            (self.state_callback.unwrap())(self as *mut Stream as *mut cubeb::Stream, self.user_ptr, s);
-        }
+            (self.state_callback.unwrap())(
+                self as *mut PulseStream as *mut ffi::cubeb_stream,
+                self.user_ptr,
+                s,
+            )
+        };
     }
 
     fn wait_until_ready(&self) -> bool {
-        fn wait_until_io_stream_ready(stm: &pulse::Stream, mainloop: &pulse::ThreadedMainloop) -> bool {
+        fn wait_until_io_stream_ready(
+            stm: &pulse::Stream,
+            mainloop: &pulse::ThreadedMainloop,
+        ) -> bool {
             if mainloop.is_null() {
                 return false;
             }
 
             loop {
                 let state = stm.get_state();
                 if !state.is_good() {
                     return false;
@@ -681,146 +735,175 @@ impl<'ctx> Stream<'ctx> {
             }
         }
 
         true
     }
 
     #[cfg_attr(feature = "cargo-clippy", allow(cyclomatic_complexity))]
     fn trigger_user_callback(&mut self, input_data: *const c_void, nbytes: usize) {
-        fn drained_cb(a: &pulse::MainloopApi, e: *mut pa_time_event, _tv: &pulse::TimeVal, u: *mut c_void) {
-            let stm = unsafe { &mut *(u as *mut Stream) };
+        fn drained_cb(
+            a: &pulse::MainloopApi,
+            e: *mut pa_time_event,
+            _tv: &pulse::TimeVal,
+            u: *mut c_void,
+        ) {
+            let stm = unsafe { &mut *(u as *mut PulseStream) };
             debug_assert_eq!(stm.drain_timer, e);
-            stm.state_change_callback(cubeb::STATE_DRAINED);
+            stm.state_change_callback(ffi::CUBEB_STATE_DRAINED);
             /* there's no pa_rttime_free, so use this instead. */
             a.time_free(stm.drain_timer);
             stm.drain_timer = ptr::null_mut();
             stm.context.mainloop.signal();
         }
 
         if let Some(ref stm) = self.output_stream {
-
             let frame_size = self.output_sample_spec.frame_size();
             debug_assert_eq!(nbytes % frame_size, 0);
 
             let mut towrite = nbytes;
             let mut read_offset = 0usize;
             while towrite > 0 {
                 match stm.begin_write(towrite) {
                     Err(e) => {
                         panic!("Failed to write data: {}", e);
-                    },
+                    }
                     Ok((buffer, size)) => {
                         debug_assert!(size > 0);
                         debug_assert_eq!(size % frame_size, 0);
 
-                        logv!("Trigger user callback with output buffer size={}, read_offset={}",
-                              size,
-                              read_offset);
-                        let read_ptr = unsafe { (input_data as *const u8).offset(read_offset as isize) };
+                        cubeb_logv!(
+                            "Trigger user callback with output buffer size={}, read_offset={}",
+                            size,
+                            read_offset
+                        );
+                        let read_ptr =
+                            unsafe { (input_data as *const u8).offset(read_offset as isize) };
                         let got = unsafe {
-                            self.data_callback.unwrap()(self as *const _ as *mut _,
-                                                        self.user_ptr,
-                                                        read_ptr as *const _ as *mut _,
-                                                        buffer,
-                                                        (size / frame_size) as c_long)
+                            self.data_callback.unwrap()(
+                                self as *const _ as *mut _,
+                                self.user_ptr,
+                                read_ptr as *const _ as *mut _,
+                                buffer,
+                                (size / frame_size) as c_long,
+                            )
                         };
                         if got < 0 {
                             let _ = stm.cancel_write();
                             self.shutdown = true;
                             return;
                         }
 
                         // If more iterations move offset of read buffer
                         if !input_data.is_null() {
                             let in_frame_size = self.input_sample_spec.frame_size();
                             read_offset += (size / frame_size) * in_frame_size;
                         }
 
                         if self.volume != PULSE_NO_GAIN {
-                            let samples = (self.output_sample_spec.channels as usize * size / frame_size) as isize;
+                            let samples = (self.output_sample_spec.channels as usize * size
+                                / frame_size) as isize;
 
-                            if self.output_sample_spec.format == PA_SAMPLE_S16BE ||
-                               self.output_sample_spec.format == PA_SAMPLE_S16LE {
+                            if self.output_sample_spec.format == PA_SAMPLE_S16BE
+                                || self.output_sample_spec.format == PA_SAMPLE_S16LE
+                            {
                                 let b = buffer as *mut i16;
                                 for i in 0..samples {
                                     unsafe { *b.offset(i) *= self.volume as i16 };
                                 }
                             } else {
                                 let b = buffer as *mut f32;
                                 for i in 0..samples {
                                     unsafe { *b.offset(i) *= self.volume };
                                 }
                             }
                         }
 
-                        let r = stm.write(buffer,
-                                          got as usize * frame_size,
-                                          0,
-                                          pulse::SeekMode::Relative);
+                        let r = stm.write(
+                            buffer,
+                            got as usize * frame_size,
+                            0,
+                            pulse::SeekMode::Relative,
+                        );
                         debug_assert!(r.is_ok());
 
                         if (got as usize) < size / frame_size {
                             let latency = match stm.get_latency() {
                                 Ok(StreamLatency::Positive(l)) => l,
                                 Ok(_) => {
                                     panic!("Can not handle negative latency values.");
-                                },
+                                }
                                 Err(e) => {
-                                    debug_assert_eq!(e, pulse::ErrorCode::from_error_code(PA_ERR_NODATA));
+                                    debug_assert_eq!(
+                                        e,
+                                        pulse::ErrorCode::from_error_code(PA_ERR_NODATA)
+                                    );
                                     /* this needs a better guess. */
                                     100 * PA_USEC_PER_MSEC
-                                },
+                                }
                             };
 
                             /* pa_stream_drain is useless, see PA bug# 866. this is a workaround. */
                             /* arbitrary safety margin: double the current latency. */
                             debug_assert!(self.drain_timer.is_null());
                             let stream_ptr = self as *const _ as *mut _;
                             if let Some(ref context) = self.context.context {
-                                self.drain_timer =
-                                    context.rttime_new(pulse::rtclock_now() + 2 * latency, drained_cb, stream_ptr);
+                                self.drain_timer = context.rttime_new(
+                                    pulse::rtclock_now() + 2 * latency,
+                                    drained_cb,
+                                    stream_ptr,
+                                );
                             }
                             self.shutdown = true;
                             return;
                         }
 
                         towrite -= size;
-                    },
+                    }
                 }
             }
             debug_assert_eq!(towrite, 0);
         }
     }
 }
 
 fn stream_success(_: &pulse::Stream, success: i32, u: *mut c_void) {
-    let stm = unsafe { &*(u as *mut Stream) };
+    let stm = unsafe { &*(u as *mut PulseStream) };
     debug_assert_ne!(success, 0);
     stm.context.mainloop.signal();
 }
 
 fn context_success(_: &pulse::Context, success: i32, u: *mut c_void) {
-    let ctx = unsafe { &*(u as *mut Context) };
+    let ctx = unsafe { &*(u as *mut PulseContext) };
     debug_assert_ne!(success, 0);
     ctx.mainloop.signal();
 }
 
 fn set_buffering_attribute(latency_frames: u32, sample_spec: &pa_sample_spec) -> pa_buffer_attr {
     let tlength = latency_frames * sample_spec.frame_size() as u32;
     let minreq = tlength / 4;
     let battr = pa_buffer_attr {
         maxlength: u32::max_value(),
         prebuf: u32::max_value(),
         tlength: tlength,
         minreq: minreq,
         fragsize: minreq,
     };
 
-    log!("Requested buffer attributes maxlength {}, tlength {}, prebuf {}, minreq {}, fragsize {}",
-         battr.maxlength,
-         battr.tlength,
-         battr.prebuf,
-         battr.minreq,
-         battr.fragsize);
+    cubeb_log!(
+        "Requested buffer attributes maxlength {}, tlength {}, prebuf {}, minreq {}, fragsize {}",
+        battr.maxlength,
+        battr.tlength,
+        battr.prebuf,
+        battr.minreq,
+        battr.fragsize
+    );
 
     battr
 }
+
+fn invalid_format() -> Error {
+    unsafe { Error::from_raw(ffi::CUBEB_ERROR_INVALID_FORMAT) }
+}
+
+fn not_supported() -> Error {
+    unsafe { Error::from_raw(ffi::CUBEB_ERROR_NOT_SUPPORTED) }
+}
--- a/media/libcubeb/cubeb-pulse-rs/src/capi.rs
+++ b/media/libcubeb/cubeb-pulse-rs/src/capi.rs
@@ -1,249 +1,17 @@
-// Copyright © 2017 Mozilla Foundation
+// Copyright © 2017-2018 Mozilla Foundation
 //
 // This program is made available under an ISC-style license.  See the
 // accompanying file LICENSE for details.
 
-use backend;
-use cubeb;
-use std::ffi::CStr;
-use std::os::raw::{c_char, c_void};
-
-unsafe extern "C" fn capi_init(c: *mut *mut cubeb::Context, context_name: *const c_char) -> i32 {
-    match backend::Context::new(context_name) {
-        Ok(ctx) => {
-            *c = Box::into_raw(ctx) as *mut _;
-            cubeb::OK
-        },
-        Err(e) => e,
-    }
-}
-
-extern "C" fn capi_get_backend_id(_: *mut cubeb::Context) -> *const c_char {
-    "pulse-rust\0".as_ptr() as *const c_char
-}
-
-unsafe extern "C" fn capi_get_max_channel_count(c: *mut cubeb::Context, max_channels: *mut u32) -> i32 {
-    let ctx = &*(c as *mut backend::Context);
-
-    match ctx.max_channel_count() {
-        Ok(mc) => {
-            *max_channels = mc;
-            cubeb::OK
-        },
-        Err(e) => e,
-    }
-}
-
-unsafe extern "C" fn capi_get_min_latency(c: *mut cubeb::Context,
-                                          param: cubeb::StreamParams,
-                                          latency_frames: *mut u32)
-                                          -> i32 {
-    let ctx = &*(c as *mut backend::Context);
-
-    match ctx.min_latency(&param) {
-        Ok(l) => {
-            *latency_frames = l;
-            cubeb::OK
-        },
-        Err(e) => e,
-    }
-}
-
-unsafe extern "C" fn capi_get_preferred_sample_rate(c: *mut cubeb::Context, rate: *mut u32) -> i32 {
-    let ctx = &*(c as *mut backend::Context);
-
-    match ctx.preferred_sample_rate() {
-        Ok(r) => {
-            *rate = r;
-            cubeb::OK
-        },
-        Err(e) => e,
-    }
-}
-
-unsafe extern "C" fn capi_get_preferred_channel_layout(c: *mut cubeb::Context,
-                                                       layout: *mut cubeb::ChannelLayout)
-                                                       -> i32 {
-    let ctx = &*(c as *mut backend::Context);
-
-    match ctx.preferred_channel_layout() {
-        Ok(l) => {
-            *layout = l;
-            cubeb::OK
-        },
-        Err(e) => e,
-    }
-}
-
-unsafe extern "C" fn capi_enumerate_devices(c: *mut cubeb::Context,
-                                            devtype: cubeb::DeviceType,
-                                            collection: *mut cubeb::DeviceCollection)
-                                            -> i32 {
-    let ctx = &*(c as *mut backend::Context);
-
-    match ctx.enumerate_devices(devtype) {
-        Ok(dc) => {
-            *collection = dc;
-            cubeb::OK
-        },
-        Err(e) => e,
-    }
-}
-
-unsafe extern "C" fn capi_device_collection_destroy(c: *mut cubeb::Context,
-                                                    collection: *mut cubeb::DeviceCollection)
-                                                    -> i32 {
-    let ctx = &*(c as *mut backend::Context);
-
-    ctx.device_collection_destroy(collection);
-    cubeb::OK
-}
-
-unsafe extern "C" fn capi_destroy(c: *mut cubeb::Context) {
-    let _: Box<backend::Context> = Box::from_raw(c as *mut _);
-}
-
-unsafe extern "C" fn capi_stream_init(c: *mut cubeb::Context,
-                                      s: *mut *mut cubeb::Stream,
-                                      stream_name: *const c_char,
-                                      input_device: cubeb::DeviceId,
-                                      input_stream_params: *mut cubeb::StreamParams,
-                                      output_device: cubeb::DeviceId,
-                                      output_stream_params: *mut cubeb::StreamParams,
-                                      latency_frames: u32,
-                                      data_callback: cubeb::DataCallback,
-                                      state_callback: cubeb::StateCallback,
-                                      user_ptr: *mut c_void)
-                                      -> i32 {
-    fn try_stream_params_from(sp: *mut cubeb::StreamParams) -> Option<cubeb::StreamParams> {
-        if sp.is_null() { None } else { Some(unsafe { *sp }) }
-    }
-
-    let ctx = &mut *(c as *mut backend::Context);
-    let stream_name = CStr::from_ptr(stream_name);
+use backend::PulseContext;
+use cubeb_backend::{capi, ffi};
+use std::os::raw::{c_char, c_int};
 
-    match ctx.new_stream(stream_name,
-                         input_device,
-                         try_stream_params_from(input_stream_params),
-                         output_device,
-                         try_stream_params_from(output_stream_params),
-                         latency_frames,
-                         data_callback,
-                         state_callback,
-                         user_ptr as _) {
-        Ok(stm) => {
-            *s = Box::into_raw(stm) as *mut _;
-            cubeb::OK
-        },
-        Err(e) => e,
-    }
-}
-
-unsafe extern "C" fn capi_stream_destroy(s: *mut cubeb::Stream) {
-    let _ = Box::from_raw(s as *mut backend::Stream);
-}
-
-unsafe extern "C" fn capi_stream_start(s: *mut cubeb::Stream) -> i32 {
-    let stm = &mut *(s as *mut backend::Stream);
-
-    stm.start()
-}
-
-unsafe extern "C" fn capi_stream_stop(s: *mut cubeb::Stream) -> i32 {
-    let stm = &mut *(s as *mut backend::Stream);
-
-    stm.stop()
-}
-
-unsafe extern "C" fn capi_stream_get_position(s: *mut cubeb::Stream, position: *mut u64) -> i32 {
-    let stm = &*(s as *mut backend::Stream);
-
-    match stm.position() {
-        Ok(pos) => {
-            *position = pos;
-            cubeb::OK
-        },
-        Err(e) => e,
-    }
-}
-
-unsafe extern "C" fn capi_stream_get_latency(s: *mut cubeb::Stream, latency: *mut u32) -> i32 {
-    let stm = &*(s as *mut backend::Stream);
-
-    match stm.latency() {
-        Ok(lat) => {
-            *latency = lat;
-            cubeb::OK
-        },
-        Err(e) => e,
-    }
-}
-
-unsafe extern "C" fn capi_stream_set_volume(s: *mut cubeb::Stream, volume: f32) -> i32 {
-    let stm = &mut *(s as *mut backend::Stream);
-
-    stm.set_volume(volume)
+/// Entry point from C code.
+#[no_mangle]
+pub unsafe extern "C" fn pulse_rust_init(
+    c: *mut *mut ffi::cubeb,
+    context_name: *const c_char,
+) -> c_int {
+    capi::capi_init::<PulseContext>(c, context_name)
 }
-
-unsafe extern "C" fn capi_stream_set_panning(s: *mut cubeb::Stream, panning: f32) -> i32 {
-    let stm = &mut *(s as *mut backend::Stream);
-
-    stm.set_panning(panning)
-}
-
-unsafe extern "C" fn capi_stream_get_current_device(s: *mut cubeb::Stream, device: *mut *const cubeb::Device) -> i32 {
-    let stm = &*(s as *mut backend::Stream);
-
-    match stm.current_device() {
-        Ok(d) => {
-            *device = Box::into_raw(d) as *mut _;
-            cubeb::OK
-        },
-        Err(e) => e,
-    }
-}
-
-unsafe extern "C" fn capi_stream_device_destroy(_: *mut cubeb::Stream, device: *mut cubeb::Device) -> i32 {
-    let _: Box<backend::Device> = Box::from_raw(device as *mut backend::Device);
-    cubeb::OK
-}
-
-unsafe extern "C" fn capi_register_device_collection_changed(c: *mut cubeb::Context,
-                                                             devtype: cubeb::DeviceType,
-                                                             collection_changed_callback:
-                                                             cubeb::DeviceCollectionChangedCallback,
-                                                      user_ptr: *mut c_void) -> i32
-{
-    let ctx = &mut *(c as *mut backend::Context);
-    ctx.register_device_collection_changed(devtype, collection_changed_callback, user_ptr as _)
-}
-
-pub const PULSE_OPS: cubeb::Ops = cubeb::Ops {
-    init: Some(capi_init),
-    get_backend_id: Some(capi_get_backend_id),
-    get_max_channel_count: Some(capi_get_max_channel_count),
-    get_min_latency: Some(capi_get_min_latency),
-    get_preferred_sample_rate: Some(capi_get_preferred_sample_rate),
-    get_preferred_channel_layout: Some(capi_get_preferred_channel_layout),
-    enumerate_devices: Some(capi_enumerate_devices),
-    device_collection_destroy: Some(capi_device_collection_destroy),
-    destroy: Some(capi_destroy),
-    stream_init: Some(capi_stream_init),
-    stream_destroy: Some(capi_stream_destroy),
-    stream_start: Some(capi_stream_start),
-    stream_stop: Some(capi_stream_stop),
-    stream_reset_default_device: None,
-    stream_get_position: Some(capi_stream_get_position),
-    stream_get_latency: Some(capi_stream_get_latency),
-    stream_set_volume: Some(capi_stream_set_volume),
-    stream_set_panning: Some(capi_stream_set_panning),
-    stream_get_current_device: Some(capi_stream_get_current_device),
-    stream_device_destroy: Some(capi_stream_device_destroy),
-    stream_register_device_changed_callback: None,
-    register_device_collection_changed: Some(capi_register_device_collection_changed),
-};
-
-#[no_mangle]
-pub unsafe extern "C" fn pulse_rust_init(c: *mut *mut cubeb::Context, context_name: *const c_char) -> i32 {
-    capi_init(c, context_name)
-}
--- a/media/libcubeb/cubeb-pulse-rs/src/lib.rs
+++ b/media/libcubeb/cubeb-pulse-rs/src/lib.rs
@@ -1,17 +1,17 @@
 //! Cubeb backend interface to Pulse Audio
 
-// Copyright © 2017 Mozilla Foundation
+// Copyright © 2017-2018 Mozilla Foundation
 //
 // This program is made available under an ISC-style license.  See the
 // accompanying file LICENSE for details.
 
 #[macro_use]
-extern crate cubeb_ffi as cubeb;
+extern crate cubeb_backend;
+extern crate pulse;
 extern crate pulse_ffi;
-extern crate pulse;
 extern crate semver;
 
 mod capi;
 mod backend;
 
 pub use capi::pulse_rust_init;