Revision 87399acb

View differences:

plugins/janus_sip.c
295 295
	janus_sip_registration_status registration_status;
296 296
} janus_sip_account;
297 297

  
298
typedef struct janus_sip_rtp_context {
299
	/* Needed to fix seq and ts in case of re-INVITEs/UPDATEs that result in a RTP stream */
300
	uint32_t a_last_ssrc, a_last_ts, a_base_ts, a_base_ts_prev,
301
			v_last_ssrc, v_last_ts, v_base_ts, v_base_ts_prev;
302
	uint16_t a_last_seq, a_base_seq, a_base_seq_prev,
303
			v_last_seq, v_base_seq, v_base_seq_prev;
304
} janus_sip_rtp_context;
305

  
298 306
typedef struct janus_sip_media {
299 307
	char *remote_ip;
300 308
	int ready:1;
......
310 318
	srtp_t audio_srtp_in, audio_srtp_out;
311 319
	srtp_policy_t audio_remote_policy, audio_local_policy;
312 320
	int audio_srtp_suite_in, audio_srtp_suite_out;
321
	gboolean audio_send;
313 322
	int has_video:1;
314 323
	int video_rtp_fd, video_rtcp_fd;
315 324
	int local_video_rtp_port, remote_video_rtp_port;
......
320 329
	srtp_t video_srtp_in, video_srtp_out;
321 330
	srtp_policy_t video_remote_policy, video_local_policy;
322 331
	int video_srtp_suite_in, video_srtp_suite_out;
332
	gboolean video_send;
333
	janus_sip_rtp_context context;
334
	int pipefd[2];
335
	gboolean updated;
323 336
} janus_sip_media;
324 337

  
325 338
typedef struct janus_sip_session {
......
330 343
	janus_sip_media media;
331 344
	char *transaction;
332 345
	char *callee;
346
	janus_sdp *sdp;				/* The SDP this user sent */
333 347
	janus_recorder *arc;		/* The Janus recorder instance for this user's audio, if enabled */
334 348
	janus_recorder *arc_peer;	/* The Janus recorder instance for the peer's audio, if enabled */
335 349
	janus_recorder *vrc;		/* The Janus recorder instance for this user's video, if enabled */
......
506 520
/* Sofia callbacks */
507 521
void janus_sip_sofia_callback(nua_event_t event, int status, char const *phrase, nua_t *nua, nua_magic_t *magic, nua_handle_t *nh, nua_hmagic_t *hmagic, sip_t const *sip, tagi_t tags[]);
508 522
/* SDP parsing and manipulation */
509
void janus_sip_sdp_process(janus_sip_session *session, janus_sdp *sdp, gboolean answer);
523
void janus_sip_sdp_process(janus_sip_session *session, janus_sdp *sdp, gboolean answer, gboolean update, gboolean *changed);
510 524
char *janus_sip_sdp_manipulate(janus_sip_session *session, janus_sdp *sdp, gboolean answer);
511 525
/* Media */
512 526
static int janus_sip_allocate_local_ports(janus_sip_session *session);
......
611 625
					    g_free(session->callee);
612 626
					    session->callee = NULL;
613 627
					}
628
					if (session->sdp) {
629
					    janus_sdp_free(session->sdp);
630
					    session->sdp = NULL;
631
					}
