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('');
}
- Janus.attachMediaStream($('#roomaudio').get(0), stream);
- if(!addButtons)
- return;
+ Janus.attachMediaStream($('#roomaudio').get(0), remoteStream);
// Mute button
audioenabled = true;
$('#toggleaudio').click(
@@ -311,6 +343,7 @@ $(document).ready(function() {
$('#list').empty();
$('#mixedaudio').empty();
$('#room').hide();
+ remoteStream = null;
}
});
},
diff --git a/html/demos.html b/html/demos.html
index 89a56e71ff..ac2d4650ae 100644
--- a/html/demos.html
+++ b/html/demos.html
@@ -20,7 +20,7 @@
-
+