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


Quelle  context.rs   Sprache: unbekannt

 
// Copyright © 2017 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::mem::{forget, MaybeUninit};
use std::os::raw::{c_int, c_void};
use std::ptr;
use util::UnwrapCStr;
use *;

// A note about `wrapped` functions
//
// C FFI demands `unsafe extern fn(*mut pa_context, ...) -> i32`, etc,
// but we want to allow such callbacks to be safe. This means no
// `unsafe` or `extern`, and callbacks should be called with a safe
// wrapper of `*mut pa_context`. Since the callback doesn't take
// ownership, this is `&Context`. `fn wrapped<T>(...)` defines a
// function that converts from our safe signature to the unsafe
// signature.
//
// Currently, we use a property of Rust, namely that each function
// gets its own unique type.  These unique types can't be written
// directly, so we use generic and a type parameter, and let the Rust
// compiler fill in the name for us:
//
// fn get_sink_input_info<CB>(&self, ..., _: CB, ...) -> ...
//     where CB: Fn(&Context, *const SinkInputInfo, i32, *mut c_void)
//
// Because we aren't storing or passing any state, we assert, at run-time :-(,
// that our functions are zero-sized:
//
// assert!(mem::size_of::<F>() == 0);
//
// We need to obtain a value of type F in order to call it. Since we
// can't name the function, we have to unsafely construct that value
// somehow - we do this using mem::uninitialized. Then, we call that
// function with a reference to the Context, and save the result:
//
//              |       generate value        ||  call it  |
// let result = ::std::mem::uninitialized::<F>()(&mut object);
//
// Lastly, since our Object is an owned type, we need to avoid
// dropping it, then return the result we just generated.
//
//  mem::forget(object);
//  result

// Aid in returning Operation from callbacks
macro_rules! op_or_err {
    ($self_:ident, $e:expr) => {{
        let o = unsafe { $e };
        if o.is_null() {
            Err(ErrorCode::from_error_code($self_.errno()))
        } else {
            Ok(unsafe { operation::from_raw_ptr(o) })
        }
    }};
}

#[repr(C)]
#[derive(Debug)]
pub struct Context(*mut ffi::pa_context);

impl Context {
    pub fn new<'a, OPT>(api: &MainloopApi, name: OPT) -> Option<Self>
    where
        OPT: Into<Option<&'a CStr>>,
    {
        let ptr = unsafe { ffi::pa_context_new(api.raw_mut(), name.unwrap_cstr()) };
        if ptr.is_null() {
            None
        } else {
            Some(Context(ptr))
        }
    }

    #[doc(hidden)]
    pub fn raw_mut(&self) -> &mut ffi::pa_context {
        unsafe { &mut *self.0 }
    }

    pub fn unref(self) {
        unsafe {
            ffi::pa_context_unref(self.raw_mut());
        }
    }

    pub fn clear_state_callback(&self) {
        unsafe {
            ffi::pa_context_set_state_callback(self.raw_mut(), None, ptr::null_mut());
        }
    }

    pub fn set_state_callback<CB>(&self, _: CB, userdata: *mut c_void)
    where
        CB: Fn(&Context, *mut c_void),
    {
        assert_eq!(::std::mem::size_of::<CB>(), 0);

        // See: A note about `wrapped` functions
        unsafe extern "C" fn wrapped<F>(c: *mut ffi::pa_context, userdata: *mut c_void)
        where
            F: Fn(&Context, *mut c_void),
        {
            let ctx = context::from_raw_ptr(c);
            let cb = MaybeUninit::<F>::uninit();
            let result = (*cb.as_ptr())(&ctx, userdata);
            forget(ctx);

            result
        }

        unsafe {
            ffi::pa_context_set_state_callback(self.raw_mut(), Some(wrapped::<CB>), userdata);
        }
    }

    pub fn errno(&self) -> ffi::pa_error_code_t {
        unsafe { ffi::pa_context_errno(self.raw_mut()) }
    }

    pub fn get_state(&self) -> ContextState {
        ContextState::try_from(unsafe { ffi::pa_context_get_state(self.raw_mut()) })
            .expect("pa_context_get_state returned invalid ContextState")
    }

