Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  stream.rs   Sprache: unbekannt

 
// Copyright © 2017-2018 Mozilla Foundation
//
// This program is made available under an ISC-style license.  See the
// accompanying file LICENSE for details.

use ffi;
use std::ffi::CStr;
use std::os::raw::{c_int, c_void};
use std::ptr;
use {ChannelLayout, DeviceRef, Result, SampleFormat};

/// Stream states signaled via `state_callback`.
#[derive(PartialEq, Eq, Clone, Debug, Copy)]
pub enum State {
    /// Stream started.
    Started,
    /// Stream stopped.
    Stopped,
    /// Stream drained.
    Drained,
    /// Stream disabled due to error.
    Error,
}

impl From<ffi::cubeb_state> for State {
    fn from(x: ffi::cubeb_state) -> Self {
        use State::*;
        match x {
            ffi::CUBEB_STATE_STARTED => Started,
            ffi::CUBEB_STATE_STOPPED => Stopped,
            ffi::CUBEB_STATE_DRAINED => Drained,
            _ => Error,
        }
    }
}

impl From<State> for ffi::cubeb_state {
    fn from(x: State) -> Self {
        use State::*;
        match x {
            Started => ffi::CUBEB_STATE_STARTED,
            Stopped => ffi::CUBEB_STATE_STOPPED,
            Drained => ffi::CUBEB_STATE_DRAINED,
            Error => ffi::CUBEB_STATE_ERROR,
        }
    }
}

bitflags! {
    /// Miscellaneous stream preferences.
    pub struct StreamPrefs: ffi::cubeb_stream_prefs {
        const LOOPBACK = ffi::CUBEB_STREAM_PREF_LOOPBACK;
        const DISABLE_DEVICE_SWITCHING = ffi::CUBEB_STREAM_PREF_DISABLE_DEVICE_SWITCHING;
        const VOICE = ffi::CUBEB_STREAM_PREF_VOICE;
    }
}

impl StreamPrefs {
    pub const NONE: Self = Self::empty();
}

bitflags! {
    /// Input stream processing parameters.
    pub struct InputProcessingParams: ffi::cubeb_input_processing_params {
        const ECHO_CANCELLATION = ffi::CUBEB_INPUT_PROCESSING_PARAM_ECHO_CANCELLATION;
        const NOISE_SUPPRESSION = ffi::CUBEB_INPUT_PROCESSING_PARAM_NOISE_SUPPRESSION;
        const AUTOMATIC_GAIN_CONTROL = ffi::CUBEB_INPUT_PROCESSING_PARAM_AUTOMATIC_GAIN_CONTROL;
        const VOICE_ISOLATION = ffi::CUBEB_INPUT_PROCESSING_PARAM_VOICE_ISOLATION;
    }
}

impl InputProcessingParams {
    pub const NONE: Self = Self::empty();
}

ffi_type_stack! {
    /// Stream format initialization parameters.
    type CType = ffi::cubeb_stream_params;
    #[derive(Debug)]
    pub struct StreamParams;
    pub struct StreamParamsRef;
}

impl StreamParamsRef {
    fn get_ref(&self) -> &ffi::cubeb_stream_params {
        unsafe { &*self.as_ptr() }
    }

    pub fn format(&self) -> SampleFormat {
        use SampleFormat::*;
        match self.get_ref().format {
            ffi::CUBEB_SAMPLE_S16LE => S16LE,
            ffi::CUBEB_SAMPLE_S16BE => S16BE,
            ffi::CUBEB_SAMPLE_FLOAT32LE => Float32LE,
            ffi::CUBEB_SAMPLE_FLOAT32BE => Float32BE,
            x => panic!("unknown sample format: {}", x),
        }
    }

    pub fn rate(&self) -> u32 {
        self.get_ref().rate
    }
    pub fn channels(&self) -> u32 {
        self.get_ref().channels
    }

    pub fn layout(&self) -> ChannelLayout {
        ChannelLayout::from(self.get_ref().layout)
    }

    pub fn prefs(&self) -> StreamPrefs {
        StreamPrefs::from_bits_truncate(self.get_ref().prefs)
    }
}

unsafe fn wrapped_cubeb_stream_destroy(stream: *mut ffi::cubeb_stream) {
    ffi::cubeb_stream_stop(stream);
    ffi::cubeb_stream_destroy(stream);
}

ffi_type_heap! {
    type CType = ffi::cubeb_stream;
    fn drop = wrapped_cubeb_stream_destroy;
    pub struct Stream;
    pub struct StreamRef;
}

