Skip to content

Commit

Permalink
Several fixes
Browse files Browse the repository at this point in the history
Improved DTLS timer and retransmissions;
Added a helper to parse on/off configuration values;
Added API command to enable/disable streaming mountpoints;
Added a (commented) H.264 sample mountpoint to the streaming configuration;
Improved SSRC multiplexing in the Video MCU;
Added a new way to trigger the end of trickle candidates;
Some more fixes here and there
  • Loading branch information
meetecho committed Oct 14, 2014
1 parent bf24339 commit 6dd1c12
Show file tree
Hide file tree
Showing 15 changed files with 293 additions and 116 deletions.
2 changes: 1 addition & 1 deletion conf/janus.plugin.audiobridge.cfg.sample
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
; description = This is my awesome room
; secret = <password needed for manipulating (e.g. destroying) the room>
; sampling_rate = <sampling rate> (e.g., 16000 for wideband mixing)
; record = true|false ( (whether this room should be recorded, default=false)
; record = true|false (whether this room should be recorded, default=false)
; record_file = /path/to/recording.wav (where to save the recording)

[1234]
Expand Down
23 changes: 23 additions & 0 deletions conf/janus.plugin.streaming.cfg.sample.in
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
; (multiple listeners = different streaming contexts)
; id = <unique numeric ID> (if missing, a random one will be generated)
; description = This is my awesome stream
; secret = <optional password needed for manipulating (e.g., destroying
; or enabling/disabling) the stream>
; filename = path to the local file to stream (only for live/ondemand)
; audio = yes|no (do/don't stream audio)
; video = yes|no (do/don't stream video)
Expand Down Expand Up @@ -37,6 +39,7 @@ audiortpmap = opus/48000/2
videoport = 5004
videopt = 100
videortpmap = VP8/90000
secret = adminpwd

[file-live-sample]
type = live
Expand All @@ -45,6 +48,7 @@ description = a-law file source (radio broadcast)
filename = @streamdir@/radio.alaw ; See install.sh
audio = yes
video = no
secret = adminpwd

[file-ondemand-sample]
type = ondemand
Expand All @@ -53,3 +57,22 @@ description = mu-law file source (music)
filename = @streamdir@/music.mulaw ; See install.sh
audio = yes
video = no
secret = adminpwd

;
; Firefox Nightly supports H.264 through Cisco's OpenH264 plugin. The only
; supported profile is the baseline one. This is an example of how to create
; a H.264 mountpoint: you can feed it an x264enc+rtph264pay pipeline in
; gstreamer.
;
;[h264-sample]
;type = rtp
;id = 10
;description = H.264 live stream coming from gstreamer
;audio = no
;video = yes
;videoport = 8004
;videopt = 126
;videortpmap = H264/90000
;videofmtp = profile-level-id=42e01f\;packetization-mode=1

43 changes: 8 additions & 35 deletions dtls.c
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,6 @@ janus_dtls_srtp *janus_dtls_srtp_create(void *ice_component, janus_dtls_role rol
}
/* Create SSL context, at last */
dtls->srtp_valid = 0;
dtls->dtls_last_msg = NULL;
dtls->dtls_last_len = 0;
dtls->ssl = SSL_new(janus_dtls_get_ssl_ctx());
if(!dtls->ssl) {
JANUS_LOG(LOG_ERR, "[%"SCNu64"] No component DTLS SSL session??\n", handle->handle_id);
Expand Down Expand Up @@ -281,12 +279,6 @@ void janus_dtls_srtp_incoming_msg(janus_dtls_srtp *dtls, char *buf, uint16_t len
JANUS_LOG(LOG_ERR, "[%"SCNu64"] No DTLS stuff for component %d in stream %d??\n", handle->handle_id, component->component_id, stream->stream_id);
return;
}
/* We just got a message, can we get rid of the last sent message? */
if(dtls->dtls_last_msg != NULL) {
g_free(dtls->dtls_last_msg);
dtls->dtls_last_msg = NULL;
dtls->dtls_last_len = 0;
}
janus_dtls_fd_bridge(dtls);
int written = BIO_write(dtls->read_bio, buf, len);
JANUS_LOG(LOG_HUGE, " Written %d of those bytes on the read BIO...\n", written);
Expand Down Expand Up @@ -490,10 +482,6 @@ void janus_dtls_srtp_destroy(janus_dtls_srtp *dtls) {
}
/* FIXME What about dtls->remote_policy and dtls->local_policy? */
}
if(dtls->dtls_last_msg != NULL) {
g_free(dtls->dtls_last_msg);
dtls->dtls_last_msg = NULL;
}
g_free(dtls);
dtls = NULL;
}
Expand Down Expand Up @@ -580,20 +568,6 @@ void janus_dtls_fd_bridge(janus_dtls_srtp *dtls) {
JANUS_LOG(LOG_HUGE, "[%"SCNu64"] >> >> Read %d bytes from the write_BIO...\n", handle->handle_id, pending);
int bytes = nice_agent_send(handle->agent, component->stream_id, component->component_id, out, outgoing);
JANUS_LOG(LOG_HUGE, "[%"SCNu64"] >> >> ... and sent %d of those bytes on the socket\n", handle->handle_id, bytes);

/* Take note of the last sent message */
if(dtls->dtls_last_msg != NULL) {
g_free(dtls->dtls_last_msg);
dtls->dtls_last_msg = NULL;
dtls->dtls_last_len = 0;
}
dtls->dtls_last_msg = calloc(pending, sizeof(char));
if(dtls->dtls_last_msg == NULL) {
JANUS_LOG(LOG_FATAL, "Memory error!\n");
return;
}
memcpy(dtls->dtls_last_msg, &outgoing, out);
dtls->dtls_last_len = out;
}
}

Expand Down Expand Up @@ -654,19 +628,18 @@ gboolean janus_dtls_retry(gpointer stack) {
return FALSE;
if(janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_STOP))
return FALSE;
//~ struct timeval timeout;
//~ DTLSv1_get_timeout(dtls->ssl, &timeout);
//~ JANUS_LOG(LOG_VERB, "[%"SCNu64"] DTLSv1_get_timeout: %"SCNu64"\n", handle->handle_id, timeout.tv_sec*1000000+timeout.tv_usec);
//~ DTLSv1_handle_timeout(dtls->ssl);
//~ janus_dtls_fd_bridge(dtls);
JANUS_LOG(LOG_VERB, "[%"SCNu64"] A second has passed on component %d of stream %d\n", handle->handle_id, component->component_id, stream->stream_id);
if(dtls->dtls_state == JANUS_DTLS_STATE_CONNECTED) {
JANUS_LOG(LOG_VERB, "[%"SCNu64"] DTLS already set up, disabling retransmission timer!\n", handle->handle_id);
return FALSE;
}
if(dtls->dtls_last_msg != NULL) {
JANUS_LOG(LOG_VERB, "[%"SCNu64"] Retransmitting last message (len=%d)\n", handle->handle_id, dtls->dtls_last_len);
nice_agent_send(handle->agent, component->stream_id, component->component_id, dtls->dtls_last_len, dtls->dtls_last_msg);
struct timeval timeout;
DTLSv1_get_timeout(dtls->ssl, &timeout);
guint64 timeout_value = timeout.tv_sec*1000 + timeout.tv_usec/1000;
JANUS_LOG(LOG_VERB, "[%"SCNu64"] DTLSv1_get_timeout: %"SCNu64"\n", handle->handle_id, timeout_value);
if(timeout_value == 0) {
JANUS_LOG(LOG_VERB, "[%"SCNu64"] DTLS timeout on component %d of stream %d, retransmitting\n", handle->handle_id, component->component_id, stream->stream_id);
DTLSv1_handle_timeout(dtls->ssl);
janus_dtls_fd_bridge(dtls);
}
return TRUE;
}
Expand Down
5 changes: 0 additions & 5 deletions dtls.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,6 @@ typedef struct janus_dtls_srtp {
srtp_policy_t local_policy;
/*! \brief Mutex to lock/unlock this libsrtp context */
janus_mutex srtp_mutex;
/*! \brief Buffer of the last message the DTLS client tried to send (needed for retransmissions) */
char *dtls_last_msg;
/*! \brief Length of the last message the DTLS client tried to send (needed for retransmissions) */
gint dtls_last_len;
/*! \brief Whether this DTLS stack is now ready to be used for messages as well (e.g., SCTP encapsulation) */
int ready;
#ifdef HAVE_SCTP
Expand Down Expand Up @@ -148,7 +144,6 @@ void janus_dtls_notify_data(janus_dtls_srtp *dtls, char *buf, int len);

/*! \brief DTLS retransmission timer
* \details As libnice is going to actually send and receive data, OpenSSL cannot handle retransmissions by itself: this timed callback (g_source_set_callback) deals with this.
* \todo Improve the rough mechanics implemented here by using DTLSv1_get_timeout() and DTLSv1_handle_timeout() to handle timeout and re-transmissions.
* @param[in] stack Opaque pointer to the janus_dtls_srtp instance to use
* @returns true if a retransmission is still needed, false otherwise */
gboolean janus_dtls_retry(gpointer stack);
Expand Down
2 changes: 1 addition & 1 deletion html/janus.js
Original file line number Diff line number Diff line change
Expand Up @@ -886,7 +886,7 @@ function Janus(gatewayCallbacks) {
config.iceDone = true;
if(config.trickle === true) {
// Notify end of candidates
sendTrickleCandidate(handleId, null);
sendTrickleCandidate(handleId, {"completed": true});
} else {
// No trickle, time to send the complete SDP (including all candidates)
sendSDP(handleId, callbacks);
Expand Down
9 changes: 4 additions & 5 deletions ice.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ gint janus_ice_init(gchar *stun_server, uint16_t stun_port, uint16_t rtp_min_por
return 0; /* No initialization needed */
if(stun_port == 0)
stun_port = 3478;
/*! \todo The RTP/RTCP port range configuration may be just a placeholder: for
/*! \note The RTP/RTCP port range configuration may be just a placeholder: for
* instance, libnice supports this since 0.1.0, but the 0.1.3 on Fedora fails
* when linking with an undefined reference to \c nice_agent_set_port_range
* so this is checked by the install.sh script in advance. */
Expand Down Expand Up @@ -595,7 +595,7 @@ void janus_ice_cb_component_state_changed(NiceAgent *agent, guint stream_id, gui
return;
}
/* Create retransmission timer */
component->source = g_timeout_source_new_seconds(1);
component->source = g_timeout_source_new(500);
g_source_set_callback(component->source, janus_dtls_retry, component->dtls, NULL);
guint id = g_source_attach(component->source, handle->icectx);
JANUS_LOG(LOG_VERB, "[%"SCNu64"] Creating retransmission timer with ID %u\n", handle->handle_id, id);
Expand Down Expand Up @@ -681,7 +681,7 @@ void janus_ice_cb_nice_recv(NiceAgent *agent, guint stream_id, guint component_i
//~ JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Got an RTP packet (%s stream)!\n", handle->handle_id,
//~ janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE) ? "bundled" : (stream->stream_id == handle->audio_id ? "audio" : "video"));
if(!component->dtls || !component->dtls->srtp_valid) {
JANUS_LOG(LOG_ERR, "[%"SCNu64"] Missing valid SRTP session, skipping...\n", handle->handle_id);
JANUS_LOG(LOG_WARN, "[%"SCNu64"] Missing valid SRTP session (packet arrived too early?), skipping...\n", handle->handle_id);
} else {
int buflen = len;
err_status_t res = srtp_unprotect(component->dtls->srtp_in, buf, &buflen);
Expand Down Expand Up @@ -726,7 +726,7 @@ void janus_ice_cb_nice_recv(NiceAgent *agent, guint stream_id, guint component_i
JANUS_LOG(LOG_HUGE, "[%"SCNu64"] Got an RTCP packet (%s stream)!\n", handle->handle_id,
janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE) ? "bundled" : (stream->stream_id == handle->audio_id ? "audio" : "video"));
if(!component->dtls || !component->dtls->srtp_valid) {
JANUS_LOG(LOG_ERR, "[%"SCNu64"] Missing valid SRTP session, skipping...\n", handle->handle_id);
JANUS_LOG(LOG_WARN, "[%"SCNu64"] Missing valid SRTP session (packet arrived too early?), skipping...\n", handle->handle_id);
} else {
int buflen = len;
err_status_t res = srtp_unprotect_rtcp(component->dtls->srtp_in, buf, &buflen);
Expand Down Expand Up @@ -771,7 +771,6 @@ void janus_ice_cb_nice_recv(NiceAgent *agent, guint stream_id, guint component_i
pkt->control = FALSE;
pkt->encrypted = TRUE; /* This was already encrypted before */
g_async_queue_push(handle->queued_packets, pkt);
//~ nice_agent_send(handle->agent, stream->stream_id, component->component_id, p->length, p->data);
}
}
rp = rp->next;
Expand Down
18 changes: 9 additions & 9 deletions janus.c
Original file line number Diff line number Diff line change
Expand Up @@ -1336,7 +1336,7 @@ int janus_process_incoming_request(janus_request_source *source, json_t *root) {
}
if(candidate != NULL) {
/* We got a single candidate */
if(!json_is_object(candidate)) {
if(!json_is_object(candidate) || json_object_get(candidate, "completed") != NULL) {
JANUS_LOG(LOG_INFO, "No more remote candidates for handle %"SCNu64"!\n", handle->handle_id);
janus_mutex_lock(&handle->mutex);
janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALL_TRICKLES);
Expand Down Expand Up @@ -1461,7 +1461,7 @@ int janus_process_incoming_request(janus_request_source *source, json_t *root) {
size_t i = 0;
for(i=0; i<json_array_size(candidates); i++) {
json_t *candidate = json_array_get(candidates, i);
if(candidate == NULL || !json_is_object(candidate)) {
if(candidate == NULL || !json_is_object(candidate) || json_object_get(candidate, "completed") != NULL) {
/* A 'NULL' candidate is our cue */
last_candidate = TRUE;
continue;
Expand Down Expand Up @@ -3875,7 +3875,7 @@ gint main(int argc, char *argv[])
}
}
item = janus_config_get_item_drilldown(config, "webserver", "http");
if(item && item->value && !strcasecmp(item->value, "no")) {
if(!item || !item->value || !janus_is_true(item->value)) {
JANUS_LOG(LOG_WARN, "HTTP webserver disabled\n");
} else {
int wsport = 8088;
Expand Down Expand Up @@ -3915,7 +3915,7 @@ gint main(int argc, char *argv[])
/* Do we also have to provide an HTTPS one? */
char *cert_pem_bytes = NULL, *cert_key_bytes = NULL;
item = janus_config_get_item_drilldown(config, "webserver", "https");
if(item && item->value && !strcasecmp(item->value, "no")) {
if(!item || !item->value || !janus_is_true(item->value)) {
JANUS_LOG(LOG_WARN, "HTTPS webserver disabled\n");
} else {
item = janus_config_get_item_drilldown(config, "webserver", "secure_port");
Expand Down Expand Up @@ -4009,7 +4009,7 @@ gint main(int argc, char *argv[])
JANUS_LOG(LOG_WARN, "WebSockets support not compiled\n");
#else
item = janus_config_get_item_drilldown(config, "webserver", "ws");
if(item && item->value && !strcasecmp(item->value, "no")) {
if(!item || !item->value || !janus_is_true(item->value)) {
JANUS_LOG(LOG_WARN, "WebSockets server disabled\n");
} else {
int wsport = 8188;
Expand All @@ -4032,7 +4032,7 @@ gint main(int argc, char *argv[])
janus_mutex_init(&wss_mutex);
}
item = janus_config_get_item_drilldown(config, "webserver", "ws_ssl");
if(!item || !item->value || !strcasecmp(item->value, "no")) {
if(!item || !item->value || !janus_is_true(item->value)) {
JANUS_LOG(LOG_WARN, "Secure WebSockets server disabled\n");
} else {
if(wss != NULL) {
Expand Down Expand Up @@ -4065,7 +4065,7 @@ gint main(int argc, char *argv[])
JANUS_LOG(LOG_WARN, "RabbitMQ support not compiled\n");
#else
item = janus_config_get_item_drilldown(config, "rabbitmq", "enable");
if(!item || !item->value || !strcasecmp(item->value, "no")) {
if(!item || !item->value || !janus_is_true(item->value)) {
JANUS_LOG(LOG_WARN, "RammitMQ support disabled\n");
} else {
/* Parse configuration */
Expand Down Expand Up @@ -4211,7 +4211,7 @@ gint main(int argc, char *argv[])
}
}
item = janus_config_get_item_drilldown(config, "admin", "admin_http");
if(item && item->value && !strcasecmp(item->value, "no")) {
if(!item || !item->value || !janus_is_true(item->value)) {
JANUS_LOG(LOG_WARN, "Admin/monitor HTTP webserver disabled\n");
} else {
int wsport = 7088;
Expand Down Expand Up @@ -4250,7 +4250,7 @@ gint main(int argc, char *argv[])
}
/* Do we also have to provide an HTTPS one? */
item = janus_config_get_item_drilldown(config, "admin", "admin_https");
if(item && item->value && !strcasecmp(item->value, "no")) {
if(!item || !item->value || !janus_is_true(item->value)) {
JANUS_LOG(LOG_WARN, "Admin/monitor HTTPS webserver disabled\n");
} else {
item = janus_config_get_item_drilldown(config, "admin", "admin_secure_port");
Expand Down
1 change: 0 additions & 1 deletion mutex.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
* \author Lorenzo Miniero <[email protected]>
* \brief Semaphors and Mutexes
* \details Implementation (based on pthread) of a locking mechanism based on mutexes.
* \todo This is mostly unused right now, involve mutexes more in later versions.
*
* \ingroup core
* \ref core
Expand Down
4 changes: 2 additions & 2 deletions plugins/janus_audiobridge.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
description = This is my awesome room
secret = <password needed for manipulating (e.g. destroying) the room>
sampling_rate = <sampling rate> (e.g., 16000 for wideband mixing)
record = yes/no (if yes, a raw mix of the recording will be saved)
record = true|false (whether this room should be recorded, default=false)
record_file = /path/to/recording.wav (where to save the recording)
\endverbatim
*
Expand Down Expand Up @@ -309,7 +309,7 @@ int janus_audiobridge_init(janus_callbacks *callback, const char *config_path) {
audiobridge->room_secret = g_strdup(secret->value);
}
audiobridge->record = FALSE;
if(record && record->value && !strcasecmp(record->value, "yes"))
if(record && record->value && janus_is_true(record->value))
audiobridge->record = TRUE;
if(recfile && recfile->value)
audiobridge->record_file = g_strdup(recfile->value);
Expand Down
6 changes: 3 additions & 3 deletions plugins/janus_sip.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
* need to fork in the same place. This specific functionality, though, has
* not been implemented as of yet.
*
* \todo Only Asterisk has been tested as a SIP server (which explains why
* the plugin talks of extensions and not generic SIP URIs), and specifically
* only basic audio calls have been tested: this plugin needs a lot of work.
* \todo Only Asterisk and Kamailio have been tested as a SIP server, and
* specifically only with basic audio calls: this plugin needs some work
* to make it more stable and reliable.
*
* \ingroup plugins
* \ref plugins
Expand Down
Loading

0 comments on commit 6dd1c12

Please sign in to comment.