614 632
					if (session->transaction) {
615 633
					    g_free(session->transaction);
616 634
					    session->transaction = NULL;
......
866 884
	session->stack = NULL;
867 885
	session->transaction = NULL;
868 886
	session->callee = NULL;
887
	session->sdp = NULL;
869 888
	session->media.remote_ip = NULL;
870 889
	session->media.ready = 0;
871 890
	session->media.autoack = TRUE;
......
885 904
	session->media.audio_pt_name = NULL;
886 905
	session->media.audio_srtp_suite_in = 0;
887 906
	session->media.audio_srtp_suite_out = 0;
907
	session->media.audio_send = TRUE;
888 908
	session->media.has_video = 0;
889 909
	session->media.video_rtp_fd = -1;
890 910
	session->media.video_rtcp_fd= -1;
......
898 918
	session->media.video_pt_name = NULL;
899 919
	session->media.video_srtp_suite_in = 0;
900 920
	session->media.video_srtp_suite_out = 0;
921
	session->media.video_send = TRUE;
922
	/* Initialize the RTP context */
923
	session->media.context.a_last_ssrc = 0;
924
	session->media.context.a_last_ssrc = 0;
925
	session->media.context.a_last_ts = 0;
926
	session->media.context.a_base_ts = 0;
927
	session->media.context.a_base_ts_prev = 0;
928
	session->media.context.v_last_ssrc = 0;
929
	session->media.context.v_last_ts = 0;
930
	session->media.context.v_base_ts = 0;
931
	session->media.context.v_base_ts_prev = 0;
932
	session->media.context.a_last_seq = 0;
933
	session->media.context.a_base_seq = 0;
934
	session->media.context.a_base_seq_prev = 0;
935
	session->media.context.v_last_seq = 0;
936
	session->media.context.v_base_seq = 0;
937
	session->media.context.v_base_seq_prev = 0;
938
	session->media.pipefd[0] = -1;
939
	session->media.pipefd[1] = -1;
940
	session->media.updated = FALSE;
901 941
	janus_mutex_init(&session->rec_mutex);
902 942
	session->destroyed = 0;
903 943
	g_atomic_int_set(&session->hangingup, 0);
......
1027 1067
			return;
1028 1068
		/* Forward to our SIP peer */
1029 1069
		if(video) {
1070
			if(!session->media.video_send) {
1071
				/* Dropping video packet, peer doesn't want to receive it */
1072
				return;
1073
			}
1030 1074
			if(session->media.video_ssrc == 0) {
1031 1075
				rtp_header *header = (rtp_header *)buf;
1032 1076
				session->media.video_ssrc = ntohl(header->ssrc);
......
1057 1101
				}
1058 1102
			}
1059 1103
		} else {
1104
			if(!session->media.audio_send) {
1105
				/* Dropping audio packet, peer doesn't want to receive it */
1106
				return;
1107
			}
1060 1108
			if(session->media.audio_ssrc == 0) {
1061 1109
				rtp_header *header = (rtp_header *)buf;
1062 1110
				session->media.audio_ssrc = ntohl(header->ssrc);
......
1657 1705
				g_snprintf(error_cause, 512, "Could not allocate RTP/RTCP ports");
1658 1706
				goto error;
1659 1707
			}
1660
			janus_sdp_free(parsed_sdp);
1708
			/* Take note of the SDP (may be useful for UPDATEs or re-INVITEs) */
1709
			janus_sdp_free(session->sdp);
1710
			session->sdp = parsed_sdp;
1661 1711
			JANUS_LOG(LOG_VERB, "Prepared SDP for INVITE:\n%s", sdp);
1662 1712
			/* Prepare the From header */
1663 1713
			char from_hdr[1024];
......
1673 1723
			if(session->stack->s_nh_i == NULL) {
1674 1724
				JANUS_LOG(LOG_WARN, "NUA Handle for INVITE still null??\n");
1675 1725
				g_free(sdp);
1726
				session->sdp = NULL;
1676 1727
				janus_sdp_free(parsed_sdp);
1677 1728
				error_code = JANUS_SIP_ERROR_LIBSOFIA_ERROR;
1678 1729
				g_snprintf(error_cause, 512, "Invalid NUA Handle");
......
1789 1840
				g_snprintf(error_cause, 512, "Could not allocate RTP/RTCP ports");
1790 1841
				goto error;
1791 1842
			}
1792
			janus_sdp_free(parsed_sdp);
1793 1843
			if(session->media.audio_pt > -1) {
1794 1844
				session->media.audio_pt_name = janus_get_codec_from_pt(sdp, session->media.audio_pt);
1795 1845
				JANUS_LOG(LOG_VERB, "Detected audio codec: %d (%s)\n", session->media.audio_pt, session->media.audio_pt_name);
......
1798 1848
				session->media.video_pt_name = janus_get_codec_from_pt(sdp, session->media.video_pt);
1799 1849
				JANUS_LOG(LOG_VERB, "Detected video codec: %d (%s)\n", session->media.video_pt, session->media.video_pt_name);
1800 1850
			}
1851
			/* Take note of the SDP (may be useful for UPDATEs or re-INVITEs) */
1852
			janus_sdp_free(session->sdp);
1853
			session->sdp = parsed_sdp;
1801 1854
			JANUS_LOG(LOG_VERB, "Prepared SDP for 200 OK:\n%s", sdp);
1802 1855
			/* Send 200 OK */
1803 1856
			g_atomic_int_set(&session->hangingup, 0);
......
2277 2330
				nua_respond(nh, 488, sip_status_phrase(488), TAG_END());
2278 2331
				break;
2279 2332
			}
2333
			gboolean reinvite = FALSE;