impl StreamRef {
    /// Start playback.
    pub fn start(&self) -> Result<()> {
        unsafe { call!(ffi::cubeb_stream_start(self.as_ptr())) }
    }

    /// Stop playback.
    pub fn stop(&self) -> Result<()> {
        unsafe { call!(ffi::cubeb_stream_stop(self.as_ptr())) }
    }

    /// Get the current stream playback position.
    pub fn position(&self) -> Result<u64> {
        let mut position = 0u64;
        unsafe {
            call!(ffi::cubeb_stream_get_position(self.as_ptr(), &mut position))?;
        }
        Ok(position)
    }

    /// Get the latency for this stream, in frames. This is the number
    /// of frames between the time cubeb acquires the data in the
    /// callback and the listener can hear the sound.
    pub fn latency(&self) -> Result<u32> {
        let mut latency = 0u32;
        unsafe {
            call!(ffi::cubeb_stream_get_latency(self.as_ptr(), &mut latency))?;
        }
        Ok(latency)
    }

    /// Get the input latency for this stream, in frames. This is the number of frames between the
    /// time the audio input device records the audio, and the cubeb callback delivers it.
    /// This returns an error if the stream is output-only.
    pub fn input_latency(&self) -> Result<u32> {
        let mut latency = 0u32;
        unsafe {
            call!(ffi::cubeb_stream_get_input_latency(
                self.as_ptr(),
                &mut latency
            ))?;
        }
        Ok(latency)
    }

    /// Set the volume for a stream.
    pub fn set_volume(&self, volume: f32) -> Result<()> {
        unsafe { call!(ffi::cubeb_stream_set_volume(self.as_ptr(), volume)) }
    }

    /// Change a stream's name
    pub fn set_name(&self, name: &CStr) -> Result<()> {
        unsafe { call!(ffi::cubeb_stream_set_name(self.as_ptr(), name.as_ptr())) }
    }

    /// Get the current output device for this stream.
    pub fn current_device(&self) -> Result<&DeviceRef> {
        let mut device: *mut ffi::cubeb_device = ptr::null_mut();
        unsafe {
            call!(ffi::cubeb_stream_get_current_device(
                self.as_ptr(),
                &mut device
            ))?;
            Ok(DeviceRef::from_ptr(device))
        }
    }

    /// Set the mute state for an input stream.
    pub fn set_input_mute(&self, mute: bool) -> Result<()> {
        let mute: c_int = if mute { 1 } else { 0 };
        unsafe { call!(ffi::cubeb_stream_set_input_mute(self.as_ptr(), mute)) }
    }

    /// Set the processing parameters for an input stream.
    pub fn set_input_processing_params(&self, params: InputProcessingParams) -> Result<()> {
        unsafe {
            call!(ffi::cubeb_stream_set_input_processing_params(
                self.as_ptr(),
                params.bits()
            ))
        }
    }

    /// Destroy a cubeb_device structure.
    pub fn device_destroy(&self, device: DeviceRef) -> Result<()> {
        unsafe {
            call!(ffi::cubeb_stream_device_destroy(
                self.as_ptr(),
                device.as_ptr()
            ))
        }
    }

    /// Set a callback to be notified when the output device changes.
    pub fn register_device_changed_callback(
        &self,
        callback: ffi::cubeb_device_changed_callback,
    ) -> Result<()> {
        unsafe {
            call!(ffi::cubeb_stream_register_device_changed_callback(
                self.as_ptr(),
                callback
            ))
        }
    }

    pub fn user_ptr(&self) -> *mut c_void {
        unsafe { ffi::cubeb_stream_user_ptr(self.as_ptr()) }
    }
}

#[cfg(test)]
mod tests {
    use std::mem;
    use {StreamParams, StreamParamsRef, StreamPrefs};

    #[test]
    fn stream_params_default() {
        let params = StreamParams::default();
        assert_eq!(params.channels(), 0);
    }

    #[test]
    fn stream_params_raw_channels() {
        let mut raw: super::ffi::cubeb_stream_params = unsafe { mem::zeroed() };
        raw.channels = 2;
        let params = unsafe { StreamParamsRef::from_ptr(&mut raw) };
        assert_eq!(params.channels(), 2);
    }

