2018-12-12 11:00:33 +00:00
#![ allow(non_camel_case_types, non_upper_case_globals, non_snake_case) ]
2018-04-09 05:53:04 +00:00
use glib ;
2018-12-11 16:47:03 +00:00
use glib ::subclass ;
use glib ::subclass ::prelude ::* ;
2018-04-09 05:53:04 +00:00
use gst ;
use gst ::prelude ::* ;
2018-12-11 16:47:03 +00:00
use gst ::subclass ::prelude ::* ;
2018-06-15 13:16:25 +00:00
use gst_audio ;
2018-12-11 16:47:03 +00:00
use gst_base ;
2018-04-09 05:53:04 +00:00
use gst_base ::prelude ::* ;
2018-12-11 16:47:03 +00:00
use gst_base ::subclass ::prelude ::* ;
2018-04-09 05:53:04 +00:00
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-12-12 11:00:33 +00:00
use byte_slice_cast ::AsMutSliceOf ;
2018-08-14 13:45:13 +00:00
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-12-05 11:55:01 +00:00
loss_threshold : u32 ,
2018-08-20 07:25:15 +00:00
id_receiver : i8 ,
2018-09-24 13:46:36 +00:00
latency : Option < gst ::ClockTime > ,
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-12-05 11:55:01 +00:00
loss_threshold : 5 ,
2018-08-20 07:25:15 +00:00
id_receiver : 0 ,
2018-09-24 13:46:36 +00:00
latency : None ,
2018-04-09 05:53:04 +00:00
}
}
}
2018-12-11 16:47:03 +00:00
static PROPERTIES : [ subclass ::Property ; 3 ] = [
2019-02-28 09:55:01 +00:00
subclass ::Property ( " stream-name " , | _ | {
2018-12-11 16:47:03 +00:00
glib ::ParamSpec ::string (
2018-09-18 09:53:12 +00:00
" stream-name " ,
" Sream Name " ,
" Name of the streaming device " ,
None ,
2018-12-11 16:47:03 +00:00
glib ::ParamFlags ::READWRITE ,
)
} ) ,
2019-02-28 09:55:01 +00:00
subclass ::Property ( " ip " , | _ | {
2018-12-11 16:47:03 +00:00
glib ::ParamSpec ::string (
2018-09-18 09:53:12 +00:00
" ip " ,
" Stream IP " ,
2018-12-10 16:29:30 +00:00
" IP of the streaming device. Ex: 127.0.0.1:5961 " ,
2018-09-18 09:53:12 +00:00
None ,
2018-12-11 16:47:03 +00:00
glib ::ParamFlags ::READWRITE ,
)
} ) ,
2019-02-28 09:55:01 +00:00
subclass ::Property ( " loss-threshold " , | _ | {
2018-12-11 16:47:03 +00:00
glib ::ParamSpec ::uint (
2018-12-05 11:55:01 +00:00
" loss-threshold " ,
" Loss threshold " ,
2018-12-11 16:47:03 +00:00
" Loss threshold " ,
0 ,
60 ,
2018-12-05 11:55:01 +00:00
5 ,
2018-12-11 16:47:03 +00:00
glib ::ParamFlags ::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-12-11 16:47:03 +00:00
impl ObjectSubclass for NdiAudioSrc {
const NAME : & 'static str = " NdiAudioSrc " ;
type ParentType = gst_base ::BaseSrc ;
type Instance = gst ::subclass ::ElementInstanceStruct < Self > ;
type Class = subclass ::simple ::ClassStruct < Self > ;
glib_object_subclass! ( ) ;
2018-04-09 05:53:04 +00:00
2018-12-11 16:47:03 +00:00
fn new ( ) -> Self {
Self {
2018-04-09 05:53:04 +00:00
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-12-11 15:42:27 +00:00
timestamp_data : Mutex ::new ( TimestampData { offset : 0 } ) ,
2018-12-11 16:47:03 +00:00
}
2018-04-09 05:53:04 +00:00
}
2018-12-11 16:47:03 +00:00
fn class_init ( klass : & mut subclass ::simple ::ClassStruct < Self > ) {
2018-04-09 05:53:04 +00:00
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-12-11 16:47:03 +00:00
(
" format " ,
& gst ::List ::new ( & [
//TODO add more formats?
//&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-12-05 14:22:01 +00:00
( " channel-mask " , & gst ::Bitmask ::new ( 0 ) ) ,
2018-12-11 16:47:03 +00:00
] ,
) ;
let src_pad_template = gst ::PadTemplate ::new (
" src " ,
gst ::PadDirection ::Src ,
gst ::PadPresence ::Always ,
& caps ,
2019-02-28 10:43:31 +00:00
)
. unwrap ( ) ;
2018-12-11 16:47:03 +00:00
klass . add_pad_template ( src_pad_template ) ;
klass . install_properties ( & PROPERTIES ) ;
}
}
2018-09-18 11:25:24 +00:00
2018-12-11 16:47:03 +00:00
impl ObjectImpl for NdiAudioSrc {
glib_object_impl! ( ) ;
2018-04-09 05:53:04 +00:00
2018-12-11 16:47:03 +00:00
fn constructed ( & self , obj : & glib ::Object ) {
self . parent_constructed ( obj ) ;
2018-05-31 09:16:29 +00:00
2018-12-11 16:47:03 +00:00
let basesrc = obj . downcast_ref ::< gst_base ::BaseSrc > ( ) . unwrap ( ) ;
// Initialize live-ness and notify the base class that
// we'd like to operate in Time format
basesrc . set_live ( true ) ;
basesrc . set_format ( gst ::Format ::Time ) ;
}
fn set_property ( & self , obj : & glib ::Object , id : usize , value : & glib ::Value ) {
let prop = & PROPERTIES [ id ] ;
let basesrc = obj . downcast_ref ::< gst_base ::BaseSrc > ( ) . unwrap ( ) ;
match * prop {
subclass ::Property ( " stream-name " , .. ) = > {
let mut settings = self . settings . lock ( ) . unwrap ( ) ;
let stream_name = value . get ( ) . unwrap ( ) ;
gst_debug! (
self . cat ,
obj : basesrc ,
" Changing stream-name from {} to {} " ,
settings . stream_name ,
stream_name
) ;
settings . stream_name = stream_name ;
drop ( settings ) ;
}
subclass ::Property ( " ip " , .. ) = > {
let mut settings = self . settings . lock ( ) . unwrap ( ) ;
let ip = value . get ( ) . unwrap ( ) ;
gst_debug! (
self . cat ,
obj : basesrc ,
" Changing ip from {} to {} " ,
settings . ip ,
ip
) ;
settings . ip = ip ;
drop ( settings ) ;
}
subclass ::Property ( " loss-threshold " , .. ) = > {
let mut settings = self . settings . lock ( ) . unwrap ( ) ;
let loss_threshold = value . get ( ) . unwrap ( ) ;
gst_debug! (
self . cat ,
obj : basesrc ,
" Changing loss threshold from {} to {} " ,
settings . loss_threshold ,
loss_threshold
) ;
settings . loss_threshold = loss_threshold ;
drop ( settings ) ;
}
_ = > unimplemented! ( ) ,
2018-12-05 11:55:01 +00:00
}
2018-04-09 05:53:04 +00:00
}
2018-12-11 16:47:03 +00:00
fn get_property ( & self , _obj : & glib ::Object , id : usize ) -> Result < glib ::Value , ( ) > {
let prop = & PROPERTIES [ id ] ;
2018-09-18 09:53:12 +00:00
2018-12-11 16:47:03 +00:00
match * prop {
subclass ::Property ( " stream-name " , .. ) = > {
let settings = self . settings . lock ( ) . unwrap ( ) ;
Ok ( settings . stream_name . to_value ( ) )
}
subclass ::Property ( " ip " , .. ) = > {
let settings = self . settings . lock ( ) . unwrap ( ) ;
Ok ( settings . ip . to_value ( ) )
}
subclass ::Property ( " loss-threshold " , .. ) = > {
let settings = self . settings . lock ( ) . unwrap ( ) ;
Ok ( settings . loss_threshold . to_value ( ) )
}
_ = > unimplemented! ( ) ,
2018-12-05 11:55:01 +00:00
}
2018-04-09 05:53:04 +00:00
}
}
2018-12-11 16:47:03 +00:00
impl ElementImpl for NdiAudioSrc {
fn change_state (
& self ,
element : & gst ::Element ,
transition : gst ::StateChange ,
2019-02-28 09:55:01 +00:00
) -> Result < gst ::StateChangeSuccess , gst ::StateChangeError > {
2018-12-11 16:47:03 +00:00
if transition = = gst ::StateChange ::PausedToPlaying {
let mut receivers = hashmap_receivers . lock ( ) . unwrap ( ) ;
let settings = self . settings . lock ( ) . unwrap ( ) ;
2018-09-11 13:20:47 +00:00
2018-12-11 16:47:03 +00:00
let receiver = receivers . get_mut ( & settings . id_receiver ) . unwrap ( ) ;
let recv = & receiver . ndi_instance ;
let pNDI_recv = recv . recv ;
let audio_frame : NDIlib_audio_frame_v2_t = Default ::default ( ) ;
unsafe {
2019-03-05 16:59:44 +00:00
while NDIlib_recv_capture_v2 ( pNDI_recv , ptr ::null ( ) , & audio_frame , ptr ::null ( ) , 1000 )
! = NDIlib_frame_type_e ::NDIlib_frame_type_audio { }
}
2019-03-06 15:16:47 +00:00
gst_debug! ( self . cat , obj : element , " NDI audio frame received: {:?} " , audio_frame ) ;
if receiver . initial_timestamp < = audio_frame . timestamp as u64
| | receiver . initial_timestamp = = 0 {
receiver . initial_timestamp = audio_frame . timestamp as u64 ;
}
unsafe {
NDIlib_recv_free_audio_v2 ( pNDI_recv , & audio_frame ) ;
}
gst_debug! ( self . cat , obj : element , " Setting initial timestamp to {} " , receiver . initial_timestamp ) ;
2018-09-11 13:20:47 +00:00
}
2018-12-11 16:47:03 +00:00
self . parent_change_state ( element , transition )
2018-09-11 13:20:47 +00:00
}
2018-04-09 05:53:04 +00:00
}
2018-12-11 16:47:03 +00:00
impl BaseSrcImpl for NdiAudioSrc {
2019-02-28 09:55:01 +00:00
fn set_caps ( & self , element : & gst_base ::BaseSrc , caps : & gst ::CapsRef ) -> Result < ( ) , gst ::LoggableError > {
2018-12-11 16:47:03 +00:00
let info = match gst_audio ::AudioInfo ::from_caps ( caps ) {
2019-02-28 10:43:31 +00:00
None = > return Err ( gst_loggable_error! ( self . cat , " Failed to build `AudioInfo` from caps {} " , caps ) ) ,
2018-12-11 16:47:03 +00:00
Some ( info ) = > info ,
} ;
2018-04-23 11:42:38 +00:00
2018-12-11 16:47:03 +00:00
gst_debug! ( self . cat , obj : element , " Configuring for caps {} " , caps ) ;
2018-04-23 11:42:38 +00:00
2018-12-11 16:47:03 +00:00
let mut state = self . state . lock ( ) . unwrap ( ) ;
state . info = Some ( info ) ;
2018-04-23 11:42:38 +00:00
2019-02-28 10:43:31 +00:00
Ok ( ( ) )
2018-12-11 16:47:03 +00:00
}
2018-09-18 09:53:12 +00:00
2019-02-28 09:55:01 +00:00
fn start ( & self , element : & gst_base ::BaseSrc ) -> Result < ( ) , gst ::ErrorMessage > {
2018-12-11 16:47:03 +00:00
* self . state . lock ( ) . unwrap ( ) = Default ::default ( ) ;
2018-09-18 11:12:04 +00:00
2018-12-11 16:47:03 +00:00
let mut settings = self . settings . lock ( ) . unwrap ( ) ;
settings . id_receiver = connect_ndi (
self . cat ,
element ,
& settings . ip . clone ( ) ,
& settings . stream_name . clone ( ) ,
) ;
2018-04-09 05:53:04 +00:00
2019-02-28 11:13:40 +00:00
match settings . id_receiver {
0 = > Err ( gst_error_msg! (
2019-02-28 12:27:38 +00:00
gst ::ResourceError ::NotFound ,
2019-02-28 11:13:40 +00:00
[ " Could not connect to this source " ]
) ) ,
_ = > Ok ( ( ) )
}
2018-12-11 16:47:03 +00:00
}
2018-08-20 07:25:15 +00:00
2019-02-28 09:55:01 +00:00
fn stop ( & self , element : & gst_base ::BaseSrc ) -> Result < ( ) , gst ::ErrorMessage > {
2018-12-11 16:47:03 +00:00
* self . state . lock ( ) . unwrap ( ) = Default ::default ( ) ;
2018-04-30 08:18:17 +00:00
2018-12-11 16:47:03 +00:00
let settings = self . settings . lock ( ) . unwrap ( ) ;
stop_ndi ( self . cat , element , settings . id_receiver ) ;
// Commented because when adding ndi destroy stopped in this line
//*self.state.lock().unwrap() = Default::default();
2019-02-28 10:43:31 +00:00
Ok ( ( ) )
2018-09-11 13:20:47 +00:00
}
2018-09-24 13:46:36 +00:00
2018-12-11 16:47:03 +00:00
fn query ( & self , element : & gst_base ::BaseSrc , query : & mut gst ::QueryRef ) -> bool {
use gst ::QueryView ;
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 ] ) ;
2018-09-24 13:46:36 +00:00
return true ;
}
2018-12-11 16:47:03 +00:00
if let QueryView ::Latency ( ref mut q ) = query . view_mut ( ) {
let settings = & * self . settings . lock ( ) . unwrap ( ) ;
let state = self . state . lock ( ) . unwrap ( ) ;
if let Some ( ref _info ) = state . info {
let latency = settings . latency . unwrap ( ) ;
gst_debug! ( self . cat , obj : element , " Returning latency {} " , latency ) ;
q . set ( true , latency , gst ::CLOCK_TIME_NONE ) ;
return true ;
} else {
return false ;
}
}
2019-02-28 10:43:31 +00:00
BaseSrcImplExt ::parent_query ( self , element , query )
2018-09-24 13:46:36 +00:00
}
2018-07-02 12:07:51 +00:00
2018-12-11 16:47:03 +00:00
fn fixate ( & self , element : & gst_base ::BaseSrc , caps : gst ::Caps ) -> gst ::Caps {
let receivers = hashmap_receivers . lock ( ) . unwrap ( ) ;
let mut settings = self . settings . lock ( ) . unwrap ( ) ;
2018-08-14 13:45:13 +00:00
2018-12-11 16:47:03 +00:00
let receiver = receivers . get ( & settings . id_receiver ) . unwrap ( ) ;
2018-09-11 13:20:47 +00:00
2018-12-11 16:47:03 +00:00
let recv = & receiver . ndi_instance ;
let pNDI_recv = recv . recv ;
2018-08-20 10:14:54 +00:00
2018-12-11 16:47:03 +00:00
let audio_frame : NDIlib_audio_frame_v2_t = Default ::default ( ) ;
2018-08-14 13:45:13 +00:00
2019-03-01 10:24:54 +00:00
unsafe {
2019-03-06 15:16:47 +00:00
while NDIlib_recv_capture_v2 ( pNDI_recv , ptr ::null ( ) , & audio_frame , ptr ::null ( ) , 1000 )
! = NDIlib_frame_type_e ::NDIlib_frame_type_audio { }
2018-12-11 16:47:03 +00:00
}
let no_samples = audio_frame . no_samples as u64 ;
let audio_rate = audio_frame . sample_rate ;
settings . latency = gst ::SECOND . mul_div_floor ( no_samples , audio_rate as u64 ) ;
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_rate ) ;
s . fixate_field_nearest_int ( " channels " , audio_frame . no_channels ) ;
s . fixate_field_str ( " layout " , " interleaved " ) ;
s . set_value ( " channel-mask " , gst ::Bitmask ::new ( gst_audio ::AudioChannelPosition ::get_fallback_mask ( audio_frame . no_channels as u32 ) ) . to_send_value ( ) ) ;
2018-06-12 11:41:48 +00:00
}
2018-09-24 13:46:36 +00:00
2018-12-11 16:47:03 +00:00
let _ = element . post_message ( & gst ::Message ::new_latency ( ) . src ( Some ( element ) ) . build ( ) ) ;
2019-03-01 10:24:54 +00:00
unsafe {
NDIlib_recv_free_audio_v2 ( pNDI_recv , & audio_frame ) ;
}
2018-12-11 16:47:03 +00:00
self . parent_fixate ( element , caps )
2018-06-25 08:38:45 +00:00
}
2018-05-31 09:16:29 +00:00
2018-12-11 16:47:03 +00:00
fn create (
& self ,
element : & gst_base ::BaseSrc ,
_offset : u64 ,
_length : u32 ,
) -> Result < gst ::Buffer , gst ::FlowError > {
let _settings = & * self . settings . lock ( ) . unwrap ( ) ;
2018-08-20 07:25:15 +00:00
2018-12-11 16:47:03 +00:00
let mut timestamp_data = self . timestamp_data . lock ( ) . unwrap ( ) ;
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 ::FlowError ::NotNegotiated ) ;
}
Some ( ref info ) = > info . clone ( ) ,
} ;
let receivers = hashmap_receivers . lock ( ) . unwrap ( ) ;
2018-06-27 09:56:11 +00:00
2018-12-11 16:47:03 +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-12-11 16:47:03 +00:00
let pts : u64 ;
let audio_frame : NDIlib_audio_frame_v2_t = Default ::default ( ) ;
2018-08-24 16:00:02 +00:00
2018-12-11 16:47:03 +00:00
unsafe {
let time = receivers . get ( & _settings . id_receiver ) . unwrap ( ) . initial_timestamp ;
2018-06-25 08:38:45 +00:00
2018-12-11 16:47:03 +00:00
let mut skip_frame = true ;
let mut count_frame_none = 0 ;
while skip_frame {
let frame_type =
2018-09-18 09:53:12 +00:00
NDIlib_recv_capture_v2 ( pNDI_recv , ptr ::null ( ) , & audio_frame , ptr ::null ( ) , 1000 ) ;
2018-12-11 16:47:03 +00:00
if ( frame_type = = NDIlib_frame_type_e ::NDIlib_frame_type_none & & _settings . loss_threshold ! = 0 )
2018-09-18 09:53:12 +00:00
| | frame_type = = NDIlib_frame_type_e ::NDIlib_frame_type_error
2018-12-11 16:47:03 +00:00
{
if count_frame_none < _settings . loss_threshold {
count_frame_none + = 1 ;
continue ;
}
gst_element_error! ( element , gst ::ResourceError ::Read , [ " NDI frame type none or error received, assuming that the source closed the stream.... " ] ) ;
return Err ( gst ::FlowError ::CustomError ) ;
2018-12-05 11:55:01 +00:00
}
2018-12-11 16:47:03 +00:00
else if frame_type = = NDIlib_frame_type_e ::NDIlib_frame_type_none & & _settings . loss_threshold = = 0 {
gst_debug! ( self . cat , obj : element , " No audio frame received, sending empty buffer " ) ;
let buffer = gst ::Buffer ::with_size ( 0 ) . unwrap ( ) ;
return Ok ( buffer )
}
2019-02-28 09:55:01 +00:00
2018-12-11 16:47:03 +00:00
if time > = ( audio_frame . timestamp as u64 ) {
2019-03-01 10:24:54 +00:00
NDIlib_recv_free_audio_v2 ( pNDI_recv , & audio_frame ) ;
2018-12-11 16:47:03 +00:00
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 ;
2018-12-10 12:27:23 +00:00
}
}
2018-09-18 09:53:12 +00:00
2018-12-11 16:47:03 +00:00
gst_log! ( self . cat , obj : element , " NDI audio frame received: {:?} " , ( audio_frame ) ) ;
2018-12-11 11:26:50 +00:00
2018-12-11 16:47:03 +00:00
pts = audio_frame . timestamp as u64 - time ;
2018-06-26 12:07:43 +00:00
2018-12-11 16:47:03 +00:00
gst_log! ( self . cat , obj : element , " Calculated pts for audio frame: {:?} " , ( pts ) ) ;
2018-12-11 11:26:50 +00:00
2018-12-11 16:47:03 +00:00
// We multiply by 2 because is the size in bytes of an i16 variable
let buff_size = ( audio_frame . no_samples * 2 * audio_frame . no_channels ) as usize ;
let mut buffer = gst ::Buffer ::with_size ( buff_size ) . unwrap ( ) ;
{
if ndi_struct . start_pts = = gst ::ClockTime ( Some ( 0 ) ) {
ndi_struct . start_pts =
2018-09-18 09:53:12 +00:00
element . get_clock ( ) . unwrap ( ) . get_time ( ) - element . get_base_time ( ) ;
2018-12-11 16:47:03 +00:00
}
2018-08-24 16:00:02 +00:00
2018-12-11 16:47:03 +00:00
let buffer = buffer . get_mut ( ) . unwrap ( ) ;
2018-09-25 09:48:08 +00:00
2018-12-11 16:47:03 +00:00
// Newtek NDI yields times in 100ns intervals since the Unix Time
let pts : gst ::ClockTime = ( pts * 100 ) . into ( ) ;
buffer . set_pts ( pts + ndi_struct . start_pts ) ;
2018-09-25 09:48:08 +00:00
2018-12-11 16:47:03 +00:00
let duration : gst ::ClockTime = ( ( ( f64 ::from ( audio_frame . no_samples )
2018-09-25 09:48:08 +00:00
/ f64 ::from ( audio_frame . sample_rate ) )
* 1_000_000_000.0 ) as u64 )
. into ( ) ;
2018-12-11 16:47:03 +00:00
buffer . set_duration ( duration ) ;
2018-09-25 09:48:08 +00:00
2018-12-11 16:47:03 +00:00
buffer . set_offset ( timestamp_data . offset ) ;
timestamp_data . offset + = audio_frame . no_samples as u64 ;
buffer . set_offset_end ( timestamp_data . offset ) ;
2018-09-25 09:48:08 +00:00
2018-12-11 16:47:03 +00:00
let mut dst : NDIlib_audio_frame_interleaved_16s_t = Default ::default ( ) ;
dst . reference_level = 0 ;
2018-12-12 11:00:33 +00:00
dst . p_data = buffer . map_writable ( ) . unwrap ( ) . as_mut_slice_of ::< i16 > ( ) . unwrap ( ) . as_mut_ptr ( ) ;
2018-12-11 16:47:03 +00:00
NDIlib_util_audio_to_interleaved_16s_v2 ( & audio_frame , & mut dst ) ;
2019-03-01 10:24:54 +00:00
NDIlib_recv_free_audio_v2 ( pNDI_recv , & audio_frame ) ;
2018-12-11 16:47:03 +00:00
}
2018-04-09 05:53:04 +00:00
2018-12-11 16:47:03 +00:00
gst_log! ( self . cat , obj : element , " Produced buffer {:?} " , buffer ) ;
2018-06-26 12:07:43 +00:00
2018-12-11 16:47:03 +00:00
Ok ( buffer )
}
2018-05-31 09:16:29 +00:00
}
2018-09-18 09:53:12 +00:00
}
2018-12-11 16:47:03 +00:00
pub fn register ( plugin : & gst ::Plugin ) -> Result < ( ) , glib ::BoolError > {
gst ::Element ::register ( plugin , " ndiaudiosrc " , 0 , NdiAudioSrc ::get_type ( ) )
2018-09-18 09:53:12 +00:00
}