2280 2334
			if(session->stack->s_nh_i != NULL) {
2281 2335
				if(session->stack->s_nh_i == nh) {
2282
					/* re-INVITE, we don't support those. */
2283
					nua_respond(nh, 488, sip_status_phrase(488), TAG_END());
2336
					/* re-INVITE, we'll check what changed later */
2337
					reinvite = TRUE;
2338
					JANUS_LOG(LOG_VERB, "Got a re-INVITE...\n");
2284 2339
				} else if(session->status >= janus_sip_call_status_inviting) {
2285 2340
					/* Busy with another call */
2286 2341
					JANUS_LOG(LOG_VERB, "\tAlready in a call (busy, status=%s)\n", janus_sip_call_status_string(session->status));
......
2303 2358
					int ret = gateway->push_event(session->handle, &janus_sip_plugin, session->transaction, missed_text, NULL, NULL);
2304 2359
					JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
2305 2360
					g_free(missed_text);
2361
					/* Done */
2362
					janus_sdp_free(sdp);
2363
					break;
2306 2364
				}
2365
			}
2366
			if(!reinvite) {
2367
				/* New incoming call */
2368
				session->callee = g_strdup(url_as_string(session->stack->s_home, sip->sip_from->a_url));
2369
				session->status = janus_sip_call_status_invited;
2370
				/* Clean up SRTP stuff from before first, in case it's still needed */
2371
				janus_sip_srtp_cleanup(session);
2372
			}
2373
			/* Parse SDP */
2374
			JANUS_LOG(LOG_VERB, "Someone is %s a call:\n%s",
2375
				reinvite ? "updating" : "inviting us in",
2376
				sip->sip_payload->pl_data);
2377
			gboolean changed = FALSE;
2378
			janus_sip_sdp_process(session, sdp, FALSE, reinvite, &changed);
2379
			if(reinvite) {
2380
				/* No need to involve the browser: we reply ourselves */
2381
				nua_respond(nh, 200, sip_status_phrase(200), TAG_END());
2307 2382
				janus_sdp_free(sdp);
2308 2383
				break;
2309 2384
			}
2310
			/* New incoming call */
2311
			session->callee = g_strdup(url_as_string(session->stack->s_home, sip->sip_from->a_url));
2312
			session->status = janus_sip_call_status_invited;
2313
			/* Clean up SRTP stuff from before first, in case it's still needed */
2314
			janus_sip_srtp_cleanup(session);
2315
			/* Parse SDP */
2316
			char *fixed_sdp = g_strdup(sip->sip_payload->pl_data);
2317
			JANUS_LOG(LOG_VERB, "Someone is inviting us in a call:\n%s", sip->sip_payload->pl_data);
2318
			janus_sip_sdp_process(session, sdp, FALSE);
2319 2385
			/* Send SDP to the browser */
2320 2386
			json_t *call = json_object();
2321 2387
			json_object_set_new(call, "sip", json_string("event"));
......
2333 2399
			char *call_text = json_dumps(call, JSON_INDENT(3) | JSON_PRESERVE_ORDER);
2334 2400
			json_decref(call);
2335 2401
			JANUS_LOG(LOG_VERB, "Pushing event to peer: %s\n", call_text);
2336
			int ret = gateway->push_event(session->handle, &janus_sip_plugin, session->transaction, call_text, "offer", fixed_sdp);
2402
			int ret = gateway->push_event(session->handle, &janus_sip_plugin, session->transaction, call_text, "offer", sip->sip_payload->pl_data);
2337 2403
			JANUS_LOG(LOG_VERB, "  >> %d (%s)\n", ret, janus_get_api_error(ret));
2338 2404
			g_free(call_text);
2339
			g_free(fixed_sdp);
2340 2405
			janus_sdp_free(sdp);
2341 2406
			/* Send a Ringing back */
2342 2407
			nua_respond(nh, 180, sip_status_phrase(180), TAG_END());
......
2444 2509
			JANUS_LOG(LOG_VERB, "Peer accepted our call:\n%s", sip->sip_payload->pl_data);
2445 2510
			session->status = janus_sip_call_status_incall;
2446 2511
			char *fixed_sdp = g_strdup(sip->sip_payload->pl_data);
2447
			janus_sip_sdp_process(session, sdp, TRUE);
2512
			janus_sip_sdp_process(session, sdp, TRUE, FALSE, NULL);
2448 2513
			/* If we asked for SRTP and are not getting it, fail */
2449 2514
			if(session->media.require_srtp && !session->media.has_srtp_remote) {
2450 2515
				JANUS_LOG(LOG_ERR, "\tWe asked for mandatory SRTP but didn't get any in the reply!\n");
......
2554 2619
	}
