#[macro_use] extern crate gstreamer as gst; use gst::prelude::*; extern crate gstreamer_app as gst_app; extern crate gstreamer_audio as gst_audio; extern crate glib; extern crate byte_slice_cast; use byte_slice_cast::*; use std::error::Error as StdError; use std::i16; use std::i32; extern crate failure; use failure::Error; #[macro_use] extern crate failure_derive; #[path = "../examples-common.rs"] mod examples_common; #[derive(Debug, Fail)] #[fail(display = "Missing element {}", _0)] struct MissingElement(&'static str); #[derive(Debug, Fail)] #[fail(display = "Received error from {}: {} (debug: {:?})", src, error, debug)] struct ErrorMessage { src: String, error: String, debug: Option, #[cause] cause: glib::Error, } fn create_pipeline() -> Result { gst::init()?; let pipeline = gst::Pipeline::new(None); let src = gst::ElementFactory::make("audiotestsrc", None).ok_or(MissingElement("audiotestsrc"))?; let sink = gst::ElementFactory::make("appsink", None).ok_or(MissingElement("appsink"))?; pipeline.add_many(&[&src, &sink])?; src.link(&sink)?; let appsink = sink.clone() .dynamic_cast::() .expect("Sink element is expected to be an appsink!"); appsink.set_caps(&gst::Caps::new_simple( "audio/x-raw", &[ ("format", &gst_audio::AUDIO_FORMAT_S16.to_string()), ("layout", &"interleaved"), ("channels", &(1i32)), ("rate", &gst::IntRange::::new(1, i32::MAX)), ], )); appsink.set_callbacks( gst_app::AppSinkCallbacks::new() .new_sample(|appsink| { let sample = match appsink.pull_sample() { None => return gst::FlowReturn::Eos, Some(sample) => sample, }; let buffer = if let Some(buffer) = sample.get_buffer() { buffer } else { gst_element_error!( appsink, gst::ResourceError::Failed, ("Failed to get buffer from appsink") ); return gst::FlowReturn::Error; }; let map = if let Some(map) = buffer.map_readable() { map } else { gst_element_error!( appsink, gst::ResourceError::Failed, ("Failed to map buffer readable") ); return gst::FlowReturn::Error; }; let samples = if let Ok(samples) = map.as_slice_of::() { samples } else { gst_element_error!( appsink, gst::ResourceError::Failed, ("Failed to interprete buffer as S16 PCM") ); return gst::FlowReturn::Error; }; let sum: f64 = samples .iter() .map(|sample| { let f = f64::from(*sample) / f64::from(i16::MAX); f * f }) .sum(); let rms = (sum / (samples.len() as f64)).sqrt(); println!("rms: {}", rms); gst::FlowReturn::Ok }) .build(), ); Ok(pipeline) } fn main_loop(pipeline: gst::Pipeline) -> Result<(), Error> { pipeline.set_state(gst::State::Playing).into_result()?; let bus = pipeline .get_bus() .expect("Pipeline without bus. Shouldn't happen!"); while let Some(msg) = bus.timed_pop(gst::CLOCK_TIME_NONE) { use gst::MessageView; match msg.view() { MessageView::Eos(..) => break, MessageView::Error(err) => { pipeline.set_state(gst::State::Null).into_result()?; Err(ErrorMessage { src: err.get_src() .map(|s| s.get_path_string()) .unwrap_or_else(|| String::from("None")), error: err.get_error().description().into(), debug: err.get_debug(), cause: err.get_error(), })?; } _ => (), } } pipeline.set_state(gst::State::Null).into_result()?; Ok(()) } fn example_main() { match create_pipeline().and_then(main_loop) { Ok(r) => r, Err(e) => eprintln!("Error! {}", e), } } fn main() { // tutorials_common::run is only required to set up the application environent on macOS // (but not necessary in normal Cocoa applications where this is set up autmatically) examples_common::run(example_main); }