char/char-rtc-obs
git clone https://git.t4t.associates/char/char-rtc-obs
35e5e7d
main
1#include "whip-output.h" 2 3static void whip_output_close_unsafe (struct whip_output * output ) 4{ 5if (output && output -> whip_output ) { 6char_rtc_output_close (output -> whip_output ); 7char_rtc_output_free (output -> whip_output ); 8output -> whip_output = NULL ; 9 } 10} 11 12static const char * whip_output_getname (void * type_data ) 13{ 14UNUSED_PARAMETER (type_data ); 15 16return obs_module_text ("Output.Name" ); 17} 18 19static void * whip_output_create (obs_data_t * settings ,obs_output_t * obs_output ) 20{ 21UNUSED_PARAMETER (settings ); 22 23struct whip_output * output = bzalloc (sizeof (struct whip_output )); 24pthread_mutex_init_value (& output -> write_mutex ); 25 26output -> output = obs_output ; 27output -> whip_output = NULL ; 28 29// This needs to be recursive due to `obs_output_signal_stop` calling 30// `whip_output_total_bytes_sent` (also guarded by mutex) 31if (pthread_mutex_init_recursive (& output -> write_mutex )!= 0 ) 32 gotofail ; 33 34return output ; 35 36fail : 37pthread_mutex_destroy (& output -> write_mutex ); 38bfree (output ); 39return NULL ; 40} 41 42static void whip_output_destroy (void * data ) 43{ 44struct whip_output * output = data ; 45 46pthread_mutex_lock (& output -> write_mutex ); 47whip_output_close_unsafe (output ); 48pthread_mutex_unlock (& output -> write_mutex ); 49 50pthread_mutex_destroy (& output -> write_mutex ); 51bfree (output ); 52} 53 54static int map_rtc_error_to_obs_error (RTCOutputError error ) 55{ 56switch (error ) { 57case RTCOutputError_ConnectFailed : 58return OBS_OUTPUT_CONNECT_FAILED ; 59case RTCOutputError_NetworkError : 60return OBS_OUTPUT_ERROR ; 61default : 62blog (LOG_ERROR ,"Invalid whip error code: %d" ,error ); 63return OBS_OUTPUT_ERROR ; 64 } 65} 66 67static void whip_output_error_callback (void * data ,RTCOutputError error ) 68{ 69struct whip_output * output = data ; 70pthread_mutex_lock (& output -> write_mutex ); 71if (output -> whip_output ) { 72whip_output_close_unsafe (output ); 73obs_output_signal_stop (output -> output , 74map_rtc_error_to_obs_error (error )); 75 } 76pthread_mutex_unlock (& output -> write_mutex ); 77} 78 79static bool whip_output_start (void * data ) 80{ 81struct whip_output * output = data ; 82obs_service_t * service ; 83obs_data_t * service_settings ; 84const char * url ,* bearer_token ; 85 86service = obs_output_get_service (output -> output ); 87if (!service ) 88return false; 89 90if (!obs_output_can_begin_data_capture (output -> output ,0 )) 91return false; 92 93if (!obs_output_initialize_encoders (output -> output ,0 )) 94return false; 95 96output -> whip_output = char_rtc_output_new (); 97if (!output -> whip_output ) { 98blog (LOG_ERROR ,"Unable to initialize whip output" ); 99return false; 100 } 101 102char_rtc_output_set_error_callback ( 103output -> whip_output , 104 (RTCOutputErrorCallback )whip_output_error_callback ,output ); 105 106service_settings = obs_service_get_settings (service ); 107if (!service_settings ) 108return false; 109 110url = obs_service_get_url (service ); 111bearer_token = obs_data_get_string (service_settings ,"bearer_token" ); 112char_rtc_output_connect (output -> whip_output ,url ,bearer_token ); 113 114obs_output_begin_data_capture (output -> output ,0 ); 115 116obs_data_release (service_settings ); 117return true; 118} 119 120static void whip_output_stop (void * data ,uint64_t ts ) 121{ 122UNUSED_PARAMETER (ts ); 123 124struct whip_output * output = data ; 125 126pthread_mutex_lock (& output -> write_mutex ); 127whip_output_close_unsafe (output ); 128pthread_mutex_unlock (& output -> write_mutex ); 129 130obs_output_signal_stop (output -> output ,OBS_OUTPUT_SUCCESS ); 131} 132 133static void whip_output_data (void * data ,struct encoder_packet * packet ) 134{ 135struct whip_output * output = data ; 136int64_t duration = 0 ; 137bool is_audio = false; 138 139if (packet -> type == OBS_ENCODER_VIDEO ) { 140duration = packet -> dts_usec - output -> video_timestamp ; 141output -> video_timestamp = packet -> dts_usec ; 142 }else if (packet -> type == OBS_ENCODER_AUDIO ) { 143is_audio = true; 144duration = packet -> dts_usec - output -> audio_timestamp ; 145output -> audio_timestamp = packet -> dts_usec ; 146 } 147 148pthread_mutex_lock (& output -> write_mutex ); 149if (output -> whip_output ) { 150if (!char_rtc_output_write (output -> whip_output ,packet -> data , 151packet -> size ,duration ,is_audio )) { 152blog (LOG_ERROR , 153"Unable to write packets to whip output" ); 154 } 155 } 156pthread_mutex_unlock (& output -> write_mutex ); 157} 158 159static void whip_output_defaults (obs_data_t * defaults ) 160{ 161UNUSED_PARAMETER (defaults ); 162} 163 164static obs_properties_t * whip_output_properties (void * unused ) 165{ 166UNUSED_PARAMETER (unused ); 167 168obs_properties_t * props = obs_properties_create (); 169 170return props ; 171} 172 173static uint64_t whip_output_total_bytes_sent (void * data ) 174{ 175struct whip_output * output = data ; 176pthread_mutex_lock (& output -> write_mutex ); 177uint64_t bytes_sent = 0 ; 178if (output -> whip_output ) 179bytes_sent = char_rtc_output_bytes_sent (output -> whip_output ); 180pthread_mutex_unlock (& output -> write_mutex ); 181 182return bytes_sent ; 183} 184 185static int whip_output_dropped_frames (void * data ) 186{ 187struct whip_output * output = data ; 188pthread_mutex_lock (& output -> write_mutex ); 189uint32_t dropped_frames = 0 ; 190if (output -> whip_output ) 191dropped_frames = 192char_rtc_output_dropped_frames (output -> whip_output ); 193pthread_mutex_unlock (& output -> write_mutex ); 194 195return dropped_frames ; 196} 197 198static int whip_output_connect_time_ms (void * data ) 199{ 200struct whip_output * output = data ; 201pthread_mutex_lock (& output -> write_mutex ); 202uint32_t connect_time = 0 ; 203if (output -> whip_output ) 204connect_time = 205char_rtc_output_connect_time_ms (output -> whip_output ); 206pthread_mutex_unlock (& output -> write_mutex ); 207 208return connect_time ; 209} 210 211struct obs_output_info whip_output_info = { 212 .id = "whip_output" , 213 .flags = OBS_OUTPUT_AV |OBS_OUTPUT_ENCODED |OBS_OUTPUT_SERVICE , 214 .encoded_video_codecs = "h264" , 215 .encoded_audio_codecs = "opus" , 216 .get_name = whip_output_getname , 217 .create = whip_output_create , 218 .destroy = whip_output_destroy , 219 .start = whip_output_start , 220 .stop = whip_output_stop , 221 .encoded_packet = whip_output_data , 222 .get_defaults = whip_output_defaults , 223 .get_properties = whip_output_properties , 224 .get_total_bytes = whip_output_total_bytes_sent , 225 .get_connect_time_ms = whip_output_connect_time_ms , 226 .get_dropped_frames = whip_output_dropped_frames , 227}; 228 229void whip_register_output () 230{ 231obs_register_output (& whip_output_info ); 232}