2555 2620
}
2556 2621

  
2557
void janus_sip_sdp_process(janus_sip_session *session, janus_sdp *sdp, gboolean answer) {
2622
void janus_sip_sdp_process(janus_sip_session *session, janus_sdp *sdp, gboolean answer, gboolean update, gboolean *changed) {
2558 2623
	if(!session || !sdp)
2559 2624
		return;
2560 2625
	/* c= */
2561 2626
	if(sdp->c_addr) {
2627
		if(update && strcmp(sdp->c_addr, session->media.remote_ip)) {
2628
			/* This is an update and an address changed */
2629
			if(changed)
2630
				*changed = TRUE;
2631
		}
2562 2632
		g_free(session->media.remote_ip);
2563 2633
		session->media.remote_ip = g_strdup(sdp->c_addr);
2564
		JANUS_LOG(LOG_VERB, "  >> Media connection:\n");
2565
		JANUS_LOG(LOG_VERB, "       %s\n", session->media.remote_ip);
2566 2634
	}
2567
	JANUS_LOG(LOG_VERB, "  >> Media lines:\n");
2568 2635
	GList *temp = sdp->m_lines;
2569 2636
	while(temp) {
2570 2637
		janus_sdp_mline *m = (janus_sdp_mline *)temp->data;
2571 2638
		session->media.require_srtp = session->media.require_srtp || (m->proto && !strcasecmp(m->proto, "RTP/SAVP"));
2572 2639
		if(m->type == JANUS_SDP_AUDIO) {
2573
			JANUS_LOG(LOG_VERB, "       Audio: %"SCNu16"\n", m->port);
2574 2640
			if(m->port) {
2641
				if(m->port != session->media.remote_audio_rtp_port) {
2642
					/* This is an update and an address changed */
2643
					if(changed)
2644
						*changed = TRUE;
2645
				}
2575 2646
				session->media.has_audio = 1;
2576 2647
				session->media.remote_audio_rtp_port = m->port;
2577 2648
				session->media.remote_audio_rtcp_port = m->port+1;	/* FIXME We're assuming RTCP is on the next port */
2649
				if(m->direction == JANUS_SDP_SENDONLY || m->direction == JANUS_SDP_INACTIVE)
2650
					session->media.audio_send = FALSE;
2651
				else
2652
					session->media.audio_send = TRUE;
2653
			} else {
2654
				session->media.audio_send = FALSE;
2578 2655
			}
2579 2656
		} else if(m->type == JANUS_SDP_VIDEO) {
2580
			JANUS_LOG(LOG_VERB, "       Video: %"SCNu16"\n", m->port);
2581 2657
			if(m->port) {
2658
				if(m->port != session->media.remote_video_rtp_port) {
2659
					/* This is an update and an address changed */
2660
					if(changed)
2661
						*changed = TRUE;
2662
				}
2582 2663
				session->media.has_video = 1;
2583 2664
				session->media.remote_video_rtp_port = m->port;
2584 2665
				session->media.remote_video_rtcp_port = m->port+1;	/* FIXME We're assuming RTCP is on the next port */
2666
				if(m->direction == JANUS_SDP_SENDONLY || m->direction == JANUS_SDP_INACTIVE)
2667
					session->media.video_send = FALSE;
2668
				else
2669
					session->media.video_send = TRUE;
2670
			} else {
2671
				session->media.video_send = FALSE;
2585 2672
			}
2586 2673
		} else {
2587
			JANUS_LOG(LOG_WARN, "       Unsupported media line (not audio/video)\n");
2674
			JANUS_LOG(LOG_WARN, "Unsupported media line (not audio/video)\n");
2588 2675
			temp = temp->next;
2589 2676
			continue;
2590 2677
		}
2591
		JANUS_LOG(LOG_VERB, "       Media connections:\n");
2592 2678
		if(m->c_addr) {
2679
			if(update && strcmp(m->c_addr, session->media.remote_ip)) {
2680
				/* This is an update and an address changed */
2681
				if(changed)
2682
					*changed = TRUE;
2683
			}
2593 2684
			g_free(session->media.remote_ip);
2594 2685
			session->media.remote_ip = g_strdup(m->c_addr);
2595
			JANUS_LOG(LOG_VERB, "         [%s]\n", session->media.remote_ip);
2596 2686
		}
2597
		JANUS_LOG(LOG_VERB, "       Media attributes:\n");
2687
		if(update) {
2688
			/* FIXME This is a session update, we only accept changes in IP/ports */
2689
			temp = temp->next;
2690
			continue;
2691
		}
2598 2692
		GList *tempA = m->attributes;
2599 2693
		while(tempA) {
2600 2694
			janus_sdp_attribute *a = (janus_sdp_attribute *)tempA->data;
2601 2695
			if(a->name) {
2602
				if(!strcasecmp(a->name, "rtpmap")) {
2603
					JANUS_LOG(LOG_VERB, "         RTP Map:     %s\n", a->value);
2604
				} else if(!strcasecmp(a->name, "crypto")) {
2605
					JANUS_LOG(LOG_VERB, "         Crypto:      %s\n", a->value);
2696
				if(!strcasecmp(a->name, "crypto")) {
2606 2697
					if(m->type == JANUS_SDP_AUDIO || m->type == JANUS_SDP_VIDEO) {
2607 2698
						gint32 tag = 0;
2608 2699
						int suite;
......
2647 2738
		}
2648 2739
		temp = temp->next;
2649 2740
	}
2741
	if(changed && *changed) {
2742
		/* Something changed: mark this on the session, so that the thread can update the sockets */
2743
		session->media.updated = TRUE;
2744
		if(session->media.pipefd[1] > 0) {
2745
			int code = 1;
2746
			ssize_t res = 0;
2747
			do {
2748
				res = write(session->media.pipefd[1], &code, sizeof(int));
2749
			} while(res == -1 && errno == EINTR);
2750
		}
2751
	}
2650 2752
}
2651 2753

  
2652 2754
char *janus_sip_sdp_manipulate(janus_sip_session *session, janus_sdp *sdp, gboolean answer) {
......
2732 2834
	session->media.local_video_rtp_port = 0;
2733 2835
	session->media.local_video_rtcp_port = 0;
2734 2836
	session->media.video_ssrc = 0;
2837
	if(session->media.pipefd[0] > 0) {
2838
		close(session->media.pipefd[0]);
2839
		session->media.pipefd[0] = -1;
2840
	}
2841
	if(session->media.pipefd[1] > 0) {
2842
		close(session->media.pipefd[1]);
2843
		session->media.pipefd[1] = -1;
2844
	}
2735 2845
	/* Start */
2736 2846
	int attempts = 100;	/* FIXME Don't retry forever */
2737 2847
	if(session->media.has_audio) {
......
2816 2926
			session->media.local_video_rtcp_port = rtcp_port;
2817 2927
		}
2818 2928
	}
2929
	/* We need this to quickly interrupt the poll when it's time to update a session or wrap up */
2930
	pipe(session->media.pipefd);
2819 2931
	return 0;
2820 2932
}
2821 2933

  
2934
/* Helper method to (re)connect RTP/RTCP sockets */
2935
static void janus_sip_connect_sockets(janus_sip_session *session, struct sockaddr_in *server_addr) {
2936
	if(!session || !server_addr)
2937
		return;
2938

  
2939
	if(session->media.updated) {
2940
		JANUS_LOG(LOG_VERB, "Updating session sockets\n");
2941
	}
2942

  
2943
	/* Connect peers (FIXME This pretty much sucks right now) */
2944
	if(session->media.remote_audio_rtp_port) {
2945
		server_addr->sin_port = htons(session->media.remote_audio_rtp_port);
2946
		if(connect(session->media.audio_rtp_fd, (struct sockaddr *)server_addr, sizeof(struct sockaddr)) == -1) {
2947
			JANUS_LOG(LOG_ERR, "[SIP-%s] Couldn't connect audio RTP? (%s:%d)\n", session->account.username, session->media.remote_ip, session->media.remote_audio_rtp_port);
2948
			JANUS_LOG(LOG_ERR, "[SIP-%s]   -- %d (%s)\n", session->account.username, errno, strerror(errno));
2949
		}
2950
	}
2951
	if(session->media.remote_audio_rtcp_port) {
2952
		server_addr->sin_port = htons(session->media.remote_audio_rtcp_port);
2953
		if(connect(session->media.audio_rtcp_fd, (struct sockaddr *)server_addr, sizeof(struct sockaddr)) == -1) {
2954
			JANUS_LOG(LOG_ERR, "[SIP-%s] Couldn't connect audio RTCP? (%s:%d)\n", session->account.username, session->media.remote_ip, session->media.remote_audio_rtcp_port);
2955
			JANUS_LOG(LOG_ERR, "[SIP-%s]   -- %d (%s)\n", session->account.username, errno, strerror(errno));
2956
		}
2957
	}
2958
	if(session->media.remote_video_rtp_port) {
2959
		server_addr->sin_port = htons(session->media.remote_video_rtp_port);
2960
		if(connect(session->media.video_rtp_fd, (struct sockaddr *)server_addr, sizeof(struct sockaddr)) == -1) {
2961
			JANUS_LOG(LOG_ERR, "[SIP-%s] Couldn't connect video RTP? (%s:%d)\n", session->account.username, session->media.remote_ip, session->media.remote_video_rtp_port);
2962
			JANUS_LOG(LOG_ERR, "[SIP-%s]   -- %d (%s)\n", session->account.username, errno, strerror(errno));
2963
		}
2964
	}
2965
	if(session->media.remote_video_rtcp_port) {
2966
		server_addr->sin_port = htons(session->media.remote_video_rtcp_port);
2967
		if(connect(session->media.video_rtcp_fd, (struct sockaddr *)server_addr, sizeof(struct sockaddr)) == -1) {
2968
			JANUS_LOG(LOG_ERR, "[SIP-%s] Couldn't connect video RTCP? (%s:%d)\n", session->account.username, session->media.remote_ip, session->media.remote_video_rtcp_port);
2969
			JANUS_LOG(LOG_ERR, "[SIP-%s]   -- %d (%s)\n", session->account.username, errno, strerror(errno));
2970
		}
2971
	}
2972

  
2973
}
2974

  
2822 2975
/* Thread to relay RTP/RTCP frames coming from the SIP peer */
2823 2976
static void *janus_sip_relay_thread(void *data) {
2824 2977
	janus_sip_session *session = (janus_sip_session *)data;
......
2841 2994
			server_addr.sin_addr = *(struct in_addr *)host->h_addr_list;
2842 2995
		}
2843 2996
	}
2844

  
2845
	/* Connect peers (FIXME This pretty much sucks right now) */
2846
	if(have_server_ip && session->media.remote_audio_rtp_port) {
2847
		server_addr.sin_port = htons(session->media.remote_audio_rtp_port);
2848
		if(connect(session->media.audio_rtp_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) {
2849
			JANUS_LOG(LOG_ERR, "[SIP-%s] Couldn't connect audio RTP? (%s:%d)\n", session->account.username, session->media.remote_ip, session->media.remote_audio_rtp_port);
2850
			JANUS_LOG(LOG_ERR, "[SIP-%s]   -- %d (%s)\n", session->account.username, errno, strerror(errno));
2851
		}
2852
	}
2853
	if(have_server_ip && session->media.remote_audio_rtcp_port) {
2854
		server_addr.sin_port = htons(session->media.remote_audio_rtcp_port);
2855
		if(connect(session->media.audio_rtcp_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) {
2856
			JANUS_LOG(LOG_ERR, "[SIP-%s] Couldn't connect audio RTCP? (%s:%d)\n", session->account.username, session->media.remote_ip, session->media.remote_audio_rtcp_port);
2857
			JANUS_LOG(LOG_ERR, "[SIP-%s]   -- %d (%s)\n", session->account.username, errno, strerror(errno));
2858
		}
2859
	}
2860
	if(have_server_ip && session->media.remote_video_rtp_port) {
2861
		server_addr.sin_port = htons(session->media.remote_video_rtp_port);
2862
		if(connect(session->media.video_rtp_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) {
2863
			JANUS_LOG(LOG_ERR, "[SIP-%s] Couldn't connect video RTP? (%s:%d)\n", session->account.username, session->media.remote_ip, session->media.remote_video_rtp_port);
2864
			JANUS_LOG(LOG_ERR, "[SIP-%s]   -- %d (%s)\n", session->account.username, errno, strerror(errno));
2865
		}
2866
	}
2867
	if(have_server_ip && session->media.remote_video_rtcp_port) {
2868
		server_addr.sin_port = htons(session->media.remote_video_rtcp_port);
2869
		if(connect(session->media.video_rtcp_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) {
2870
			JANUS_LOG(LOG_ERR, "[SIP-%s] Couldn't connect video RTCP? (%s:%d)\n", session->account.username, session->media.remote_ip, session->media.remote_video_rtcp_port);
2871
			JANUS_LOG(LOG_ERR, "[SIP-%s]   -- %d (%s)\n", session->account.username, errno, strerror(errno));
2872
		}
2873
	}
2997
	if(have_server_ip)
2998
		janus_sip_connect_sockets(session, &server_addr);
2874 2999

  
2875 3000
	if(!session->callee) {
2876 3001
		JANUS_LOG(LOG_VERB, "[SIP-%s] Leaving thread, no callee...\n", session->account.username);
......
2882 3007
	struct sockaddr_in remote;
2883 3008
	int resfd = 0, bytes = 0;
2884 3009
	struct pollfd fds[4];
3010
	int pipe_fd = session->media.pipefd[0];
2885 3011
	char buffer[1500];
2886 3012
	memset(buffer, 0, 1500);
2887 3013
	/* Loop */
2888 3014
	int num = 0;
2889 3015
	gboolean goon = TRUE;
3016
	int astep = 0, vstep = 0;
3017
	guint32 ats = 0, vts = 0;
2890 3018
	while(goon && session != NULL && !session->destroyed &&
2891 3019
			session->status > janus_sip_call_status_idle &&
2892 3020
			session->status < janus_sip_call_status_closing) {	/* FIXME We need a per-call watchdog as well */
3021

  
3022
		if(session->media.updated) {
3023
			/* Apparently there was a session update */
3024
			if(have_server_ip)
3025
				janus_sip_connect_sockets(session, &server_addr);
3026
			session->media.updated = FALSE;
3027
		}
3028

  
2893 3029
		/* Prepare poll */
2894 3030
		num = 0;
2895 3031
		if(session->media.audio_rtp_fd != -1) {
......
2916 3052
			fds[num].revents = 0;
2917 3053
			num++;
2918 3054
		}
3055
		if(pipe_fd != -1) {
3056
			fds[num].fd = pipe_fd;
3057
			fds[num].events = POLLIN;
3058
			fds[num].revents = 0;
3059
			num++;
3060
		}
2919 3061
		/* Wait for some data */
2920 3062
		resfd = poll(fds, num, 1000);
2921 3063
		if(resfd < 0) {
......
2937 3079
				JANUS_LOG(LOG_ERR, "[SIP-%s] Error polling: %s...\n", session->account.username,
2938 3080
					fds[i].revents & POLLERR ? "POLLERR" : "POLLHUP");
2939 3081
				JANUS_LOG(LOG_ERR, "[SIP-%s]   -- %d (%s)\n", session->account.username, errno, strerror(errno));
3082
				if(session->media.updated)
3083
					break;
2940 3084
				goon = FALSE;	/* Can we assume it's pretty much over, after a POLLERR? */
2941 3085
				/* FIXME Simulate a "hangup" coming from the browser */
2942 3086
				janus_sip_message *msg = g_malloc0(sizeof(janus_sip_message));
......
2948 3092
				g_async_queue_push(messages, msg);
2949 3093
				break;
2950 3094
			} else if(fds[i].revents & POLLIN) {
3095
				if(pipe_fd != -1 && fds[i].fd == pipe_fd) {
3096
					/* Poll interrupted for a reason, go on */
3097
					int code = 0;
3098
					bytes = read(pipe_fd, &code, sizeof(int));
3099
					break;
3100
				}
2951 3101
				/* Got an RTP/RTCP packet */
2952 3102
				if(session->media.audio_rtp_fd != -1 && fds[i].fd == session->media.audio_rtp_fd) {
2953 3103
					/* Got something audio (RTP) */
2954 3104
					addrlen = sizeof(remote);
2955 3105
					bytes = recvfrom(session->media.audio_rtp_fd, buffer, 1500, 0, (struct sockaddr*)&remote, &addrlen);
2956
					//~ JANUS_LOG(LOG_VERB, "************************\nGot %d bytes on the audio RTP channel...\n", bytes);
2957
					//~ rtp_header_t *rtp = (rtp_header_t *)buffer;
2958
					//~ JANUS_LOG(LOG_VERB, " ... parsed RTP packet (ssrc=%u, pt=%u, seq=%u, ts=%u)...\n",
2959
						//~ ntohl(rtp->ssrc), rtp->type, ntohs(rtp->seq_number), ntohl(rtp->timestamp));
2960 3106
					if(session->media.audio_ssrc_peer == 0) {
2961 3107
						rtp_header *header = (rtp_header *)buffer;
2962 3108
						session->media.audio_ssrc_peer = ntohl(header->ssrc);
......
2976 3122
						}
2977 3123
						bytes = buflen;
2978 3124
					}
3125
					/* Check if the SSRC changed (e.g., after a re-INVITE or UPDATE) */
3126
					rtp_header *header = (rtp_header *)buffer;
3127
					guint32 ssrc = ntohl(header->ssrc);
3128
					guint32 timestamp = ntohl(header->timestamp);
3129
					guint16 seq = ntohs(header->seq_number);
3130
					if(ssrc != session->media.context.a_last_ssrc) {
3131
						JANUS_LOG(LOG_VERB, "Audio SSRC changed (re-INVITE?), %"SCNu32" --> %"SCNu32"\n",
3132
							session->media.context.a_last_ssrc, ssrc);
3133
						session->media.context.a_last_ssrc = ssrc;
3134
						session->media.context.a_base_ts_prev = session->media.context.a_last_ts;
3135
						session->media.context.a_base_ts = timestamp;
3136
						session->media.context.a_base_seq_prev = session->media.context.a_last_seq;
3137
						session->media.context.a_base_seq = seq;
3138
					}
3139
					/* Compute a coherent timestamp and sequence number */
3140
					session->media.context.a_last_ts = (timestamp-session->media.context.a_base_ts)
3141
						+ session->media.context.a_base_ts_prev+(astep ? astep : 960);	/* FIXME */
3142
					session->media.context.a_last_seq = (seq-session->media.context.a_base_seq)+session->media.context.a_base_seq_prev+1;
3143
					/* Update the timestamp and sequence number in the RTP packet, and send it */
3144
					header->timestamp = htonl(session->media.context.a_last_ts);
3145
					header->seq_number = htons(session->media.context.a_last_seq);
3146
					if(ats == 0) {
3147
						ats = timestamp;
3148
					} else if(astep == 0) {
3149
						astep = timestamp-ats;
3150
						if(astep < 0)
3151
							astep = 0;
3152
					}
2979 3153
					/* Save the frame if we're recording */
2980 3154
					janus_recorder_save_frame(session->arc_peer, buffer, bytes);
2981 3155
					/* Relay to browser */
......
3027 3201
						}
3028 3202
						bytes = buflen;
3029 3203
					}
3204
					/* Check if the SSRC changed (e.g., after a re-INVITE or UPDATE) */
3205
					rtp_header *header = (rtp_header *)buffer;
3206
					guint32 ssrc = ntohl(header->ssrc);
3207
					guint32 timestamp = ntohl(header->timestamp);
3208
					guint16 seq = ntohs(header->seq_number);
3209
					if(ssrc != session->media.context.v_last_ssrc) {
3210
						JANUS_LOG(LOG_VERB, "Video SSRC changed (re-INVITE?)\n");
3211
						session->media.context.v_last_ssrc = ssrc;
3212
						session->media.context.v_base_ts_prev = session->media.context.v_last_ts;
3213
						session->media.context.v_base_ts = timestamp;
3214
						session->media.context.v_base_seq_prev = session->media.context.v_last_seq;
3215
						session->media.context.v_base_seq = seq;
3216
					}
3217
					/* Compute a coherent timestamp and sequence number */
3218
					session->media.context.v_last_ts = (timestamp-session->media.context.v_base_ts)
3219
						+ session->media.context.v_base_ts_prev+(vstep ? vstep : 4500);	/* FIXME */
3220
					session->media.context.v_last_seq = (seq-session->media.context.v_base_seq)+session->media.context.v_base_seq_prev+1;
3221
					/* Update the timestamp and sequence number in the RTP packet, and send it */
3222
					header->timestamp = htonl(session->media.context.v_last_ts);
3223
					header->seq_number = htons(session->media.context.v_last_seq);
3224
					if(vts == 0) {
3225
						vts = timestamp;
3226
					} else if(vstep == 0) {
3227
						vstep = timestamp-vts;
3228
						if(vstep < 0)
3229
							vstep = 0;
3230
					}
3030 3231
					/* Save the frame if we're recording */
3031 3232
					janus_recorder_save_frame(session->vrc_peer, buffer, bytes);
3032 3233
					/* Relay to browser */
......
3077 3278
	session->media.local_video_rtp_port = 0;
3078 3279
	session->media.local_video_rtcp_port = 0;
3079 3280
	session->media.video_ssrc = 0;
3281
	if(session->media.pipefd[0] > 0) {
3282
		close(session->media.pipefd[0]);
3283
		session->media.pipefd[0] = -1;
3284
	}
3285
	if(session->media.pipefd[1] > 0) {
3286
		close(session->media.pipefd[1]);
3287
		session->media.pipefd[1] = -1;
3288
	}
3080 3289
	/* Clean up SRTP stuff, if needed */
3081 3290
	janus_sip_srtp_cleanup(session);
3082 3291
	/* Done */
......
3116 3325
	session->stack->s_nua = nua_create(session->stack->s_root,
3117 3326
				janus_sip_sofia_callback,
3118 3327
				session,
3119
				SIPTAG_ALLOW_STR("INVITE, ACK, BYE, CANCEL, OPTIONS"),
3328
				SIPTAG_ALLOW_STR("INVITE, ACK, BYE, CANCEL, OPTIONS, UPDATE"),
3120 3329
				NUTAG_M_USERNAME(session->account.username),
3121 3330
				NUTAG_URL(sip_url),
3122 3331
				TAG_IF(session->account.sips, NUTAG_SIPS_URL(sips_url)),

Also available in: Unified diff