Module libpulse_binding::mainloop::standard[][src]

Standard/minimal main loop implementation based on poll().

Overview

This 'standard' (minimal) main loop implementation is based on the poll() system call. It supports the functions defined in the main loop abstraction (::mainloop::api) and very little else.

This implementation is thread safe as long as you access the main loop object from a single thread only.

Usage

A Mainloop is created using Mainloop::new. To get access to the main loop abstraction, Mainloop::get_api is used.

Destruction of the Mainloop object is done automatically when the object falls out of scope. (Rust's Drop trait has been implemented and takes care of it).

Iteration

The main loop is designed around the concept of iterations. Each iteration consists of three steps that repeat during the application's entire lifetime:

  • Prepare - Build a list of file descriptors that need to be monitored and calculate the next timeout.
  • Poll - Execute the actual poll() system call.
  • Dispatch - Dispatch any events that have fired.

When using the main loop, the application can either execute each iteration, one at a time, using Mainloop::iterate, or let the library iterate automatically using Mainloop::run.

Threads

The main loop functions are designed to be thread safe, but the objects are not. What this means is that multiple main loops can be used, but only one object per thread.

Example

An example program using the standard mainloop:

extern crate libpulse_binding as pulse;

use std::sync::atomic;
use std::rc::Rc;
use std::cell::RefCell;
use std::ops::Deref;
use pulse::mainloop::standard::Mainloop;
use pulse::context::Context;
use pulse::stream::Stream;
use pulse::proplist::Proplist;
use pulse::mainloop::standard::IterateResult;
use pulse::def::Retval;

fn main() {
    let spec = pulse::sample::Spec {
        format: pulse::sample::SAMPLE_S16NE,
        channels: 2,
        rate: 44100,
    };
    assert!(spec.is_valid());

    let mut proplist = Proplist::new().unwrap();
    proplist.sets(pulse::proplist::properties::APPLICATION_NAME, "FooApp")
        .unwrap();

    let mut mainloop = Rc::new(RefCell::new(Mainloop::new()
        .expect("Failed to create mainloop")));

    let mut context = Rc::new(RefCell::new(Context::new_with_proplist(
        mainloop.borrow().deref(),
        "FooAppContext",
        &proplist
        ).expect("Failed to create new context")));

    context.borrow_mut().connect(None, pulse::context::flags::NOFLAGS, None)
        .expect("Failed to connect context");

    // Wait for context to be ready
    loop {
        match mainloop.borrow_mut().iterate(false) {
            IterateResult::Quit(_) |
            IterateResult::Err(_) => {
                eprintln!("iterate state was not success, quitting...");
                return;
            },
            IterateResult::Success(_) => {},
        }
        match context.borrow().get_state() {
            pulse::context::State::Ready => { break; },
            pulse::context::State::Failed |
            pulse::context::State::Terminated => {
                eprintln!("context state failed/terminated, quitting...");
                return;
            },
            _ => {},
        }
    }

    let mut stream = Rc::new(RefCell::new(Stream::new(
        &mut context.borrow_mut(),
        "Music",
        &spec,
        None
        ).expect("Failed to create new stream")));

    stream.borrow_mut().connect_playback(None, None, pulse::stream::flags::START_CORKED,
        None, None).expect("Failed to connect playback");

    // Wait for stream to be ready
    loop {
        match mainloop.borrow_mut().iterate(false) {
            IterateResult::Quit(_) |
            IterateResult::Err(_) => {
                eprintln!("iterate state was not success, quitting...");
                return;
            },
            IterateResult::Success(_) => {},
        }
        match stream.borrow().get_state() {
            pulse::stream::State::Ready => { break; },
            pulse::stream::State::Failed |
            pulse::stream::State::Terminated => {
                eprintln!("stream state failed/terminated, quitting...");
                return;
            },
            _ => {},
        }
    }

    // Our main loop
    let drained = Rc::new(atomic::AtomicBool::new(false));
    loop {
        match mainloop.borrow_mut().iterate(false) {
            IterateResult::Quit(_) |
            IterateResult::Err(_) => {
                eprintln!("iterate state was not success, quitting...");
                return;
            },
            IterateResult::Success(_) => {},
        }

        // Write some data with stream.write()

        if stream.borrow().is_corked().unwrap() {
            stream.borrow_mut().uncork(None);
        }

        // Wait for our data to be played
        let _o = {
            let drain_state_ref = Rc::clone(&drained);
            stream.borrow_mut().drain(Some(Box::new(move |_success: bool| {
                drain_state_ref.store(true, atomic::Ordering::Relaxed);
            })))
        };
        while !drained.compare_and_swap(true, false, atomic::Ordering::Relaxed) {
            match mainloop.borrow_mut().iterate(false) {
                IterateResult::Quit(_) |
                IterateResult::Err(_) => {
                    eprintln!("iterate state was not success, quitting...");
                    return;
                },
                IterateResult::Success(_) => {},
            }
        }

        // Remember to break out of the loop once done writing all data (or whatever).
    }

    // Clean shutdown
    mainloop.borrow_mut().quit(Retval(0)); // uncertain whether this is necessary
    stream.borrow_mut().disconnect().unwrap();
}

Structs

Mainloop

This acts as a safe interface to the internal PA Mainloop.

Enums

IterateResult

Return type for Mainloop::iterate.

MainloopInternal

An opaque main loop object

Type Definitions

PollFn

Generic prototype of a poll() like function