    #[test]
    fn stream_params_raw_format() {
        let mut raw: super::ffi::cubeb_stream_params = unsafe { mem::zeroed() };
        macro_rules! check(
            ($($raw:ident => $real:ident),*) => (
                $(raw.format = super::ffi::$raw;
                  let params = unsafe {
                      StreamParamsRef::from_ptr(&mut raw)
                  };
                  assert_eq!(params.format(), super::SampleFormat::$real);
                )*
            ) );

        check!(CUBEB_SAMPLE_S16LE => S16LE,
               CUBEB_SAMPLE_S16BE => S16BE,
               CUBEB_SAMPLE_FLOAT32LE => Float32LE,
               CUBEB_SAMPLE_FLOAT32BE => Float32BE);
    }

    #[test]
    fn stream_params_raw_format_native_endian() {
        let mut raw: super::ffi::cubeb_stream_params = unsafe { mem::zeroed() };
        raw.format = super::ffi::CUBEB_SAMPLE_S16NE;
        let params = unsafe { StreamParamsRef::from_ptr(&mut raw) };
        assert_eq!(
            params.format(),
            if cfg!(target_endian = "little") {
                super::SampleFormat::S16LE
            } else {
                super::SampleFormat::S16BE
            }
        );

        raw.format = super::ffi::CUBEB_SAMPLE_FLOAT32NE;
        let params = unsafe { StreamParamsRef::from_ptr(&mut raw) };
        assert_eq!(
            params.format(),
            if cfg!(target_endian = "little") {
                super::SampleFormat::Float32LE
            } else {
                super::SampleFormat::Float32BE
            }
        );
    }

    #[test]
    fn stream_params_raw_layout() {
        let mut raw: super::ffi::cubeb_stream_params = unsafe { mem::zeroed() };
        macro_rules! check(
            ($($raw:ident => $real:ident),*) => (
                $(raw.layout = super::ffi::$raw;
                  let params = unsafe {
                      StreamParamsRef::from_ptr(&mut raw)
                  };
                  assert_eq!(params.layout(), super::ChannelLayout::$real);
                )*
            ) );

        check!(CUBEB_LAYOUT_UNDEFINED => UNDEFINED,
               CUBEB_LAYOUT_MONO => MONO,
               CUBEB_LAYOUT_MONO_LFE => MONO_LFE,
               CUBEB_LAYOUT_STEREO => STEREO,
               CUBEB_LAYOUT_STEREO_LFE => STEREO_LFE,
               CUBEB_LAYOUT_3F => _3F,
               CUBEB_LAYOUT_3F_LFE => _3F_LFE,
               CUBEB_LAYOUT_2F1 => _2F1,
               CUBEB_LAYOUT_2F1_LFE => _2F1_LFE,
               CUBEB_LAYOUT_3F1 => _3F1,
               CUBEB_LAYOUT_3F1_LFE => _3F1_LFE,
               CUBEB_LAYOUT_2F2 => _2F2,
               CUBEB_LAYOUT_2F2_LFE => _2F2_LFE,
               CUBEB_LAYOUT_QUAD => QUAD,
               CUBEB_LAYOUT_QUAD_LFE => QUAD_LFE,
               CUBEB_LAYOUT_3F2 => _3F2,
               CUBEB_LAYOUT_3F2_LFE => _3F2_LFE,
               CUBEB_LAYOUT_3F2_BACK => _3F2_BACK,
               CUBEB_LAYOUT_3F2_LFE_BACK => _3F2_LFE_BACK,
               CUBEB_LAYOUT_3F3R_LFE => _3F3R_LFE,
               CUBEB_LAYOUT_3F4_LFE => _3F4_LFE);
    }

    #[test]
    fn stream_params_raw_rate() {
        let mut raw: super::ffi::cubeb_stream_params = unsafe { mem::zeroed() };
        raw.rate = 44_100;
        let params = unsafe { StreamParamsRef::from_ptr(&mut raw) };
        assert_eq!(params.rate(), 44_100);
    }

    #[test]
    fn stream_params_raw_prefs() {
        let mut raw: super::ffi::cubeb_stream_params = unsafe { mem::zeroed() };
        raw.prefs = super::ffi::CUBEB_STREAM_PREF_LOOPBACK;
        let params = unsafe { StreamParamsRef::from_ptr(&mut raw) };
        assert_eq!(params.prefs(), StreamPrefs::LOOPBACK);
    }

    #[test]
    fn stream_params_stream_params_ref_ptr_match() {
        let params = StreamParams::default();
        assert_eq!(params.as_ptr(), params.as_ref().as_ptr());
    }
}

[ Dauer der Verarbeitung: 0.28 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge