Revision 486455a0

View differences:

html/sipretest.js
206 206
										} else if(event === 'incomingcall') {
207 207
											Janus.log("Incoming call from " + result["displayname"] + " (" + result["username"] + ")!");
208 208
											var doAudio = true, doVideo = true;
209
											var offerlessInvite = false;
209 210
											if(jsep !== null && jsep !== undefined) {
210 211
												// What has been negotiated?
211 212
												doAudio = (jsep.sdp.indexOf("m=audio ") > -1);
212 213
												doVideo = (jsep.sdp.indexOf("m=video ") > -1);
213 214
												Janus.debug("Audio " + (doAudio ? "has" : "has NOT") + " been negotiated");
214 215
												Janus.debug("Video " + (doVideo ? "has" : "has NOT") + " been negotiated");
216
											} else {
217
												Janus.log("This call doesn't contain an offer... we'll need to provide one ourselves");
218
												offerlessInvite = true;
219
												// In case you want to offer video when reacting to an offerless call, set this to true
220
												doVideo = false;
215 221
											}
216 222
											// Any security offered? A missing "srtp" attribute means plain RTP
217 223
											var rtpType = "";
......
222 228
												rtpType = " (SDES-SRTP mandatory)";
223 229
											// Notify user
224 230
											bootbox.hideAll();
231
											var extra = "";
232
											if(offerlessInvite)
233
												extra = " (no SDP offer provided)";
225 234
											incoming = bootbox.dialog({
226
												message: "Incoming call from " + result["displayname"] + " (" + result["username"] + ")!" + rtpType,
235
												message: "Incoming call from " + result["displayname"] + " (" + result["username"] + ")!" + rtpType + extra,
227 236
												title: "Incoming call",
228 237
												closeButton: false,
229 238
												buttons: {
......
233 242
														callback: function() {
234 243
															incoming = null;
235 244
															$('#peer').val(result["username"]).attr('disabled', true);
236
															sipcall.createAnswer(
245
															// Notice that we can only answer if we got an offer: if this was
246
															// an offerless call, we'll need to create an offer ourselves
247
															var sipcallAction = (offerlessInvite ? sipcall.createOffer : sipcall.createAnswer);
248
															sipcallAction(
237 249
																{
238 250
																	jsep: jsep,
239 251
																	media: { audio: doAudio, video: doVideo },
240 252
																	success: function(jsep) {
241
																		Janus.debug("Got SDP! audio=" + doAudio + ", video=" + doVideo);
253
																		Janus.debug("Got SDP " + jsep.type + "! audio=" + doAudio + ", video=" + doVideo);
242 254
																		Janus.debug(jsep);
243 255
																		var body = { request: "accept" };
244 256
																		// Note: as with "call", you can add a "srtp" attribute to
......
278 290
											});											
279 291
										} else if(event === 'accepted') {
280 292
											Janus.log(result["username"] + " accepted the call!");
281
											// TODO Video call can start
293
											Janus.log(jsep);
294
											// Call can start, now: handle the remote answer
282 295
											if(jsep !== null && jsep !== undefined) {
283 296
												sipcall.handleRemoteJsep({jsep: jsep, error: doHangup });
284 297
											}
plugins/janus_sipre.c
1253 1253
				video ? "video" : "audio",
1254 1254
				video ? session->media.video_ssrc : session->media.audio_ssrc);
1255 1255
		}
1256
		if((video && session->media.has_video && session->media.video_rtp_fd) ||
1257
				(!video && session->media.has_audio && session->media.audio_rtp_fd)) {
1256
		if((video && session->media.has_video && session->media.video_rtp_fd != -1) ||
1257
				(!video && session->media.has_audio && session->media.audio_rtp_fd != -1)) {
1258 1258
			/* Save the frame if we're recording */
1259 1259
			janus_recorder_save_frame(video ? session->vrc : session->arc, buf, len);
1260 1260
			/* Is SRTP involved? */
......
1294 1294
			return;
1295 1295
		}
1296 1296
		/* Forward to our SIPre peer */
1297
		if((video && session->media.has_video && session->media.video_rtcp_fd) ||
1298
				(!video && session->media.has_audio && session->media.audio_rtcp_fd)) {
1297
		if((video && session->media.has_video && session->media.video_rtcp_fd != -1) ||
1298
				(!video && session->media.has_audio && session->media.audio_rtcp_fd != -1)) {
1299 1299
			/* Fix SSRCs as the gateway does */
1300 1300
			JANUS_LOG(LOG_HUGE, "[SIPre-%s] Fixing %s SSRCs (local %u, peer %u)\n",
1301 1301
				session->account.username ? session->account.username : "unknown",
......
1965 1965
			}
1966 1966
			/* Accept a call from another peer */
1967 1967
			JANUS_LOG(LOG_VERB, "We're accepting the call from %s\n", session->callee);
1968
			gboolean answer = !strcasecmp(msg_sdp_type, "answer");
1969
			if(!answer) {
1970
				JANUS_LOG(LOG_VERB, "This is a response to an offerless INVITE\n");
1971
			}
1968 1972
			JANUS_LOG(LOG_VERB, "This is involving a negotiation (%s) as well:\n%s\n", msg_sdp_type, msg_sdp);
1969 1973
			session->media.has_srtp_local = answer_srtp;
1970 1974
			if(answer_srtp) {
......
2018 2022
			/* Also notify event handlers */
2019 2023
			if(notify_events && gateway->events_is_enabled()) {
2020 2024
				json_t *info = json_object();
2021
				json_object_set_new(info, "event", json_string("accepted"));
2025
				json_object_set_new(info, "event", json_string(answer ? "accepted" : "accepting"));
2022 2026
				if(session->callid)
2023 2027
					json_object_set_new(info, "call-id", json_string(session->callid));
2024 2028
				gateway->notify_event(&janus_sipre_plugin, session->handle, info);
2025 2029
			}
2026 2030
			/* Enqueue the 200 OK */
2031
			if(!answer) {
2032
				if(session->transaction)
2033
					g_free(session->transaction);
2034
				session->transaction = msg->transaction ? g_strdup(msg->transaction) : NULL;
2035
			}
2027 2036
			g_atomic_int_set(&session->hangingup, 0);
2028 2037
			session->status = janus_sipre_call_status_incall;
2029 2038
			session->temp_sdp = sdp;
2030 2039
			mqueue_push(mq, janus_sipre_mqueue_event_do_accept, janus_sipre_mqueue_payload_create(session, NULL, 0, NULL));
2031 2040
			/* Send an ack back */
2032 2041
			result = json_object();
2033
			json_object_set_new(result, "event", json_string("accepted"));
2034
			/* Start the media */
2035
			session->media.ready = TRUE;	/* FIXME Maybe we need a better way to signal this */
2036
			GError *error = NULL;
2037
			char tname[16];
2038
			g_snprintf(tname, sizeof(tname), "siprertp %s", session->account.username);
2039
			g_thread_try_new(tname, janus_sipre_relay_thread, session, &error);
2040
			if(error != NULL) {
2041
				JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the RTP/RTCP thread...\n", error->code, error->message ? error->message : "??");
2042
			json_object_set_new(result, "event", json_string(answer ? "accepted" : "accepting"));
2043
			if(answer) {
2044
				/* Start the media */
2045
				session->media.ready = TRUE;	/* FIXME Maybe we need a better way to signal this */
2046
				GError *error = NULL;
2047
				char tname[16];
2048
				g_snprintf(tname, sizeof(tname), "siprertp %s", session->account.username);
2049
				g_thread_try_new(tname, janus_sipre_relay_thread, session, &error);
2050
				if(error != NULL) {
2051
					JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the RTP/RTCP thread...\n", error->code, error->message ? error->message : "??");
2052
				}
2042 2053
			}
2043 2054
		} else if(!strcasecmp(request_text, "decline")) {
2044 2055
			/* Reject an incoming call */
......
2927 2938
		int i = 0;
2928 2939
		for(i=0; i<num; i++) {
2929 2940
			if(fds[i].revents & (POLLERR | POLLHUP)) {
2930
				/* Socket error? */
2931
				JANUS_LOG(LOG_ERR, "[SIPre-%s] Error polling: %s...\n", session->account.username,
2932
					fds[i].revents & POLLERR ? "POLLERR" : "POLLHUP");
2933
				JANUS_LOG(LOG_ERR, "[SIPre-%s]   -- %d (%s)\n", session->account.username, errno, strerror(errno));
2941
				/* If we just updated the session, let's wait until things have calmed down */
2934 2942
				if(session->media.updated)
2935 2943
					break;
2936
				goon = FALSE;	/* Can we assume it's pretty much over, after a POLLERR? */
2944
				/* Check the socket error */
2945
				int error = 0;
2946
				socklen_t errlen = sizeof(error);
2947
				getsockopt(fds[i].fd, SOL_SOCKET, SO_ERROR, (void *)&error, &errlen);
2948
				if(error == 0) {
2949
					/* Maybe not a breaking error after all? */
2950
					continue;
2951
				} else if(error == 111) {
2952
					/* ICMP error? If it's related to RTCP, let's just close the RTCP socket and move on */
2953
					if(fds[i].fd == session->media.audio_rtcp_fd) {
2954
						JANUS_LOG(LOG_WARN, "[SIPre-%s] Got a '%s' on the audio RTCP socket, closing it\n",
2955
							session->account.username, strerror(error));
2956
						close(session->media.audio_rtcp_fd);
2957
						session->media.audio_rtcp_fd = -1;
2958
					} else if(fds[i].fd == session->media.video_rtcp_fd) {
2959
						JANUS_LOG(LOG_WARN, "[SIPre-%s] Got a '%s' on the video RTCP socket, closing it\n",
2960
							session->account.username, strerror(error));
2961
						close(session->media.video_rtcp_fd);
2962
						session->media.video_rtcp_fd = -1;
2963
					}
2964
					/* FIXME Should we do the same with the RTP sockets as well? We may risk overreacting, there... */
2965
					continue;
2966
				}
2967
				JANUS_LOG(LOG_ERR, "[SIPre-%s] Error polling %d (socket #%d): %s...\n", session->account.username,
2968
					fds[i].fd, i, fds[i].revents & POLLERR ? "POLLERR" : "POLLHUP");
2969
				JANUS_LOG(LOG_ERR, "[SIPre-%s]   -- %d (%s)\n", session->account.username, error, strerror(error));
2970
				/* Can we assume it's pretty much over, after a POLLERR? */
2971
				goon = FALSE;
2937 2972
				/* FIXME Simulate a "hangup" coming from the browser */
2938 2973
				janus_sipre_message *msg = g_malloc0(sizeof(janus_sipre_message));
2939 2974
				msg->handle = session->handle;
......
3263 3298
		}
3264 3299
		return;
3265 3300
	}
3266
	/* New incoming call */
3267
	const char *offer = (const char *)mbuf_buf(msg->mb);
3268
	if(offer == NULL) {
3269
		/* No SDP? */
3270
		JANUS_LOG(LOG_WARN, "[SIPre-%s] No SDP in the INVITE?\n", session->account.username);
3271
		mqueue_push(mq, janus_sipre_mqueue_event_do_rcode, janus_sipre_mqueue_payload_create(session, msg, 488, NULL));
3272
		return;
3273
	}
3301
	/* New incoming call, check if there's an SDP to process */
3274 3302
	char sdp_offer[1024];
3275
	g_snprintf(sdp_offer, sizeof(sdp_offer), "%.*s", (int)mbuf_get_left(msg->mb), offer);
3276
	JANUS_LOG(LOG_HUGE, "[SIPre-%s]   -- Offer: %s\n", session->account.username, sdp_offer);
3277
	/* Parse the remote SDP */
3278
	char sdperror[100];
3279
	janus_sdp *sdp = janus_sdp_parse(sdp_offer, sdperror, sizeof(sdperror));
3280
	if(!sdp) {
3281
		JANUS_LOG(LOG_ERR, "Error parsing SDP! %s\n", sdperror);
3282
		mqueue_push(mq, janus_sipre_mqueue_event_do_rcode, janus_sipre_mqueue_payload_create(session, msg, 488, NULL));
3283
		return;
3303
	janus_sdp *sdp = NULL;
3304
	const char *offer = (const char *)mbuf_buf(msg->mb);
3305
	if(offer == NULL || mbuf_get_left(msg->mb) == 0) {
3306
		JANUS_LOG(LOG_WARN, "[SIPre-%s] Received offerless INVITE\n", session->account.username);
3307
	} else {
3308
		g_snprintf(sdp_offer, sizeof(sdp_offer), "%.*s", (int)mbuf_get_left(msg->mb), offer);
3309
		JANUS_LOG(LOG_WARN, "[SIPre-%s]   -- Offer: %s\n", session->account.username, sdp_offer);
3310
		/* Parse the remote SDP */
3311
		char sdperror[100];
3312
		sdp = janus_sdp_parse(sdp_offer, sdperror, sizeof(sdperror));
3313
		if(!sdp) {
3314
			JANUS_LOG(LOG_ERR, "Error parsing SDP! %s\n", sdperror);
3315
			mqueue_push(mq, janus_sipre_mqueue_event_do_rcode, janus_sipre_mqueue_payload_create(session, msg, 488, NULL));
3316
			return;
3317
		}
3284 3318
	}
3285 3319
	session->callee = g_strdup(from);
3286 3320
	session->callid = g_strdup(callid);
......
3290 3324
	janus_sipre_srtp_cleanup(session);
3291 3325
	/* Parse SDP */
3292 3326
	JANUS_LOG(LOG_VERB, "Someone is inviting us a call\n");
3293
	gboolean changed = FALSE;
3294
	janus_sipre_sdp_process(session, sdp, FALSE, FALSE, &changed);
3295
	/* Check if offer has neither audio nor video, fail with 488 */
3296
	if (!session->media.has_audio && !session->media.has_video) {
3297
		mqueue_push(mq, janus_sipre_mqueue_event_do_rcode, janus_sipre_mqueue_payload_create(session, msg, 488, NULL));
3298
		janus_sdp_free(sdp);
3299
		return;
3300
	}
3301
	/* Also fail with 488 if there's no remote IP address that can be used for RTP */
3302
	if (!session->media.remote_ip) {
3303
		mqueue_push(mq, janus_sipre_mqueue_event_do_rcode, janus_sipre_mqueue_payload_create(session, msg, 488, NULL));
3304
		janus_sdp_free(sdp);
3305
		return;
3327
	if(sdp) {
3328
		gboolean changed = FALSE;
3329
		janus_sipre_sdp_process(session, sdp, FALSE, FALSE, &changed);
3330
		/* Check if offer has neither audio nor video, fail with 488 */
3331
		if(!session->media.has_audio && !session->media.has_video) {
3332
			mqueue_push(mq, janus_sipre_mqueue_event_do_rcode, janus_sipre_mqueue_payload_create(session, msg, 488, NULL));
3333
			janus_sdp_free(sdp);
3334
			return;
3335
		}
3336
		/* Also fail with 488 if there's no remote IP address that can be used for RTP */
3337
		if(!session->media.remote_ip) {
3338
			mqueue_push(mq, janus_sipre_mqueue_event_do_rcode, janus_sipre_mqueue_payload_create(session, msg, 488, NULL));
3339
			janus_sdp_free(sdp);
3340
			return;
3341
		}
3306 3342
	}
3307 3343
	session->stack.invite = msg;
3308
	/* Send SDP to the browser */
3309
	json_t *jsep = json_pack("{ssss}", "type", "offer", "sdp", sdp_offer);
3344
	/* Notify the browser about the call */
3345
	json_t *jsep = NULL;
3346
	if(sdp)
3347
		jsep = json_pack("{ssss}", "type", "offer", "sdp", sdp_offer);
3310 3348
	json_t *call = json_object();
3311 3349
	json_object_set_new(call, "sip", json_string("event"));
3312 3350
	json_t *calling = json_object();
......
3315 3353
	if(strlen(dname)) {
3316 3354
		json_object_set_new(calling, "displayname", json_string(dname));
3317 3355
	}
3318
	if(session->media.has_srtp_remote) {
3356
	if(sdp && session->media.has_srtp_remote) {
3319 3357
		/* FIXME Maybe a true/false instead? */
3320 3358
		json_object_set_new(calling, "srtp", json_string(session->media.require_srtp ? "sdes_mandatory" : "sdes_optional"));
3321 3359
	}
......
3325 3363
		JANUS_LOG(LOG_VERB, "  >> Pushing event to peer: %d (%s)\n", ret, janus_get_api_error(ret));
3326 3364
	}
3327 3365
	json_decref(call);
3328
	json_decref(jsep);
3366
	if(jsep)
3367
		json_decref(jsep);
3329 3368
	janus_sdp_free(sdp);
3330 3369
	/* Also notify event handlers */
3331 3370
	if(notify_events && gateway->events_is_enabled()) {

Also available in: Unified diff