2018-04-24 17:41:27 +00:00
#![ allow(non_camel_case_types, non_upper_case_globals, non_snake_case) ]
2018-04-09 05:53:04 +00:00
use glib ;
use gst ;
use gst ::prelude ::* ;
2018-06-15 13:16:25 +00:00
use gst_audio ;
2018-04-09 05:53:04 +00:00
use gst_base ::prelude ::* ;
2018-09-18 09:53:12 +00:00
use gobject_subclass ::object ::* ;
2018-04-09 05:53:04 +00:00
use gst_plugin ::base_src ::* ;
use gst_plugin ::element ::* ;
use std ::sync ::Mutex ;
use std ::{ i32 , u32 } ;
2018-04-13 10:06:15 +00:00
use std ::ptr ;
2018-06-15 13:16:25 +00:00
2018-06-26 12:07:43 +00:00
use connect_ndi ;
2018-08-24 16:00:02 +00:00
use ndi_struct ;
2018-09-18 09:53:12 +00:00
use ndisys ::* ;
use stop_ndi ;
2018-04-13 10:06:15 +00:00
2018-08-14 13:45:13 +00:00
use hashmap_receivers ;
2018-04-12 15:17:59 +00:00
#[ derive(Debug, Clone) ]
2018-04-09 05:53:04 +00:00
struct Settings {
2018-04-12 15:17:59 +00:00
stream_name : String ,
2018-05-31 09:14:11 +00:00
ip : String ,
2018-08-20 07:25:15 +00:00
id_receiver : i8 ,
2018-04-09 05:53:04 +00:00
}
impl Default for Settings {
fn default ( ) -> Self {
Settings {
2018-04-12 15:17:59 +00:00
stream_name : String ::from ( " Fixed ndi stream name " ) ,
2018-05-31 09:14:11 +00:00
ip : String ::from ( " " ) ,
2018-08-20 07:25:15 +00:00
id_receiver : 0 ,
2018-04-09 05:53:04 +00:00
}
}
}
2018-05-31 09:14:11 +00:00
static PROPERTIES : [ Property ; 2 ] = [
2018-09-18 09:53:12 +00:00
Property ::String (
" stream-name " ,
" Sream Name " ,
" Name of the streaming device " ,
None ,
PropertyMutability ::ReadWrite ,
) ,
Property ::String (
" ip " ,
" Stream IP " ,
" Stream IP " ,
None ,
PropertyMutability ::ReadWrite ,
) ,
2018-04-09 05:53:04 +00:00
] ;
struct State {
2018-06-15 13:16:25 +00:00
info : Option < gst_audio ::AudioInfo > ,
2018-04-09 05:53:04 +00:00
}
impl Default for State {
fn default ( ) -> State {
2018-09-18 09:53:12 +00:00
State { info : None }
2018-04-09 05:53:04 +00:00
}
}
2018-09-18 09:53:12 +00:00
struct TimestampData {
2018-04-30 08:18:17 +00:00
offset : u64 ,
}
2018-04-09 05:53:04 +00:00
2018-06-12 12:40:17 +00:00
struct NdiAudioSrc {
2018-04-09 05:53:04 +00:00
cat : gst ::DebugCategory ,
settings : Mutex < Settings > ,
state : Mutex < State > ,
2018-06-27 09:56:11 +00:00
timestamp_data : Mutex < TimestampData > ,
2018-04-09 05:53:04 +00:00
}
2018-06-12 12:40:17 +00:00
impl NdiAudioSrc {
2018-04-09 05:53:04 +00:00
fn new ( element : & BaseSrc ) -> Box < BaseSrcImpl < BaseSrc > > {
2018-04-24 17:41:27 +00:00
element . set_live ( true ) ;
2018-04-09 05:53:04 +00:00
element . set_format ( gst ::Format ::Time ) ;
Box ::new ( Self {
cat : gst ::DebugCategory ::new (
2018-06-12 12:40:17 +00:00
" ndiaudiosrc " ,
2018-04-09 05:53:04 +00:00
gst ::DebugColorFlags ::empty ( ) ,
2018-06-15 13:16:25 +00:00
" NewTek NDI Audio Source " ,
2018-04-09 05:53:04 +00:00
) ,
settings : Mutex ::new ( Default ::default ( ) ) ,
state : Mutex ::new ( Default ::default ( ) ) ,
2018-09-18 09:53:12 +00:00
timestamp_data : Mutex ::new ( TimestampData { offset : 0 } ) ,
2018-04-09 05:53:04 +00:00
} )
}
fn class_init ( klass : & mut BaseSrcClass ) {
klass . set_metadata (
2018-06-12 12:40:17 +00:00
" NewTek NDI Audio Source " ,
2018-04-09 05:53:04 +00:00
" Source " ,
2018-06-25 08:38:45 +00:00
" NewTek NDI audio source " ,
" Ruben Gonzalez <rubenrua@teltek.es>, Daniel Vilar <daniel.peiteado@teltek.es> " ,
2018-04-09 05:53:04 +00:00
) ;
let caps = gst ::Caps ::new_simple (
2018-06-15 13:16:25 +00:00
" audio/x-raw " ,
2018-04-09 05:53:04 +00:00
& [
2018-09-18 09:53:12 +00:00
(
" format " ,
& gst ::List ::new ( & [
2018-09-18 11:25:24 +00:00
//TODO add more formats?
2018-09-18 09:53:12 +00:00
& gst_audio ::AUDIO_FORMAT_F32 . to_string ( ) ,
& gst_audio ::AUDIO_FORMAT_F64 . to_string ( ) ,
& gst_audio ::AUDIO_FORMAT_S16 . to_string ( ) ,
2018-04-24 17:41:27 +00:00
] ) ,
2018-04-09 05:53:04 +00:00
) ,
2018-06-15 13:16:25 +00:00
( " rate " , & gst ::IntRange ::< i32 > ::new ( 1 , i32 ::MAX ) ) ,
( " channels " , & gst ::IntRange ::< i32 > ::new ( 1 , i32 ::MAX ) ) ,
( " layout " , & " interleaved " ) ,
2018-09-18 09:53:12 +00:00
] ,
) ;
2018-09-18 11:25:24 +00:00
2018-09-18 09:53:12 +00:00
let src_pad_template = gst ::PadTemplate ::new (
" src " ,
gst ::PadDirection ::Src ,
gst ::PadPresence ::Always ,
& caps ,
) ;
klass . add_pad_template ( src_pad_template ) ;
2018-04-09 05:53:04 +00:00
2018-09-18 09:53:12 +00:00
klass . install_properties ( & PROPERTIES ) ;
}
}
2018-05-31 09:16:29 +00:00
2018-09-18 09:53:12 +00:00
impl ObjectImpl < BaseSrc > for NdiAudioSrc {
fn set_property ( & self , obj : & glib ::Object , id : u32 , value : & glib ::Value ) {
let prop = & PROPERTIES [ id as usize ] ;
let element = obj . clone ( ) . downcast ::< BaseSrc > ( ) . unwrap ( ) ;
match * prop {
Property ::String ( " stream-name " , .. ) = > {
let mut settings = self . settings . lock ( ) . unwrap ( ) ;
let stream_name = value . get ( ) . unwrap ( ) ;
gst_debug! (
self . cat ,
obj : & element ,
" Changing stream-name from {} to {} " ,
settings . stream_name ,
stream_name
) ;
settings . stream_name = stream_name ;
drop ( settings ) ;
let _ =
2018-05-31 09:14:11 +00:00
element . post_message ( & gst ::Message ::new_latency ( ) . src ( Some ( & element ) ) . build ( ) ) ;
2018-09-18 09:53:12 +00:00
}
Property ::String ( " ip " , .. ) = > {
let mut settings = self . settings . lock ( ) . unwrap ( ) ;
let ip = value . get ( ) . unwrap ( ) ;
gst_debug! (
self . cat ,
obj : & element ,
" Changing ip from {} to {} " ,
settings . ip ,
ip
) ;
settings . ip = ip ;
drop ( settings ) ;
let _ =
2018-04-12 15:17:59 +00:00
element . post_message ( & gst ::Message ::new_latency ( ) . src ( Some ( & element ) ) . build ( ) ) ;
}
2018-09-18 09:53:12 +00:00
_ = > unimplemented! ( ) ,
2018-04-09 05:53:04 +00:00
}
2018-09-18 09:53:12 +00:00
}
2018-04-09 05:53:04 +00:00
2018-09-18 09:53:12 +00:00
fn get_property ( & self , _obj : & glib ::Object , id : u32 ) -> Result < glib ::Value , ( ) > {
let prop = & PROPERTIES [ id as usize ] ;
match * prop {
Property ::String ( " stream-name " , .. ) = > {
let settings = self . settings . lock ( ) . unwrap ( ) ;
Ok ( settings . stream_name . to_value ( ) )
2018-04-12 15:17:59 +00:00
}
2018-09-18 09:53:12 +00:00
Property ::String ( " ip " , .. ) = > {
let settings = self . settings . lock ( ) . unwrap ( ) ;
Ok ( settings . ip . to_value ( ) )
}
_ = > unimplemented! ( ) ,
2018-04-09 05:53:04 +00:00
}
}
2018-09-18 09:53:12 +00:00
}
2018-04-09 05:53:04 +00:00
2018-09-18 09:53:12 +00:00
impl ElementImpl < BaseSrc > for NdiAudioSrc {
fn change_state (
& self ,
element : & BaseSrc ,
transition : gst ::StateChange ,
) -> gst ::StateChangeReturn {
if transition = = gst ::StateChange ::PausedToPlaying {
let receivers = hashmap_receivers . lock ( ) . unwrap ( ) ;
let settings = self . settings . lock ( ) . unwrap ( ) ;
2018-09-11 13:20:47 +00:00
2018-09-18 09:53:12 +00:00
let receiver = receivers . get ( & settings . id_receiver ) . unwrap ( ) ;
let recv = & receiver . ndi_instance ;
let pNDI_recv = recv . recv ;
2018-09-11 13:20:47 +00:00
2018-09-18 09:53:12 +00:00
let audio_frame : NDIlib_audio_frame_v2_t = Default ::default ( ) ;
2018-09-11 13:20:47 +00:00
2018-09-18 09:53:12 +00:00
let mut frame_type : NDIlib_frame_type_e = NDIlib_frame_type_e ::NDIlib_frame_type_none ;
unsafe {
while frame_type ! = NDIlib_frame_type_e ::NDIlib_frame_type_audio {
frame_type = NDIlib_recv_capture_v2 (
pNDI_recv ,
ptr ::null ( ) ,
& audio_frame ,
ptr ::null ( ) ,
1000 ,
) ;
}
2018-09-11 13:20:47 +00:00
2018-09-18 09:53:12 +00:00
if ndi_struct . initial_timestamp < = audio_frame . timestamp as u64
| | ndi_struct . initial_timestamp = = 0
{
ndi_struct . initial_timestamp = audio_frame . timestamp as u64 ;
2018-09-11 13:20:47 +00:00
}
}
}
2018-09-18 09:53:12 +00:00
element . parent_change_state ( transition )
2018-04-09 05:53:04 +00:00
}
2018-09-18 09:53:12 +00:00
}
2018-04-09 05:53:04 +00:00
2018-09-18 09:53:12 +00:00
impl BaseSrcImpl < BaseSrc > for NdiAudioSrc {
fn set_caps ( & self , element : & BaseSrc , caps : & gst ::CapsRef ) -> bool {
let info = match gst_audio ::AudioInfo ::from_caps ( caps ) {
None = > return false ,
Some ( info ) = > info ,
} ;
2018-04-23 11:42:38 +00:00
2018-09-18 09:53:12 +00:00
gst_debug! ( self . cat , obj : element , " Configuring for caps {} " , caps ) ;
2018-04-23 11:42:38 +00:00
2018-09-18 09:53:12 +00:00
let mut state = self . state . lock ( ) . unwrap ( ) ;
state . info = Some ( info ) ;
2018-04-23 11:42:38 +00:00
2018-09-18 09:53:12 +00:00
true
}
2018-05-31 09:16:29 +00:00
2018-09-18 09:53:12 +00:00
fn start ( & self , element : & BaseSrc ) -> bool {
* self . state . lock ( ) . unwrap ( ) = Default ::default ( ) ;
let mut settings = self . settings . lock ( ) . unwrap ( ) ;
settings . id_receiver = connect_ndi (
self . cat ,
element ,
2018-09-18 11:12:04 +00:00
& settings . ip . clone ( ) ,
& settings . stream_name . clone ( ) ,
2018-09-18 09:53:12 +00:00
) ;
2018-09-18 11:12:04 +00:00
settings . id_receiver ! = 0
2018-09-18 09:53:12 +00:00
}
2018-04-09 05:53:04 +00:00
2018-09-18 09:53:12 +00:00
fn stop ( & self , element : & BaseSrc ) -> bool {
* self . state . lock ( ) . unwrap ( ) = Default ::default ( ) ;
2018-08-20 07:25:15 +00:00
2018-09-18 09:53:12 +00:00
let settings = self . settings . lock ( ) . unwrap ( ) ;
2018-09-18 11:12:04 +00:00
stop_ndi ( self . cat , element , settings . id_receiver ) ;
2018-09-18 09:53:12 +00:00
// Commented because when adding ndi destroy stopped in this line
//*self.state.lock().unwrap() = Default::default();
true
}
2018-04-30 08:18:17 +00:00
2018-09-18 09:53:12 +00:00
fn query ( & self , element : & BaseSrc , query : & mut gst ::QueryRef ) -> bool {
use gst ::QueryView ;
2018-09-18 11:12:04 +00:00
if let QueryView ::Scheduling ( ref mut q ) = query . view_mut ( ) {
q . set ( gst ::SchedulingFlags ::SEQUENTIAL , 1 , - 1 , 0 ) ;
q . add_scheduling_modes ( & [ gst ::PadMode ::Push ] ) ;
return true ;
2018-09-11 13:20:47 +00:00
}
2018-09-18 09:53:12 +00:00
BaseSrcBase ::parent_query ( element , query )
}
2018-07-02 12:07:51 +00:00
2018-09-18 09:53:12 +00:00
fn fixate ( & self , element : & BaseSrc , caps : gst ::Caps ) -> gst ::Caps {
let receivers = hashmap_receivers . lock ( ) . unwrap ( ) ;
let settings = self . settings . lock ( ) . unwrap ( ) ;
2018-08-14 13:45:13 +00:00
2018-09-18 09:53:12 +00:00
let receiver = receivers . get ( & settings . id_receiver ) . unwrap ( ) ;
2018-09-11 13:20:47 +00:00
2018-09-18 09:53:12 +00:00
let recv = & receiver . ndi_instance ;
let pNDI_recv = recv . recv ;
2018-08-20 10:14:54 +00:00
2018-09-18 09:53:12 +00:00
let audio_frame : NDIlib_audio_frame_v2_t = Default ::default ( ) ;
2018-08-14 13:45:13 +00:00
2018-09-18 09:53:12 +00:00
let mut frame_type : NDIlib_frame_type_e = NDIlib_frame_type_e ::NDIlib_frame_type_none ;
while frame_type ! = NDIlib_frame_type_e ::NDIlib_frame_type_audio {
unsafe {
frame_type =
NDIlib_recv_capture_v2 ( pNDI_recv , ptr ::null ( ) , & audio_frame , ptr ::null ( ) , 1000 ) ;
2018-06-12 11:41:48 +00:00
}
2018-09-18 09:53:12 +00:00
}
let mut caps = gst ::Caps ::truncate ( caps ) ;
{
let caps = caps . make_mut ( ) ;
let s = caps . get_mut_structure ( 0 ) . unwrap ( ) ;
s . fixate_field_nearest_int ( " rate " , audio_frame . sample_rate / audio_frame . no_channels ) ;
s . fixate_field_nearest_int ( " channels " , audio_frame . no_channels ) ;
2018-06-25 08:38:45 +00:00
}
2018-05-31 09:16:29 +00:00
2018-09-18 09:53:12 +00:00
element . parent_fixate ( caps )
}
2018-08-20 07:25:15 +00:00
2018-09-18 09:53:12 +00:00
fn create (
& self ,
element : & BaseSrc ,
_offset : u64 ,
_length : u32 ,
) -> Result < gst ::Buffer , gst ::FlowReturn > {
let _settings = & * self . settings . lock ( ) . unwrap ( ) ;
let mut timestamp_data = self . timestamp_data . lock ( ) . unwrap ( ) ;
2018-09-18 11:25:24 +00:00
2018-09-18 09:53:12 +00:00
let state = self . state . lock ( ) . unwrap ( ) ;
let _info = match state . info {
None = > {
gst_element_error! ( element , gst ::CoreError ::Negotiation , [ " Have no caps yet " ] ) ;
return Err ( gst ::FlowReturn ::NotNegotiated ) ;
}
Some ( ref info ) = > info . clone ( ) ,
} ;
let receivers = hashmap_receivers . lock ( ) . unwrap ( ) ;
2018-06-27 09:56:11 +00:00
2018-09-18 09:53:12 +00:00
let recv = & receivers . get ( & _settings . id_receiver ) . unwrap ( ) . ndi_instance ;
let pNDI_recv = recv . recv ;
2018-08-14 13:45:13 +00:00
2018-09-18 09:53:12 +00:00
let pts : u64 ;
let audio_frame : NDIlib_audio_frame_v2_t = Default ::default ( ) ;
2018-08-24 16:00:02 +00:00
2018-09-18 09:53:12 +00:00
unsafe {
let time = ndi_struct . initial_timestamp ;
2018-06-25 08:38:45 +00:00
2018-09-18 09:53:12 +00:00
let mut skip_frame = true ;
while skip_frame {
let frame_type =
NDIlib_recv_capture_v2 ( pNDI_recv , ptr ::null ( ) , & audio_frame , ptr ::null ( ) , 1000 ) ;
if frame_type = = NDIlib_frame_type_e ::NDIlib_frame_type_none
| | frame_type = = NDIlib_frame_type_e ::NDIlib_frame_type_error
2018-06-26 12:07:43 +00:00
{
2018-09-18 09:53:12 +00:00
gst_element_error! ( element , gst ::ResourceError ::Read , [ " NDI frame type none received, assuming that the source closed the stream.... " ] ) ;
return Err ( gst ::FlowReturn ::CustomError ) ;
2018-06-25 08:38:45 +00:00
}
2018-09-18 09:53:12 +00:00
if time > = ( audio_frame . timestamp as u64 ) {
gst_debug! ( self . cat , obj : element , " Frame timestamp ({:?}) is lower than received in the first frame from NDI ({:?}), so skiping... " , ( audio_frame . timestamp as u64 ) , time ) ;
} else {
skip_frame = false ;
}
}
pts = audio_frame . timestamp as u64 - time ;
2018-06-26 12:07:43 +00:00
2018-09-18 09:53:12 +00:00
let buff_size = ( audio_frame . channel_stride_in_bytes ) as usize ;
let mut buffer = gst ::Buffer ::with_size ( buff_size ) . unwrap ( ) ;
{
let vec = Vec ::from_raw_parts ( audio_frame . p_data as * mut u8 , buff_size , buff_size ) ;
let pts : gst ::ClockTime = ( pts * 100 ) . into ( ) ;
2018-09-18 11:12:04 +00:00
let duration : gst ::ClockTime = ( ( ( f64 ::from ( audio_frame . no_samples )
/ f64 ::from ( audio_frame . sample_rate ) )
* 1_000_000_000.0 ) as u64 )
2018-09-18 09:53:12 +00:00
. into ( ) ;
let buffer = buffer . get_mut ( ) . unwrap ( ) ;
if ndi_struct . start_pts = = gst ::ClockTime ( Some ( 0 ) ) {
ndi_struct . start_pts =
element . get_clock ( ) . unwrap ( ) . get_time ( ) - element . get_base_time ( ) ;
}
2018-08-24 16:00:02 +00:00
2018-09-18 09:53:12 +00:00
buffer . set_pts ( pts + ndi_struct . start_pts ) ;
buffer . set_duration ( duration ) ;
buffer . set_offset ( timestamp_data . offset ) ;
buffer . set_offset_end ( timestamp_data . offset + 1 ) ;
2018-09-18 11:12:04 +00:00
timestamp_data . offset + = timestamp_data . offset ;
2018-09-18 09:53:12 +00:00
buffer . copy_from_slice ( 0 , & vec ) . unwrap ( ) ;
2018-05-31 09:16:29 +00:00
}
2018-04-09 05:53:04 +00:00
2018-09-18 09:53:12 +00:00
gst_debug! ( self . cat , obj : element , " Produced buffer {:?} " , buffer ) ;
2018-06-26 12:07:43 +00:00
2018-09-18 09:53:12 +00:00
Ok ( buffer )
2018-05-31 09:16:29 +00:00
}
2018-09-18 09:53:12 +00:00
}
}
2018-04-09 05:53:04 +00:00
2018-09-18 09:53:12 +00:00
struct NdiAudioSrcStatic ;
impl ImplTypeStatic < BaseSrc > for NdiAudioSrcStatic {
fn get_name ( & self ) -> & str {
" NdiAudioSrc "
2018-06-26 12:07:43 +00:00
}
2018-09-18 09:53:12 +00:00
fn new ( & self , element : & BaseSrc ) -> Box < BaseSrcImpl < BaseSrc > > {
NdiAudioSrc ::new ( element )
2018-06-26 12:07:43 +00:00
}
2018-09-18 09:53:12 +00:00
fn class_init ( & self , klass : & mut BaseSrcClass ) {
NdiAudioSrc ::class_init ( klass ) ;
}
}
pub fn register ( plugin : & gst ::Plugin ) {
let type_ = register_type ( NdiAudioSrcStatic ) ;
gst ::Element ::register ( plugin , " ndiaudiosrc " , 0 , type_ ) ;
}