    pub fn connect<'a, OPT>(
        &self,
        server: OPT,
        flags: ContextFlags,
        api: *const ffi::pa_spawn_api,
    ) -> Result<()>
    where
        OPT: Into<Option<&'a CStr>>,
    {
        let r = unsafe {
            ffi::pa_context_connect(
                self.raw_mut(),
                server.into().unwrap_cstr(),
                flags.into(),
                api,
            )
        };
        error_result!((), r)
    }

    pub fn disconnect(&self) {
        unsafe {
            ffi::pa_context_disconnect(self.raw_mut());
        }
    }

    pub fn drain<CB>(&self, _: CB, userdata: *mut c_void) -> Result<Operation>
    where
        CB: Fn(&Context, *mut c_void),
    {
        assert_eq!(::std::mem::size_of::<CB>(), 0);

        // See: A note about `wrapped` functions
        unsafe extern "C" fn wrapped<F>(c: *mut ffi::pa_context, userdata: *mut c_void)
        where
            F: Fn(&Context, *mut c_void),
        {
            let ctx = context::from_raw_ptr(c);
            let cb = MaybeUninit::<F>::uninit();
            let result = (*cb.as_ptr())(&ctx, userdata);
            forget(ctx);

            result
        }

        op_or_err!(
            self,
            ffi::pa_context_drain(self.raw_mut(), Some(wrapped::<CB>), userdata)
        )
    }

    pub fn rttime_new<CB>(
        &self,
        usec: USec,
        _: CB,
        userdata: *mut c_void,
    ) -> *mut ffi::pa_time_event
    where
        CB: Fn(&MainloopApi, *mut ffi::pa_time_event, &TimeVal, *mut c_void),
    {
        assert_eq!(::std::mem::size_of::<CB>(), 0);

        // See: A note about `wrapped` functions
        unsafe extern "C" fn wrapped<F>(
            a: *mut ffi::pa_mainloop_api,
            e: *mut ffi::pa_time_event,
            tv: *const TimeVal,
            userdata: *mut c_void,
        ) where
            F: Fn(&MainloopApi, *mut ffi::pa_time_event, &TimeVal, *mut c_void),
        {
            let api = mainloop_api::from_raw_ptr(a);
            let timeval = &*tv;
            let cb = MaybeUninit::<F>::uninit();
            let result = (*cb.as_ptr())(&api, e, timeval, userdata);
            forget(api);

            result
        }

        unsafe { ffi::pa_context_rttime_new(self.raw_mut(), usec, Some(wrapped::<CB>), userdata) }
    }

    pub fn get_server_info<CB>(&self, _: CB, userdata: *mut c_void) -> Result<Operation>
    where
        CB: Fn(&Context, Option<&ServerInfo>, *mut c_void),
    {
        assert_eq!(::std::mem::size_of::<CB>(), 0);

        // See: A note about `wrapped` functions
        unsafe extern "C" fn wrapped<F>(
            c: *mut ffi::pa_context,
            i: *const ffi::pa_server_info,
            userdata: *mut c_void,
        ) where
            F: Fn(&Context, Option<&ServerInfo>, *mut c_void),
        {
            let info = if i.is_null() { None } else { Some(&*i) };
            let ctx = context::from_raw_ptr(c);
            let cb = MaybeUninit::<F>::uninit();
            let result = (*cb.as_ptr())(&ctx, info, userdata);
            forget(ctx);

            result
        }

        op_or_err!(
            self,
            ffi::pa_context_get_server_info(self.raw_mut(), Some(wrapped::<CB>), userdata)
        )
    }

    pub fn get_sink_info_by_name<'str, CS, CB>(
        &self,
        name: CS,
        _: CB,
        userdata: *mut c_void,
    ) -> Result<Operation>
    where
        CB: Fn(&Context, *const SinkInfo, i32, *mut c_void),
        CS: Into<Option<&'str CStr>>,
    {
        assert_eq!(::std::mem::size_of::<CB>(), 0);

        // See: A note about `wrapped` functions
        unsafe extern "C" fn wrapped<F>(
            c: *mut ffi::pa_context,
            info: *const ffi::pa_sink_info,
            eol: c_int,
            userdata: *mut c_void,
        ) where
            F: Fn(&Context, *const SinkInfo, i32, *mut c_void),
        {
            let ctx = context::from_raw_ptr(c);
            let cb = MaybeUninit::<F>::uninit();
            let result = (*cb.as_ptr())(&ctx, info, eol, userdata);
            forget(ctx);

            result
        }

        op_or_err!(
            self,
            ffi::pa_context_get_sink_info_by_name(
                self.raw_mut(),
                name.into().unwrap_cstr(),
                Some(wrapped::<CB>),
                userdata
            )
        )
    }

    pub fn get_sink_info_list<CB>(&self, _: CB, userdata: *mut c_void) -> Result<Operation>
    where
        CB: Fn(&Context, *const SinkInfo, i32, *mut c_void),
    {
        assert_eq!(::std::mem::size_of::<CB>(), 0);

        // See: A note about `wrapped` functions
        unsafe extern "C" fn wrapped<F>(
            c: *mut ffi::pa_context,
            info: *const ffi::pa_sink_info,
            eol: c_int,
            userdata: *mut c_void,
        ) where
            F: Fn(&Context, *const SinkInfo, i32, *mut c_void),
        {
            let ctx = context::from_raw_ptr(c);
            let cb = MaybeUninit::<F>::uninit();
            let result = (*cb.as_ptr())(&ctx, info, eol, userdata);
            forget(ctx);

            result
        }

        op_or_err!(
            self,
            ffi::pa_context_get_sink_info_list(self.raw_mut(), Some(wrapped::<CB>), userdata)
        )
    }

    pub fn get_sink_input_info<CB>(
        &self,
        idx: u32,
        _: CB,
        userdata: *mut c_void,
    ) -> Result<Operation>
    where
        CB: Fn(&Context, *const SinkInputInfo, i32, *mut c_void),
    {
        assert_eq!(::std::mem::size_of::<CB>(), 0);

        // See: A note about `wrapped` functions
        unsafe extern "C" fn wrapped<F>(
            c: *mut ffi::pa_context,
            info: *const ffi::pa_sink_input_info,
            eol: c_int,
            userdata: *mut c_void,
        ) where
            F: Fn(&Context, *const SinkInputInfo, i32, *mut c_void),
        {
            let ctx = context::from_raw_ptr(c);
            let cb = MaybeUninit::<F>::uninit();
            let result = (*cb.as_ptr())(&ctx, info, eol, userdata);
            forget(ctx);

            result
        }

        op_or_err!(
            self,
            ffi::pa_context_get_sink_input_info(self.raw_mut(), idx, Some(wrapped::<CB>), userdata)
        )
    }

    pub fn get_source_info_list<CB>(&self, _: CB, userdata: *mut c_void) -> Result<Operation>
    where
        CB: Fn(&Context, *const SourceInfo, i32, *mut c_void),
    {
        assert_eq!(::std::mem::size_of::<CB>(), 0);

        // See: A note about `wrapped` functions
        unsafe extern "C" fn wrapped<F>(
            c: *mut ffi::pa_context,
            info: *const ffi::pa_source_info,
            eol: c_int,
            userdata: *mut c_void,
        ) where
            F: Fn(&Context, *const SourceInfo, i32, *mut c_void),
        {
            let ctx = context::from_raw_ptr(c);
            let cb = MaybeUninit::<F>::uninit();
            let result = (*cb.as_ptr())(&ctx, info, eol, userdata);
            forget(ctx);

            result
        }

        op_or_err!(
            self,
            ffi::pa_context_get_source_info_list(self.raw_mut(), Some(wrapped::<CB>), userdata)
        )
    }

    pub fn set_sink_input_volume<CB>(
        &self,
        idx: u32,
        volume: &CVolume,
        _: CB,
        userdata: *mut c_void,
    ) -> Result<Operation>
    where
        CB: Fn(&Context, i32, *mut c_void),
    {
        assert_eq!(::std::mem::size_of::<CB>(), 0);

        // See: A note about `wrapped` functions
        unsafe extern "C" fn wrapped<F>(
            c: *mut ffi::pa_context,
            success: c_int,
            userdata: *mut c_void,
        ) where
            F: Fn(&Context, i32, *mut c_void),
        {
            let ctx = context::from_raw_ptr(c);
            let cb = MaybeUninit::<F>::uninit();
            let result = (*cb.as_ptr())(&ctx, success, userdata);
            forget(ctx);

            result
        }

        op_or_err!(
            self,
            ffi::pa_context_set_sink_input_volume(
                self.raw_mut(),
                idx,
                volume,
                Some(wrapped::<CB>),
                userdata
            )
        )
    }

    pub fn subscribe<CB>(
        &self,
        m: SubscriptionMask,
        _: CB,
        userdata: *mut c_void,
    ) -> Result<Operation>
    where
        CB: Fn(&Context, i32, *mut c_void),
    {
        assert_eq!(::std::mem::size_of::<CB>(), 0);

        // See: A note about `wrapped` functions
        unsafe extern "C" fn wrapped<F>(
            c: *mut ffi::pa_context,
            success: c_int,
            userdata: *mut c_void,
        ) where
            F: Fn(&Context, i32, *mut c_void),
        {
            let ctx = context::from_raw_ptr(c);
            let cb = MaybeUninit::<F>::uninit();
            let result = (*cb.as_ptr())(&ctx, success, userdata);
            forget(ctx);

            result
        }

        op_or_err!(
            self,
            ffi::pa_context_subscribe(self.raw_mut(), m.into(), Some(wrapped::<CB>), userdata)
        )
    }

    pub fn clear_subscribe_callback(&self) {
        unsafe {
            ffi::pa_context_set_subscribe_callback(self.raw_mut(), None, ptr::null_mut());
        }
    }

    pub fn set_subscribe_callback<CB>(&self, _: CB, userdata: *mut c_void)
    where
        CB: Fn(&Context, SubscriptionEvent, u32, *mut c_void),
    {
        assert_eq!(::std::mem::size_of::<CB>(), 0);

        // See: A note about `wrapped` functions
        unsafe extern "C" fn wrapped<F>(
            c: *mut ffi::pa_context,
            t: ffi::pa_subscription_event_type_t,
            idx: u32,
            userdata: *mut c_void,
        ) where
            F: Fn(&Context, SubscriptionEvent, u32, *mut c_void),
        {
            let ctx = context::from_raw_ptr(c);
            let event = SubscriptionEvent::try_from(t)
                .expect("pa_context_subscribe_cb_t passed invalid pa_subscription_event_type_t");
            let cb = MaybeUninit::<F>::uninit();
            let result = (*cb.as_ptr())(&ctx, event, idx, userdata);
            forget(ctx);

            result
        }

        unsafe {
            ffi::pa_context_set_subscribe_callback(self.raw_mut(), Some(wrapped::<CB>), userdata);
        }
    }
}

#[doc(hidden)]
pub unsafe fn from_raw_ptr(ptr: *mut ffi::pa_context) -> Context {
    Context(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