diff --git a/Makefile.am b/Makefile.am index 125791e444..24ec7f49ea 100644 --- a/Makefile.am +++ b/Makefile.am @@ -446,7 +446,9 @@ stream_DATA += \ plugins/streams/music.mulaw \ plugins/streams/radio.alaw \ plugins/streams/test_gstreamer.sh \ - plugins/streams/test_gstreamer_1.sh + plugins/streams/test_gstreamer1.sh \ + plugins/streams/test_gstreamer_multistream.sh \ + plugins/streams/test_gstreamer1_multistream.sh EXTRA_DIST += \ conf/janus.plugin.streaming.jcfg.sample.in \ $(stream_DATA) diff --git a/conf/janus.plugin.streaming.jcfg.sample.in b/conf/janus.plugin.streaming.jcfg.sample.in index b476bc3138..9e456f7878 100644 --- a/conf/janus.plugin.streaming.jcfg.sample.in +++ b/conf/janus.plugin.streaming.jcfg.sample.in @@ -143,6 +143,7 @@ file-ondemand-sample: { #videopt = 126 #videortpmap = "H264/90000" #videofmtp = "profile-level-id=42e01f;packetization-mode=1" + #secret = "adminpwd" #} # @@ -162,6 +163,7 @@ file-ondemand-sample: { #video = false #data = true #dataport = 5008 + #secret = "adminpwd" #} # @@ -182,6 +184,7 @@ file-ondemand-sample: { #videomcast = "232.3.4.5" #videopt = 100 #videortpmap = "VP8/90000" + #secret = "adminpwd" #} # @@ -202,4 +205,54 @@ file-ondemand-sample: { #url = "rtsp://127.0.0.1:8554/unicast" #rtsp_user = "username" #rtsp_pwd = "password" + #secret = "adminpwd" #} + +# +# Finally, this is an example of how you can configure a live Streaming +# mountpoint to send multiple streams of the same type at the same time: +# that is, not simulcasting, but different streams (e.g., two audio +# streams and two video streams). To do so, you don't set the audio, +# video and data properties inline, but use an array of properties instead, +# each identifying a single stream to add, that will then translate to +# a dedicated m-line in the SDP. For each stream, you specify the type, +# a unique ID (mid), and can provide a short description (label) so that +# the client side can know what's what when rendering the streams. Notice +# how the port/pt/rtpmap/fmtp/etc. stuff is called just like that, without +# any audio/video/data prefix: in fact, each media stream can be configured +# the same way, and it's the type that allows us to differentiate them. +# As such, you can use the same approach for creating regular mountpoints +# as well (e.g., 1 audio and 1 video) in a much clearer, and cleaner, way. +# +multistream-test: { + type = "rtp" + id = 123 + description = "Multistream test (1 audio, 2 video)" + media = ( + { + type = "audio" + mid = "a" + label = "Audio stream" + port = 5102 + pt = 111 + rtpmap = "opus/48000/2" + }, + { + type = "video" + mid = "v1" + label = "Video stream #1" + port = 5104 + pt = 100 + rtpmap = "VP8/90000" + }, + { + type = "video" + mid = "v2" + label = "Video stream #2" + port = 5106 + pt = 100 + rtpmap = "VP8/90000" + } + ) + secret = "adminpwd" +} diff --git a/dtls-bio.c b/dtls-bio.c index 21eff3507c..1a76945a6a 100644 --- a/dtls-bio.c +++ b/dtls-bio.c @@ -3,7 +3,7 @@ * \copyright GNU General Public License v3 * \brief OpenSSL BIO agent writer * \details OpenSSL BIO that writes packets to a libnice agent. - * + * * \ingroup protocols * \ref protocols */ @@ -110,7 +110,7 @@ static int janus_dtls_bio_agent_free(BIO *bio) { #endif return 1; } - + static int janus_dtls_bio_agent_write(BIO *bio, const char *in, int inl) { JANUS_LOG(LOG_HUGE, "janus_dtls_bio_agent_write: %p, %d\n", in, inl); /* Forward data to the write BIO */ @@ -129,17 +129,12 @@ static int janus_dtls_bio_agent_write(BIO *bio, const char *in, int inl) { JANUS_LOG(LOG_ERR, "No DTLS-SRTP stack, no DTLS bridge...\n"); return -1; } - janus_ice_component *component = (janus_ice_component *)dtls->component; - if(component == NULL) { - JANUS_LOG(LOG_ERR, "No component, no DTLS bridge...\n"); - return -1; - } - janus_ice_stream *stream = component->stream; - if(!stream) { - JANUS_LOG(LOG_ERR, "No stream, no DTLS bridge...\n"); + janus_handle_webrtc *pc = (janus_handle_webrtc *)dtls->pc; + if(pc == NULL) { + JANUS_LOG(LOG_ERR, "No WebRTC PeerConnection, no DTLS bridge...\n"); return -1; } - janus_ice_handle *handle = stream->handle; + janus_handle *handle = pc->handle; if(!handle || !handle->agent || !dtls->write_bio) { JANUS_LOG(LOG_ERR, "No handle/agent/bio, no DTLS bridge...\n"); return -1; @@ -149,17 +144,17 @@ static int janus_dtls_bio_agent_write(BIO *bio, const char *in, int inl) { /* FIXME Just a warning for now, this will need to be solved with proper fragmentation */ JANUS_LOG(LOG_WARN, "[%"SCNu64"] The DTLS stack is trying to send a packet of %d bytes, this may be larger than the MTU and get dropped!\n", handle->handle_id, inl); } - int bytes = nice_agent_send(handle->agent, component->stream_id, component->component_id, inl, in); + int bytes = nice_agent_send(handle->agent, pc->stream_id, pc->component_id, inl, in); if(bytes < inl) { - JANUS_LOG(LOG_ERR, "[%"SCNu64"] Error sending DTLS message on component %d of stream %d (%d)\n", handle->handle_id, component->component_id, stream->stream_id, bytes); + JANUS_LOG(LOG_ERR, "[%"SCNu64"] Error sending DTLS message on component %d of stream %d (%d)\n", handle->handle_id, pc->component_id, pc->stream_id, bytes); } else { JANUS_LOG(LOG_HUGE, "[%"SCNu64"] >> >> ... and sent %d of those bytes on the socket\n", handle->handle_id, bytes); } /* Update stats (TODO Do the same for the last second window as well) * FIXME: the Data stats includes the bytes used for the handshake */ if(bytes > 0) { - component->out_stats.data.packets++; - component->out_stats.data.bytes += bytes; + pc->dtls_out_stats.info[0].packets++; + pc->dtls_out_stats.info[0].bytes += bytes; } return bytes; } diff --git a/dtls.c b/dtls.c index 7b201a763d..df3d9d8dd7 100644 --- a/dtls.c +++ b/dtls.c @@ -79,13 +79,10 @@ static void janus_dtls_notify_state_change(janus_dtls_srtp *dtls) { return; if(dtls == NULL) return; - janus_ice_component *component = (janus_ice_component *)dtls->component; - if(component == NULL) + janus_handle_webrtc *pc = (janus_handle_webrtc *)dtls->pc; + if(pc == NULL) return; - janus_ice_stream *stream = component->stream; - if(stream == NULL) - return; - janus_ice_handle *handle = stream->handle; + janus_handle *handle = pc->handle; if(handle == NULL) return; janus_session *session = (janus_session *)handle->session; @@ -93,8 +90,8 @@ static void janus_dtls_notify_state_change(janus_dtls_srtp *dtls) { return; json_t *info = json_object(); json_object_set_new(info, "dtls", json_string(janus_get_dtls_srtp_state(dtls->dtls_state))); - json_object_set_new(info, "stream_id", json_integer(stream->stream_id)); - json_object_set_new(info, "component_id", json_integer(component->component_id)); + json_object_set_new(info, "stream_id", json_integer(pc->stream_id)); + json_object_set_new(info, "component_id", json_integer(pc->component_id)); json_object_set_new(info, "retransmissions", json_integer(dtls->retransmissions)); janus_events_notify_handlers(JANUS_EVENT_TYPE_WEBRTC, session->session_id, handle->handle_id, handle->opaque_id, info); } @@ -444,7 +441,7 @@ gint janus_dtls_srtp_init(const char *server_pem, const char *server_key, const static void janus_dtls_srtp_free(const janus_refcount *dtls_ref) { janus_dtls_srtp *dtls = janus_refcount_containerof(dtls_ref, janus_dtls_srtp, ref); /* This stack can be destroyed, free all the resources */ - dtls->component = NULL; + dtls->pc = NULL; if(dtls->ssl != NULL) { SSL_free(dtls->ssl); dtls->ssl = NULL; @@ -486,18 +483,13 @@ void janus_dtls_srtp_cleanup(void) { } -janus_dtls_srtp *janus_dtls_srtp_create(void *ice_component, janus_dtls_role role) { - janus_ice_component *component = (janus_ice_component *)ice_component; - if(component == NULL) { - JANUS_LOG(LOG_ERR, "No component, no DTLS...\n"); - return NULL; - } - janus_ice_stream *stream = component->stream; - if(!stream) { - JANUS_LOG(LOG_ERR, "No stream, no DTLS...\n"); +janus_dtls_srtp *janus_dtls_srtp_create(void *webrtc, janus_dtls_role role) { + janus_handle_webrtc *pc = (janus_handle_webrtc *)webrtc; + if(pc == NULL) { + JANUS_LOG(LOG_ERR, "No WebRTC PeerConnection, no DTLS...\n"); return NULL; } - janus_ice_handle *handle = stream->handle; + janus_handle *handle = pc->handle; if(!handle || !handle->agent) { JANUS_LOG(LOG_ERR, "No handle/agent, no DTLS...\n"); return NULL; @@ -561,7 +553,7 @@ janus_dtls_srtp *janus_dtls_srtp_create(void *ice_component, janus_dtls_role rol #endif /* Done */ dtls->dtls_connected = 0; - dtls->component = component; + dtls->pc = pc; return dtls; } @@ -588,21 +580,18 @@ int janus_dtls_srtp_create_sctp(janus_dtls_srtp *dtls) { #ifdef HAVE_SCTP if(dtls == NULL) return -1; - janus_ice_component *component = (janus_ice_component *)dtls->component; - if(component == NULL) + janus_handle_webrtc *pc = (janus_handle_webrtc *)dtls->pc; + if(pc == NULL) return -2; - janus_ice_stream *stream = component->stream; - if(!stream) - return -3; - janus_ice_handle *handle = stream->handle; + janus_handle *handle = pc->handle; if(!handle || !handle->agent) + return -3; + if(janus_flags_is_set(&handle->webrtc_flags, JANUS_HANDLE_WEBRTC_ALERT)) return -4; - if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT)) - return -5; dtls->sctp = janus_sctp_association_create(dtls, handle, 5000); if(dtls->sctp == NULL) { JANUS_LOG(LOG_ERR, "[%"SCNu64"] Error creating SCTP association...\n", handle->handle_id); - return -6; + return -5; } return 0; #else @@ -616,27 +605,22 @@ void janus_dtls_srtp_incoming_msg(janus_dtls_srtp *dtls, char *buf, uint16_t len JANUS_LOG(LOG_ERR, "No DTLS-SRTP stack, no incoming message...\n"); return; } - janus_ice_component *component = (janus_ice_component *)dtls->component; - if(component == NULL) { - JANUS_LOG(LOG_ERR, "No component, no DTLS...\n"); - return; - } - janus_ice_stream *stream = component->stream; - if(!stream) { - JANUS_LOG(LOG_ERR, "No stream, no DTLS...\n"); + janus_handle_webrtc *pc = (janus_handle_webrtc *)dtls->pc; + if(pc == NULL) { + JANUS_LOG(LOG_ERR, "No WebRTC PeerConnection, no DTLS...\n"); return; } - janus_ice_handle *handle = stream->handle; + janus_handle *handle = pc->handle; if(!handle || !handle->agent) { JANUS_LOG(LOG_ERR, "No handle/agent, no DTLS...\n"); return; } - if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT)) { + if(janus_flags_is_set(&handle->webrtc_flags, JANUS_HANDLE_WEBRTC_ALERT)) { JANUS_LOG(LOG_WARN, "[%"SCNu64"] Alert already triggered, clearing up...\n", handle->handle_id); return; } if(!dtls->ssl || !dtls->read_bio) { - JANUS_LOG(LOG_ERR, "[%"SCNu64"] No DTLS stuff for component %d in stream %d??\n", handle->handle_id, component->component_id, stream->stream_id); + JANUS_LOG(LOG_ERR, "[%"SCNu64"] No DTLS stuff for component %d in stream %d??\n", handle->handle_id, pc->component_id, pc->stream_id); return; } if(dtls->dtls_started == 0) { @@ -664,7 +648,7 @@ void janus_dtls_srtp_incoming_msg(janus_dtls_srtp *dtls, char *buf, uint16_t len return; } } - if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_STOP) || janus_is_stopping()) { + if(janus_flags_is_set(&handle->webrtc_flags, JANUS_HANDLE_WEBRTC_STOP) || janus_is_stopping()) { /* DTLS alert triggered, we should end it here */ JANUS_LOG(LOG_VERB, "[%"SCNu64"] Forced to stop it here...\n", handle->handle_id); return; @@ -679,6 +663,14 @@ void janus_dtls_srtp_incoming_msg(janus_dtls_srtp *dtls, char *buf, uint16_t len JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Any data available?\n", handle->handle_id); #ifdef HAVE_SCTP if(dtls->sctp != NULL && read > 0) { + /* Update stats for the data medium */ + janus_handle_webrtc_medium *medium = g_hash_table_lookup(pc->media_bytype, + GINT_TO_POINTER(JANUS_MEDIA_DATA)); + if(medium != NULL) { + medium->in_stats.info[0].packets++; + medium->in_stats.info[0].bytes += read; + } + /* Pass the data to the SCTP stack */ JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Sending data (%d bytes) to the SCTP stack...\n", handle->handle_id, read); janus_sctp_data_from_dtls(dtls->sctp, data, read); } @@ -699,7 +691,7 @@ void janus_dtls_srtp_incoming_msg(janus_dtls_srtp *dtls, char *buf, uint16_t len unsigned char rfingerprint[EVP_MAX_MD_SIZE]; char remote_fingerprint[160]; char *rfp = (char *)&remote_fingerprint; - if(stream->remote_hashing && !strcasecmp(stream->remote_hashing, "sha-1")) { + if(pc->remote_hashing && !strcasecmp(pc->remote_hashing, "sha-1")) { JANUS_LOG(LOG_VERB, "[%"SCNu64"] Computing sha-1 fingerprint of remote certificate...\n", handle->handle_id); X509_digest(rcert, EVP_sha1(), (unsigned char *)rfingerprint, &rsize); } else { @@ -715,8 +707,8 @@ void janus_dtls_srtp_incoming_msg(janus_dtls_srtp *dtls, char *buf, uint16_t len } *(rfp-1) = 0; JANUS_LOG(LOG_VERB, "[%"SCNu64"] Remote fingerprint (%s) of the client is %s\n", - handle->handle_id, stream->remote_hashing ? stream->remote_hashing : "sha-256", remote_fingerprint); - if(!strcasecmp(remote_fingerprint, stream->remote_fingerprint ? stream->remote_fingerprint : "(none)")) { + handle->handle_id, pc->remote_hashing ? pc->remote_hashing : "sha-256", remote_fingerprint); + if(!strcasecmp(remote_fingerprint, pc->remote_fingerprint ? pc->remote_fingerprint : "(none)")) { JANUS_LOG(LOG_VERB, "[%"SCNu64"] Fingerprint is a match!\n", handle->handle_id); dtls->dtls_state = JANUS_DTLS_STATE_CONNECTED; dtls->dtls_connected = janus_get_monotonic_time(); @@ -724,7 +716,7 @@ void janus_dtls_srtp_incoming_msg(janus_dtls_srtp *dtls, char *buf, uint16_t len janus_dtls_notify_state_change(dtls); } else { /* FIXME NOT a match! MITM? */ - JANUS_LOG(LOG_ERR, "[%"SCNu64"] Fingerprint is NOT a match! got %s, expected %s\n", handle->handle_id, remote_fingerprint, stream->remote_fingerprint); + JANUS_LOG(LOG_ERR, "[%"SCNu64"] Fingerprint is NOT a match! got %s, expected %s\n", handle->handle_id, remote_fingerprint, pc->remote_fingerprint); dtls->dtls_state = JANUS_DTLS_STATE_FAILED; /* Notify event handlers */ janus_dtls_notify_state_change(dtls); @@ -776,7 +768,7 @@ void janus_dtls_srtp_incoming_msg(janus_dtls_srtp *dtls, char *buf, uint16_t len if(!SSL_export_keying_material(dtls->ssl, material, master_length*2, "EXTRACTOR-dtls_srtp", 19, NULL, 0, 0)) { /* Oops... */ JANUS_LOG(LOG_ERR, "[%"SCNu64"] Oops, couldn't extract SRTP keying material for component %d in stream %d?? (%s)\n", - handle->handle_id, component->component_id, stream->stream_id, ERR_reason_error_string(ERR_get_error())); + handle->handle_id, pc->component_id, pc->stream_id, ERR_reason_error_string(ERR_get_error())); goto done; } /* Key derivation (http://tools.ietf.org/html/rfc5764#section-4.2) */ @@ -866,23 +858,23 @@ void janus_dtls_srtp_incoming_msg(janus_dtls_srtp *dtls, char *buf, uint16_t len srtp_err_status_t res = srtp_create(&(dtls->srtp_in), &(dtls->remote_policy)); if(res != srtp_err_status_ok) { /* Something went wrong... */ - JANUS_LOG(LOG_ERR, "[%"SCNu64"] Oops, error creating inbound SRTP session for component %d in stream %d??\n", handle->handle_id, component->component_id, stream->stream_id); + JANUS_LOG(LOG_ERR, "[%"SCNu64"] Oops, error creating inbound SRTP session for component %d in stream %d??\n", handle->handle_id, pc->component_id, pc->stream_id); JANUS_LOG(LOG_ERR, "[%"SCNu64"] -- %d (%s)\n", handle->handle_id, res, janus_srtp_error_str(res)); goto done; } - JANUS_LOG(LOG_VERB, "[%"SCNu64"] Created inbound SRTP session for component %d in stream %d\n", handle->handle_id, component->component_id, stream->stream_id); + JANUS_LOG(LOG_VERB, "[%"SCNu64"] Created inbound SRTP session for component %d in stream %d\n", handle->handle_id, pc->component_id, pc->stream_id); res = srtp_create(&(dtls->srtp_out), &(dtls->local_policy)); if(res != srtp_err_status_ok) { /* Something went wrong... */ - JANUS_LOG(LOG_ERR, "[%"SCNu64"] Oops, error creating outbound SRTP session for component %d in stream %d??\n", handle->handle_id, component->component_id, stream->stream_id); + JANUS_LOG(LOG_ERR, "[%"SCNu64"] Oops, error creating outbound SRTP session for component %d in stream %d??\n", handle->handle_id, pc->component_id, pc->stream_id); JANUS_LOG(LOG_ERR, "[%"SCNu64"] -- %d (%s)\n", handle->handle_id, res, janus_srtp_error_str(res)); goto done; } dtls->srtp_profile = srtp_profile->id; dtls->srtp_valid = 1; - JANUS_LOG(LOG_VERB, "[%"SCNu64"] Created outbound SRTP session for component %d in stream %d\n", handle->handle_id, component->component_id, stream->stream_id); + JANUS_LOG(LOG_VERB, "[%"SCNu64"] Created outbound SRTP session for component %d in stream %d\n", handle->handle_id, pc->component_id, pc->stream_id); #ifdef HAVE_SCTP - if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_DATA_CHANNELS)) { + if(janus_flags_is_set(&handle->webrtc_flags, JANUS_HANDLE_WEBRTC_DATA_CHANNELS)) { /* Create SCTP association as well */ janus_dtls_srtp_create_sctp(dtls); } @@ -890,13 +882,13 @@ void janus_dtls_srtp_incoming_msg(janus_dtls_srtp *dtls, char *buf, uint16_t len dtls->ready = 1; } done: - if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT) && dtls->srtp_valid) { + if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_HANDLE_WEBRTC_ALERT) && dtls->srtp_valid) { /* Handshake successfully completed */ - janus_ice_dtls_handshake_done(handle, component); + janus_handle_dtls_handshake_done(handle); } else { /* Something went wrong in either DTLS or SRTP... tell the plugin about it */ janus_dtls_callback(dtls->ssl, SSL_CB_ALERT, 0); - janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_CLEANING); + janus_flags_set(&handle->webrtc_flags, JANUS_HANDLE_WEBRTC_CLEANING); } } } @@ -939,23 +931,18 @@ void janus_dtls_callback(const SSL *ssl, int where, int ret) { JANUS_LOG(LOG_ERR, "No DTLS session related to this alert...\n"); return; } - janus_ice_component *component = dtls->component; - if(component == NULL) { - JANUS_LOG(LOG_ERR, "No ICE component related to this alert...\n"); - return; - } - janus_ice_stream *stream = component->stream; - if(!stream) { - JANUS_LOG(LOG_ERR, "No ICE stream related to this alert...\n"); + janus_handle_webrtc *pc = (janus_handle_webrtc *)dtls->pc; + if(pc == NULL) { + JANUS_LOG(LOG_ERR, "No WebRTC PeerConnection related to this alert...\n"); return; } - janus_ice_handle *handle = stream->handle; + janus_handle *handle = pc->handle; if(!handle) { JANUS_LOG(LOG_ERR, "No ICE handle related to this alert...\n"); return; } - JANUS_LOG(LOG_VERB, "[%"SCNu64"] DTLS alert triggered on stream %u (component %u), closing...\n", handle->handle_id, stream->stream_id, component->component_id); - janus_ice_webrtc_hangup(handle, "DTLS alert"); + JANUS_LOG(LOG_VERB, "[%"SCNu64"] DTLS alert triggered on stream %u (component %u), closing...\n", handle->handle_id, pc->stream_id, pc->component_id); + janus_handle_webrtc_hangup(handle, "DTLS alert"); } /* DTLS certificate verification callback */ @@ -974,10 +961,23 @@ void janus_dtls_wrap_sctp_data(janus_dtls_srtp *dtls, char *label, char *buf, in int janus_dtls_send_sctp_data(janus_dtls_srtp *dtls, char *buf, int len) { if(dtls == NULL || !dtls->ready || buf == NULL || len < 1) return -1; + janus_handle_webrtc *pc = (janus_handle_webrtc *)dtls->pc; + if(pc == NULL) { + JANUS_LOG(LOG_ERR, "No WebRTC PeerConnection related to this data...\n"); + return -2; + } int res = SSL_write(dtls->ssl, buf, len); if(res <= 0) { unsigned long err = SSL_get_error(dtls->ssl, res); JANUS_LOG(LOG_ERR, "Error sending data: %s\n", ERR_reason_error_string(err)); + } else { + /* Update stats for the data medium */ + janus_handle_webrtc_medium *medium = g_hash_table_lookup(pc->media_bytype, + GINT_TO_POINTER(JANUS_MEDIA_DATA)); + if(medium != NULL) { + medium->out_stats.info[0].packets++; + medium->out_stats.info[0].bytes += res; + } } return res; } @@ -985,17 +985,12 @@ int janus_dtls_send_sctp_data(janus_dtls_srtp *dtls, char *buf, int len) { void janus_dtls_notify_data(janus_dtls_srtp *dtls, char *label, char *buf, int len) { if(dtls == NULL || buf == NULL || len < 1) return; - janus_ice_component *component = (janus_ice_component *)dtls->component; - if(component == NULL) { - JANUS_LOG(LOG_ERR, "No component...\n"); + janus_handle_webrtc *pc = (janus_handle_webrtc *)dtls->pc; + if(pc == NULL) { + JANUS_LOG(LOG_ERR, "No WebRTC PeerConnection...\n"); return; } - janus_ice_stream *stream = component->stream; - if(!stream) { - JANUS_LOG(LOG_ERR, "No stream...\n"); - return; - } - janus_ice_handle *handle = stream->handle; + janus_handle *handle = pc->handle; if(!handle || !handle->agent || !dtls->write_bio) { JANUS_LOG(LOG_ERR, "No handle...\n"); return; @@ -1008,16 +1003,13 @@ gboolean janus_dtls_retry(gpointer stack) { janus_dtls_srtp *dtls = (janus_dtls_srtp *)stack; if(dtls == NULL) return FALSE; - janus_ice_component *component = (janus_ice_component *)dtls->component; - if(component == NULL) - return FALSE; - janus_ice_stream *stream = component->stream; - if(!stream) + janus_handle_webrtc *pc = (janus_handle_webrtc *)dtls->pc; + if(pc == NULL) goto stoptimer; - janus_ice_handle *handle = stream->handle; + janus_handle *handle = pc->handle; if(!handle) goto stoptimer; - if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_STOP)) + if(janus_flags_is_set(&handle->webrtc_flags, JANUS_HANDLE_WEBRTC_STOP)) goto stoptimer; if(dtls->dtls_state == JANUS_DTLS_STATE_CONNECTED) { JANUS_LOG(LOG_VERB, "[%"SCNu64"] DTLS already set up, disabling retransmission timer!\n", handle->handle_id); @@ -1026,8 +1018,8 @@ gboolean janus_dtls_retry(gpointer stack) { if(janus_get_monotonic_time() - dtls->dtls_started >= 20*G_USEC_PER_SEC) { /* FIXME Should we really give up after 20 seconds waiting for DTLS? */ JANUS_LOG(LOG_ERR, "[%"SCNu64"] DTLS taking too much time for component %d in stream %d...\n", - handle->handle_id, component->component_id, stream->stream_id); - janus_ice_webrtc_hangup(handle, "DTLS timeout"); + handle->handle_id, pc->component_id, pc->stream_id); + janus_handle_webrtc_hangup(handle, "DTLS timeout"); goto stoptimer; } struct timeval timeout = {0}; @@ -1039,7 +1031,7 @@ gboolean janus_dtls_retry(gpointer stack) { JANUS_LOG(LOG_HUGE, "[%"SCNu64"] DTLSv1_get_timeout: %"SCNu64"\n", handle->handle_id, timeout_value); if(timeout_value == 0) { dtls->retransmissions++; - JANUS_LOG(LOG_VERB, "[%"SCNu64"] DTLS timeout on component %d of stream %d, retransmitting\n", handle->handle_id, component->component_id, stream->stream_id); + JANUS_LOG(LOG_VERB, "[%"SCNu64"] DTLS timeout on component %d of stream %d, retransmitting\n", handle->handle_id, pc->component_id, pc->stream_id); /* Notify event handlers */ janus_dtls_notify_state_change(dtls); /* Retransmit the packet */ @@ -1048,10 +1040,10 @@ gboolean janus_dtls_retry(gpointer stack) { return TRUE; stoptimer: - if(component->dtlsrt_source != NULL) { - g_source_destroy(component->dtlsrt_source); - g_source_unref(component->dtlsrt_source); - component->dtlsrt_source = NULL; + if(pc->dtlsrt_source != NULL) { + g_source_destroy(pc->dtlsrt_source); + g_source_unref(pc->dtlsrt_source); + pc->dtlsrt_source = NULL; } return FALSE; } diff --git a/dtls.h b/dtls.h index d095b1a2cf..6c25924924 100644 --- a/dtls.h +++ b/dtls.h @@ -58,8 +58,8 @@ typedef enum janus_dtls_state { /*! \brief Janus DTLS-SRTP handle */ typedef struct janus_dtls_srtp { - /*! \brief Opaque pointer to the component this DTLS-SRTP context belongs to */ - void *component; + /*! \brief Opaque pointer to the WebRTC PeerConnection this DTLS-SRTP context belongs to */ + void *pc; /*! \brief DTLS role of the server for this stream: 1=client, 0=server */ janus_dtls_role dtls_role; /*! \brief DTLS state of this component: -1=failed, 0=nothing, 1=trying, 2=connected */ @@ -102,10 +102,10 @@ typedef struct janus_dtls_srtp { /*! \brief Create a janus_dtls_srtp instance - * @param[in] component Opaque pointer to the component owning that will use the stack + * @param[in] webrtc Opaque pointer to the WebRTC PeerConnection owning that will use the stack * @param[in] role The role of the DTLS stack (client/server) * @returns A new janus_dtls_srtp instance if successful, NULL otherwise */ -janus_dtls_srtp *janus_dtls_srtp_create(void *component, janus_dtls_role role); +janus_dtls_srtp *janus_dtls_srtp_create(void *webrtc, janus_dtls_role role); /*! \brief Start a DTLS handshake * @param[in] dtls The janus_dtls_srtp instance to start the handshake on */ void janus_dtls_srtp_handshake(janus_dtls_srtp *dtls); diff --git a/events.c b/events.c index b22907fbbc..c8f9d298e7 100644 --- a/events.c +++ b/events.c @@ -58,6 +58,7 @@ int janus_events_init(gboolean enabled, char *server_name, GHashTable *handlers) g_free(server); g_async_queue_unref(events); JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the Events handler thread...\n", error->code, error->message ? error->message : "??"); + g_error_free(error); return -1; } } diff --git a/events/janus_mqttevh.c b/events/janus_mqttevh.c index 0772191f31..d5352abdee 100644 --- a/events/janus_mqttevh.c +++ b/events/janus_mqttevh.c @@ -820,6 +820,7 @@ static int janus_mqttevh_init(const char *config_path) { if(error != NULL) { g_atomic_int_set(&initialized, 0); JANUS_LOG(LOG_FATAL, "Got error %d (%s) trying to launch the MQTT EventHandler handler thread...\n", error->code, error->message ? error->message : "??"); + g_error_free(error); goto error; } diff --git a/events/janus_rabbitmqevh.c b/events/janus_rabbitmqevh.c index 0cae51db91..758e0f1a7a 100644 --- a/events/janus_rabbitmqevh.c +++ b/events/janus_rabbitmqevh.c @@ -349,6 +349,7 @@ int janus_rabbitmqevh_init(const char *config_path) { if(error != NULL) { g_atomic_int_set(&initialized, 0); JANUS_LOG(LOG_FATAL, "Got error %d (%s) trying to launch the RabbitMQEventHandler handler thread...\n", error->code, error->message ? error->message : "??"); + g_error_free(error); goto error; } diff --git a/events/janus_sampleevh.c b/events/janus_sampleevh.c index c6b09d6a6b..23fd633f2a 100644 --- a/events/janus_sampleevh.c +++ b/events/janus_sampleevh.c @@ -244,6 +244,7 @@ int janus_sampleevh_init(const char *config_path) { if(error != NULL) { g_atomic_int_set(&initialized, 0); JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the SampleEventHandler handler thread...\n", error->code, error->message ? error->message : "??"); + g_error_free(error); return -1; } JANUS_LOG(LOG_INFO, "%s initialized!\n", JANUS_SAMPLEEVH_NAME); diff --git a/html/audiobridgetest.js b/html/audiobridgetest.js index e091def17f..1bd96906e5 100644 --- a/html/audiobridgetest.js +++ b/html/audiobridgetest.js @@ -52,6 +52,7 @@ var janus = null; var mixertest = null; var opaqueId = "audiobridgetest-"+Janus.randomString(12); +var remoteStream = null; var spinner = null; var myroom = 1234; // Demo room @@ -120,6 +121,19 @@ $(document).ready(function() { $.unblockUI(); } }, + iceState: function(state) { + Janus.log("ICE state changed to " + state); + }, + mediaState: function(medium, on, mid) { + Janus.log("Janus " + (on ? "started" : "stopped") + " receiving our " + medium + " (mid=" + mid + ")"); + }, + webrtcState: function(on) { + Janus.log("Janus says our WebRTC PeerConnection is " + (on ? "up" : "down") + " now"); + }, + slowLink: function(uplink, lost, mid) { + Janus.warn("Janus reports problems " + (uplink ? "sending" : "receiving") + + " packets on mid " + mid + " (" + lost + " lost packets)"); + }, onmessage: function(msg, jsep) { Janus.debug(" ::: Got a message :::"); Janus.debug(msg); @@ -273,24 +287,42 @@ $(document).ready(function() { mixertest.handleRemoteJsep({jsep: jsep}); } }, - onlocalstream: function(stream) { - Janus.debug(" ::: Got a local stream :::"); - Janus.debug(stream); + onlocaltrack: function(track, on) { + Janus.debug(" ::: Got a local track event :::"); + Janus.debug("Local track " + (on ? "added" : "removed") + ":", track); // We're not going to attach the local audio stream $('#audiojoin').hide(); $('#room').removeClass('hide').show(); $('#participant').removeClass('hide').html(myusername).show(); }, - onremotestream: function(stream) { + onremotetrack: function(track, mid, on) { + Janus.debug(" ::: Got a remote track event :::"); + Janus.debug("Remote track (mid=" + mid + ") " + (on ? "added" : "removed") + ":", track); + if(remoteStream || track.kind !== "audio") + return; + if(!on) { + // Track removed, get rid of the stream and the rendering + if(remoteStream) { + try { + var tracks = remoteStream.getTracks(); + for(var i in tracks) { + var mst = tracks[i]; + if(mst !== null && mst !== undefined) + mst.stop(); + } + } catch(e) {} + } + remoteStream = null; + $('#roomaudio').remove(); + return; + } + remoteStream = new MediaStream(); + remoteStream.addTrack(track.clone()); $('#room').removeClass('hide').show(); - var addButtons = false; if($('#roomaudio').length === 0) { - addButtons = true; $('#mixedaudio').append('