char/char-rtc-obs
git clone https://git.t4t.associates/char/char-rtc-obs
eeaf4aa
main
1use crate :: output::{ EncodedPacket , EncodedPacketType , OutputStream , OutputStreamError }; 2use anyhow:: Result ; 3use log::{ error, info}; 4use std::{ 5 os:: raw::{ c_char, c_void}, 6 slice, 7 time:: Duration , 8}; 9use tokio:: runtime:: Runtime ; 10 11pub struct RTCOutput { 12stream : OutputStream , 13runtime : Runtime , 14} 15/// cbindgen:prefix-with-name 16# [ repr ( C )] 17pub enum RTCOutputError { 18ConnectFailed , 19NetworkError , 20} 21 22impl From < OutputStreamError > for RTCOutputError { 23fn from ( ose : OutputStreamError ) ->Self { 24match ose{ 25OutputStreamError :: ConnectFailed =>RTCOutputError :: ConnectFailed , 26OutputStreamError :: NetworkError =>RTCOutputError :: NetworkError , 27OutputStreamError :: WriteError ( _) =>RTCOutputError :: NetworkError , 28} 29} 30} 31 32// You must call `char_rtc_output_free` on the returned value 33# [ no_mangle ] 34pub extern "C" fn char_rtc_output_new () ->* mut RTCOutput { 35( || ->Result < * mut RTCOutput > { 36let runtime = tokio:: runtime:: Runtime :: new () ?; 37let stream = runtime. block_on ( OutputStream :: new ()) ?; 38Ok ( Box :: into_raw ( Box :: new ( RTCOutput { stream, runtime}))) 39})() 40. unwrap_or_else ( |e|{ 41error! ( "Unable to create whip output: {e:?}" ); 42 std:: ptr:: null_mut ::< RTCOutput >() 43}) 44} 45 46# [ no_mangle ] 47pub unsafe extern "C" fn char_rtc_output_free ( output : * mut RTCOutput ) { 48info! ( "Freeing whip output" ); 49if !output. is_null () { 50drop ( Box :: from_raw ( output)); 51} 52} 53 54# [ no_mangle ] 55pub unsafe extern "C" fn char_rtc_output_bytes_sent ( output : * const RTCOutput ) ->u64 { 56let output = output. as_ref (). unwrap (); 57 output. stream . bytes_sent () 58} 59 60# [ no_mangle ] 61pub unsafe extern "C" fn char_rtc_output_dropped_frames ( output : * const RTCOutput ) ->i32 { 62let output = output. as_ref (). unwrap (); 63 output. stream . dropped_frames () 64} 65 66# [ no_mangle ] 67pub unsafe extern "C" fn char_rtc_output_congestion ( output : * const RTCOutput ) ->f64 { 68let output = output. as_ref (). unwrap (); 69 output. stream . congestion () 70} 71 72# [ no_mangle ] 73pub unsafe extern "C" fn char_rtc_output_connect_time_ms ( output : * const RTCOutput ) ->i32 { 74let output = output. as_ref (). unwrap (); 75 output. stream . connect_time (). as_millis () as i32 76} 77 78# [ no_mangle ] 79pub unsafe extern "C" fn char_rtc_output_connect ( 80output : * const RTCOutput , 81url : * const c_char , 82bearer_token : * const c_char , 83) { 84let output = output. as_ref (). unwrap (); 85 86let url = std:: ffi:: CStr :: from_ptr ( url). to_str (). unwrap (). to_owned (); 87let bearer_token =if !bearer_token. is_null () { 88Some ( 89 std:: ffi:: CStr :: from_ptr ( bearer_token) 90. to_str () 91. unwrap () 92. to_owned (), 93) 94} else { 95None 96}; 97 98 output. runtime . spawn ( async move { 99 output. stream . connect ( & url, bearer_token. as_deref ()). await ; 100}); 101} 102 103// Once closed, you cannot call `char_rtc_output_connect` again 104# [ no_mangle ] 105pub unsafe extern "C" fn char_rtc_output_close ( output : * const RTCOutput ) { 106let output = output. as_ref (). unwrap (); 107 108info! ( "Closing whip output" ); 109 output 110. runtime 111. block_on ( async { 112info! ( "I'm on a thread!" ); 113 output. stream . close (). await 114}) 115. unwrap_or_else ( |e|error! ( "Failed closing whip output: {e:?}" )) 116} 117 118/// Write an audio or video packet to the whip output 119# [ no_mangle ] 120pub unsafe extern "C" fn char_rtc_output_write ( 121output : * const RTCOutput , 122data : * const u8 , 123size : usize , 124duration : u64 , 125is_audio : bool , 126) ->bool { 127let output = output. as_ref (). unwrap (); 128 129let slice: & [ u8 ] = slice:: from_raw_parts ( data, size); 130let encoded_packet =EncodedPacket { 131data : slice. to_owned (), 132duration : Duration :: from_micros ( duration), 133typ : if is_audio{ 134EncodedPacketType :: Audio 135} else { 136EncodedPacketType :: Video 137}, 138}; 139 140 output 141. stream 142. write ( encoded_packet) 143. map ( |_|true ) 144. unwrap_or_else ( |e|{ 145error! ( "Failed to write packets to whip output: {e:?}" ); 146false 147}) 148} 149 150pub struct ErrorCallbackUserdata ( * mut c_void ); 151unsafe impl Send for ErrorCallbackUserdata {} 152unsafe impl Sync for ErrorCallbackUserdata {} 153 154impl ErrorCallbackUserdata { 155fn as_ptr ( & self ) ->* mut c_void { 156self . 0 157} 158} 159 160type RTCOutputErrorCallback =unsafe extern "C" fn ( user_data : * mut c_void , error : RTCOutputError ); 161 162# [ no_mangle ] 163pub unsafe extern "C" fn char_rtc_output_set_error_callback ( 164output : * const RTCOutput , 165cb : RTCOutputErrorCallback , 166user_data : * mut c_void , 167) { 168let output = output. as_ref (). unwrap (); 169 170let user_data =ErrorCallbackUserdata ( user_data); 171 output 172. stream 173. set_error_callback ( Box :: new ( move |error|cb ( user_data. as_ptr (), error. into ()))) 174}