I want to stream a webcam (vp8 and opus) with webrtcbin from gstreamer to a janus gateway. There is an example from gstreamer playing video only which is working.
Now I struggle adding the audio part too.
This ist the pipeline I want to prepare
gst-launch-1.0 webrtcbin name=web videotestsrc is-live=true ! videoconvert ! vp8enc ! rtpvp8pay ! web.sink_%u audiotestsrc is-live=true wave=8 ! audioconvert ! audioresample ! opusenc ! rtpopuspay ! web.sink_%u
But the following failes with
Error: Pads have no common grandparent
use gst::gst_element_error;
use gst::prelude::*;
async fn run() -> Result<(), anyhow::Error> {
gst::init()?;
let pipeline = gst::Pipeline::new(Some("test"));
let webrtc_bin = gst::parse_bin_from_description("webrtcbin name=web", false)?;
pipeline.add(&webrtc_bin)?;
let video_bin = gst::parse_bin_from_description("autovideosrc ! videoconvert ! vp8enc ! rtpvp8pay", true)?;
pipeline.add(&video_bin)?;
let audio_bin = gst::parse_bin_from_description("autoaudiosrc ! audioconvert ! opusenc ! rtpopuspay", true)?;
pipeline.add(&audio_bin)?;
let webrtcbin = pipeline.get_by_name("web").expect("can't find webrtcbin");
let video_src = video_bin.get_static_pad("src").expect("Unable to get video src pad");
let video_sink = webrtcbin.get_request_pad("sink_%u").expect("Unable to request outgoing webrtcbin pad");
if let Ok(webrtc_ghost_video_src) = gst::GhostPad::with_target(Some("webrtc_video_src"), &video_src) {
video_bin.add_pad(&webrtc_ghost_video_src)?;
webrtc_ghost_video_src.link(&video_sink)?;
}
let audio_src = audio_bin.get_static_pad("src").expect("Unable to get audio src pad");
let audio_sink = webrtcbin.get_request_pad("sink_%u").expect("Unable to request outgoing webrtcbin pad");
if let Ok(webrtc_ghost_audio_src) = gst::GhostPad::with_target(Some("webrtc_audio_src"), &audio_src) {
audio_bin.add_pad(&webrtc_ghost_audio_src)?;
webrtc_ghost_audio_src.link(&audio_sink)?;
}
let bus = pipeline.get_bus().unwrap();
let _ = bus.add_watch_local(move |_bus, msg| {
println!("{:#?}", msg);
glib::Continue(true)
});
pipeline.call_async(|pipeline| {
// If this fails, post an error on the bus so we exit
if pipeline.set_state(gst::State::Playing).is_err() {
gst_element_error!(
pipeline,
gst::LibraryError::Failed,
("Failed to set pipeline to Playing")
);
}
});
Ok(())
}
fn main() -> Result<(), anyhow::Error> {
let main_context = glib::MainContext::default();
main_context.block_on(run())
}