Revision 242e4f31 plugins/janus_videoroom.c

View differences:

plugins/janus_videoroom.c
66 66
fir_freq = <send a FIR to publishers every fir_freq seconds> (0=disable)
67 67
audiocodec = opus|isac32|isac16|pcmu|pcma|g722 (audio codec to force on publishers, default=opus)
68 68
videocodec = vp8|vp9|h264 (video codec to force on publishers, default=vp8)
69
video_svc = yes|no (whether SVC support must be enabled; works only for VP9, default=no)
69 70
audiolevel_ext = yes|no (whether the ssrc-audio-level RTP extension must be
70 71
	negotiated/used or not for new publishers, default=yes)
71 72
audiolevel_event = yes|no (whether to emit event to other users or not)
......
148 149

  
149 150

  
150 151
/* Plugin information */
151
#define JANUS_VIDEOROOM_VERSION			8
152
#define JANUS_VIDEOROOM_VERSION_STRING	"0.0.8"
152
#define JANUS_VIDEOROOM_VERSION			9
153
#define JANUS_VIDEOROOM_VERSION_STRING	"0.0.9"
153 154
#define JANUS_VIDEOROOM_DESCRIPTION		"This is a plugin implementing a videoconferencing SFU (Selective Forwarding Unit) for Janus, that is an audio/video router."
154 155
#define JANUS_VIDEOROOM_NAME			"JANUS VideoRoom plugin"
155 156
#define JANUS_VIDEOROOM_AUTHOR			"Meetecho s.r.l."
......
229 230
	{"publishers", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
230 231
	{"audiocodec", JSON_STRING, 0},
231 232
	{"videocodec", JSON_STRING, 0},
233
	{"video_svc", JANUS_JSON_BOOL, 0},
232 234
	{"audiolevel_ext", JANUS_JSON_BOOL, 0},
233 235
	{"audiolevel_event", JANUS_JSON_BOOL, 0},
234 236
	{"audio_active_packets", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
......
300 302
static struct janus_json_parameter configure_parameters[] = {
301 303
	{"audio", JANUS_JSON_BOOL, 0},
302 304
	{"video", JANUS_JSON_BOOL, 0},
303
	{"data", JANUS_JSON_BOOL, 0}
305
	{"data", JANUS_JSON_BOOL, 0},
306
	{"spatial_layer", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
307
	{"temporal_layer", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE}
304 308
};
305 309
static struct janus_json_parameter listener_parameters[] = {
306 310
	{"feed", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE},
......
447 451
			return VP8_PT;
448 452
	}
449 453
}
454
/* Helper method to parse an RTP video frame and get some SVC-related info
455
 * (note: this only works with VP9, right now, on an experimental basis) */
456
static int janus_videoroom_videocodec_parse_svc(janus_videoroom_videocodec vcodec,
457
	char *buf, int total, int *found,
458
	int *spatial_layer, int *temporal_layer,
459
	uint8_t *p, uint8_t *d, uint8_t *u, uint8_t *b, uint8_t *e);
460

  
450 461

  
451 462
typedef struct janus_videoroom {
452 463
	guint64 room_id;			/* Unique room ID */
......
460 471
	uint16_t fir_freq;			/* Regular FIR frequency (0=disabled) */
461 472
	janus_videoroom_audiocodec acodec;	/* Audio codec to force on publishers*/
462 473
	janus_videoroom_videocodec vcodec;	/* Video codec to force on publishers*/
474
	gboolean do_svc;			/* Whether SVC must be done for video (note: only available for VP9 right now) */
463 475
	gboolean audiolevel_ext;	/* Whether the ssrc-audio-level extension must be negotiated or not for new publishers */
464 476
	gboolean audiolevel_event;	/* Whether to emit event to other users about audiolevel */
465 477
	int audio_active_packets;	/* amount of packets with audio level for checkup */
......
559 571
	gboolean audio, video, data;		/* Whether audio, video and/or data must be sent to this publisher */
560 572
	gboolean paused;
561 573
	gboolean kicked;	/* Whether this subscription belongs to a participant that has been kicked */
574
	/* The following are only relevant if we're doing VP9 SVC*/
575
	int spatial_layer, target_spatial_layer;
576
	int temporal_layer, target_temporal_layer;
562 577
} janus_videoroom_listener;
563 578
static void janus_videoroom_listener_free(janus_videoroom_listener *l);
564 579

  
......
568 583
	gboolean is_video;
569 584
	uint32_t timestamp;
570 585
	uint16_t seq_number;
586
	/* The following are only relevant if we're doing VP9 SVC*/
587
	gboolean svc;
588
	int spatial_layer;
589
	int temporal_layer;
590
	uint8_t pbit, dbit, ubit, bbit, ebit;
571 591
} janus_videoroom_rtp_relay_packet;
572 592

  
573 593

  
......
785 805
			janus_config_item *firfreq = janus_config_get_item(cat, "fir_freq");
786 806
			janus_config_item *audiocodec = janus_config_get_item(cat, "audiocodec");
787 807
			janus_config_item *videocodec = janus_config_get_item(cat, "videocodec");
808
			janus_config_item *svc = janus_config_get_item(cat, "video_svc");
788 809
			janus_config_item *audiolevel_ext = janus_config_get_item(cat, "audiolevel_ext");
789 810
			janus_config_item *audiolevel_event = janus_config_get_item(cat, "audiolevel_event");
790 811
			janus_config_item *audio_active_packets = janus_config_get_item(cat, "audio_active_packets");
......
855 876
					videoroom->vcodec = JANUS_VIDEOROOM_VP8;
856 877
				}
857 878
			}
879
			if(svc && svc->value && janus_is_true(svc->value)) {
880
				if(videoroom->vcodec == JANUS_VIDEOROOM_VP9) {
881
					videoroom->do_svc = TRUE;
882
				} else {
883
					JANUS_LOG(LOG_WARN, "SVC is only supported, in an experimental way, for VP9, not %s: disabling it...\n",
884
						janus_videoroom_videocodec_name(videoroom->vcodec));
885
				}
886
			}
858 887
			videoroom->audiolevel_ext = TRUE;
859 888
			if(audiolevel_ext != NULL && audiolevel_ext->value != NULL)
860 889
				videoroom->audiolevel_ext = janus_is_true(audiolevel_ext->value);
......
1185 1214
				json_object_set_new(media, "video", json_integer(participant->video));
1186 1215
				json_object_set_new(media, "data", json_integer(participant->data));
1187 1216
				json_object_set_new(info, "media", media);
1217
				if(participant->room && participant->room->do_svc) {
1218
					json_t *svc = json_object();
1219
					json_object_set_new(svc, "spatial-layer", json_integer(participant->spatial_layer));
1220
					json_object_set_new(svc, "target-spatial-layer", json_integer(participant->target_spatial_layer));
1221
					json_object_set_new(svc, "temporal-layer", json_integer(participant->temporal_layer));
1222
					json_object_set_new(svc, "target-temporal-layer", json_integer(participant->target_temporal_layer));
1223
					json_object_set_new(info, "svc", svc);
1224
				}
1188 1225
			}
1189 1226
		}
1190 1227
	}
......
1329 1366
				goto plugin_response;
1330 1367
			}
1331 1368
		}
1369
		json_t *svc = json_object_get(root, "video_svc");
1332 1370
		json_t *audiolevel_ext = json_object_get(root, "audiolevel_ext");
1333 1371
		json_t *audiolevel_event = json_object_get(root, "audiolevel_event");
1334 1372
		json_t *audio_active_packets = json_object_get(root, "audio_active_packets");
......
1460 1498
				videoroom->vcodec = JANUS_VIDEOROOM_VP8;
1461 1499
			}
1462 1500
		}
1501
		if(svc && json_is_true(svc)) {
1502
			if(videoroom->vcodec == JANUS_VIDEOROOM_VP9) {
1503
				videoroom->do_svc = TRUE;
1504
			} else {
1505
				JANUS_LOG(LOG_WARN, "SVC is only supported, in an experimental way, for VP9, not %s: disabling it...\n",
1506
					janus_videoroom_videocodec_name(videoroom->vcodec));
1507
			}
1508
		}
1463 1509
		videoroom->audiolevel_ext = audiolevel_ext ? json_is_true(audiolevel_ext) : TRUE;
1464 1510
		videoroom->audiolevel_event = audiolevel_event ? json_is_true(audiolevel_event) : FALSE;
1465 1511
		if(videoroom->audiolevel_event) {
......
1537 1583
			}
1538 1584
			janus_config_add_item(config, cat, "audiocodec", janus_videoroom_audiocodec_name(videoroom->acodec));
1539 1585
			janus_config_add_item(config, cat, "videocodec", janus_videoroom_videocodec_name(videoroom->vcodec));
1586
			if(videoroom->do_svc)
1587
				janus_config_add_item(config, cat, "video_svc", "yes");
1540 1588
			if(videoroom->room_secret)
1541 1589
				janus_config_add_item(config, cat, "secret", videoroom->room_secret);
1542 1590
			if(videoroom->room_pin)
......
1674 1722
				json_object_set_new(rl, "fir_freq", json_integer(room->fir_freq));
1675 1723
				json_object_set_new(rl, "audiocodec", json_string(janus_videoroom_audiocodec_name(room->acodec)));
1676 1724
				json_object_set_new(rl, "videocodec", json_string(janus_videoroom_videocodec_name(room->vcodec)));
1725
				if(room->do_svc)
1726
					json_object_set_new(rl, "video_svc", json_true());
1677 1727
				json_object_set_new(rl, "record", room->record ? json_true() : json_false());
1678 1728
				json_object_set_new(rl, "rec_dir", json_string(room->rec_dir));
1679 1729
				/* TODO: Should we list participants as well? or should there be a separate API call on a specific room for this? */
......
2397 2447
		packet.data = rtp;
2398 2448
		packet.length = len;
2399 2449
		packet.is_video = video;
2450
		packet.svc = FALSE;
2451
		if(video && videoroom->do_svc) {
2452
			/* We're doing SVC: let's parse this packet to see which layers are there */
2453
			uint8_t pbit = 0, dbit = 0, ubit = 0, bbit = 0, ebit = 0;
2454
			int found = 0, spatial_layer = 0, temporal_layer = 0;
2455
			if(janus_videoroom_videocodec_parse_svc(videoroom->vcodec, buf, len, &found, &spatial_layer, &temporal_layer, &pbit, &dbit, &ubit, &bbit, &ebit) == 0) {
2456
				if(found) {
2457
					packet.svc = TRUE;
2458
					packet.spatial_layer = spatial_layer;
2459
					packet.temporal_layer = temporal_layer;
2460
					packet.pbit = pbit;
2461
					packet.dbit = dbit;
2462
					packet.ubit = ubit;
2463
					packet.bbit = bbit;
2464
					packet.ebit = ebit;
2465
					JANUS_LOG(LOG_WARN, "sl=%d, tl=%d, p=%u, d=%u, u=%u, b=%u, e=%u\n",
2466
						packet.spatial_layer, packet.temporal_layer,
2467
						packet.pbit, packet.dbit, packet.ubit, packet.bbit, packet.ebit);
2468
				}
2469
			}
2470
		}
2400 2471
		/* Backup the actual timestamp and sequence number set by the publisher, in case switching is involved */
2401 2472
		packet.timestamp = ntohl(packet.data->timestamp);
2402 2473
		packet.seq_number = ntohs(packet.data->seq_number);
......
3088 3159
						listener->data = FALSE;	/* ... unless the publisher isn't sending any data */
3089 3160
					listener->paused = TRUE;	/* We need an explicit start from the listener */
3090 3161
					session->participant = listener;
3162
					if(videoroom->do_svc) {
3163
						/* This listener belongs to a room where VP9 SVC has been enabled,
3164
						 * let's assume we're interested in all layers for the time being */
3165
						listener->spatial_layer = -1;
3166
						listener->target_spatial_layer = 1;		/* FIXME Chrome sends 0 and 1 */
3167
						listener->temporal_layer = -1;
3168
						listener->target_temporal_layer = 2;	/* FIXME Chrome sends 0, 1 and 2 */
3169
					}
3091 3170
					janus_mutex_lock(&publisher->listeners_mutex);
3092 3171
					publisher->listeners = g_slist_append(publisher->listeners, listener);
3093 3172
					janus_mutex_unlock(&publisher->listeners_mutex);
......
3388 3467
				json_t *audio = json_object_get(root, "audio");
3389 3468
				json_t *video = json_object_get(root, "video");
3390 3469
				json_t *data = json_object_get(root, "data");
3470
				json_t *spatial = json_object_get(root, "spatial_layer");
3471
				json_t *temporal = json_object_get(root, "temporal_layer");
3391 3472
				/* Update the audio/video/data flags, if set */
3392 3473
				janus_videoroom_participant *publisher = listener->feed;
3393 3474
				if(publisher) {
......
3398 3479
					if(data && publisher->data)
3399 3480
						listener->data = json_is_true(data);
3400 3481
				}
3482
				if(listener->room->do_svc) {
3483
					/* Also check if the viewer is trying to configure a layer change */
3484
					if(spatial) {
3485
						int spatial_layer = json_integer_value(spatial);
3486
						if(spatial_layer > 1) {
3487
							JANUS_LOG(LOG_WARN, "Spatial layer higher than 1, will probably be ignored\n");
3488
						}
3489
						if(spatial_layer != listener->target_spatial_layer) {
3490
							/* Send a FIR to the new RTP forward publisher */
3491
							char buf[20];
3492
							janus_rtcp_fir((char *)&buf, 20, &publisher->fir_seq);
3493
							JANUS_LOG(LOG_VERB, "Need to downscale spatially, sending FIR to %"SCNu64" (%s)\n", publisher->user_id, publisher->display ? publisher->display : "??");
3494
							gateway->relay_rtcp(publisher->session->handle, 1, buf, 20);
3495
							/* Send a PLI too, just in case... */
3496
							janus_rtcp_pli((char *)&buf, 12);
3497
							JANUS_LOG(LOG_VERB, "Need to downscale spatially, sending PLI to %"SCNu64" (%s)\n", publisher->user_id, publisher->display ? publisher->display : "??");
3498
							gateway->relay_rtcp(publisher->session->handle, 1, buf, 12);
3499
						}
3500
						listener->target_spatial_layer = spatial_layer;
3501
					}
3502
					if(temporal) {
3503
						int temporal_layer = json_integer_value(temporal);
3504
						if(temporal_layer > 2) {
3505
							JANUS_LOG(LOG_WARN, "Temporal layer higher than 2, will probably be ignored\n");
3506
						}
3507
						listener->target_temporal_layer = temporal_layer;
3508
					}
3509
				}
3401 3510
				event = json_object();
3402 3511
				json_object_set_new(event, "videoroom", json_string("event"));
3403 3512
				json_object_set_new(event, "room", json_integer(listener->room->room_id));
......
3462 3571
				listener->data = data ? json_is_true(data) : TRUE;	/* True by default */
3463 3572
				if(!publisher->data)
3464 3573
					listener->data = FALSE;	/* ... unless the publisher isn't sending any data */
3574
				if(listener->room && listener->room->do_svc) {
3575
					/* This listener belongs to a room where VP9 SVC has been enabled,
3576
					 * let's assume we're interested in all layers for the time being */
3577
					listener->spatial_layer = -1;
3578
					listener->target_spatial_layer = 1;		/* FIXME Chrome sends 0 and 1 */
3579
					listener->temporal_layer = -1;
3580
					listener->target_temporal_layer = 2;	/* FIXME Chrome sends 0, 1 and 2 */
3581
				}
3465 3582
				janus_mutex_lock(&publisher->listeners_mutex);
3466 3583
				publisher->listeners = g_slist_append(publisher->listeners, listener);
3467 3584
				janus_mutex_unlock(&publisher->listeners_mutex);
......
3828 3945
	return NULL;
3829 3946
}
3830 3947

  
3948
/* Helper method to parse an RTP video frame and get some SVC-related info */
3949
static int janus_videoroom_videocodec_parse_svc(janus_videoroom_videocodec vcodec,
3950
		char *buf, int total, int *found,
3951
		int *spatial_layer, int *temporal_layer,
3952
		uint8_t *p, uint8_t *d, uint8_t *u, uint8_t *b, uint8_t *e) {
3953
	if(found)
3954
		*found = 0;
3955
	if(!buf || total < 12)
3956
		return -1;
3957
	/* This only works with VP9, right now, on an experimental basis) */
3958
	if(vcodec != JANUS_VIDEOROOM_VP9)
3959
		return -2;
3960
	/* Skip RTP header and extensions */
3961
	int len = 0;
3962
	char *buffer = janus_rtp_payload(buf, total, &len);
3963
	/* VP9 depay: */
3964
		/* https://tools.ietf.org/html/draft-ietf-payload-vp9-03 */
3965
	/* Read the first octet (VP9 Payload Descriptor) */
3966
	uint8_t vp9pd = *buffer;
3967
	uint8_t ibit = (vp9pd & 0x80) >> 7;
3968
	uint8_t pbit = (vp9pd & 0x40) >> 6;
3969
	uint8_t lbit = (vp9pd & 0x20) >> 5;
3970
	uint8_t fbit = (vp9pd & 0x10) >> 4;
3971
	uint8_t bbit = (vp9pd & 0x08) >> 3;
3972
	uint8_t ebit = (vp9pd & 0x04) >> 2;
3973
	uint8_t vbit = (vp9pd & 0x02) >> 1;
3974
	if(!lbit) {
3975
		/* No Layer indices present, no need to go on */
3976
		if(found)
3977
			*found = 0;
3978
		return 0;
3979
	}
3980
	/* Move to the next octet and see what's there */
3981
	buffer++;
3982
	len--;
3983
	if(ibit) {
3984
		/* Read the PictureID octet */
3985
		vp9pd = *buffer;
3986
		uint16_t picid = vp9pd, wholepicid = picid;
3987
		uint8_t mbit = (vp9pd & 0x80);
3988
		if(!mbit) {
3989
			buffer++;
3990
			len--;
3991
		} else {
3992
			memcpy(&picid, buffer, sizeof(uint16_t));
3993
			wholepicid = ntohs(picid);
3994
			picid = (wholepicid & 0x7FFF);
3995
			buffer += 2;
3996
			len -= 2;
3997
		}
3998
	}
3999
	if(lbit) {
4000
		/* Read the octet and parse the layer indices now */
4001
		vp9pd = *buffer;
4002
		int tlid = (vp9pd & 0xE0) >> 5;
4003
		uint8_t ubit = (vp9pd & 0x10) >> 4;
4004
		int slid = (vp9pd & 0x0E) >> 1;
4005
		uint8_t dbit = (vp9pd & 0x01);
4006
		JANUS_LOG(LOG_HUGE, "Parsed Layer indices: Temporal: %d (%u), Spatial: %d (%u)\n",
4007
			tlid, ubit, slid, dbit);
4008
		if(temporal_layer)
4009
			*temporal_layer = tlid;
4010
		if(spatial_layer)
4011
			*spatial_layer = slid;
4012
		if(p)
4013
			*p = pbit;
4014
		if(d)
4015
			*d = dbit;
4016
		if(u)
4017
			*u = ubit;
4018
		if(b)
4019
			*b = bbit;
4020
		if(e)
4021
			*e = ebit;
4022
		if(found)
4023
			*found = 1;
4024
		/* Go on, just to get to the SS, if available (which we currently ignore anyway) */
4025
		buffer++;
4026
		len--;
4027
		if(!fbit) {
4028
			/* Non-flexible mode, skip TL0PICIDX */
4029
			buffer++;
4030
			len--;
4031
		}
4032
	}
4033
	if(fbit && pbit) {
4034
		/* Skip reference indices */
4035
		uint8_t nbit = 1;
4036
		while(nbit) {
4037
			vp9pd = *buffer;
4038
			nbit = (vp9pd & 0x01);
4039
			buffer++;
4040
			len--;
4041
		}
4042
	}
4043
	if(vbit) {
4044
		/* Parse and skip SS */
4045
		vp9pd = *buffer;
4046
		int n_s = (vp9pd & 0xE0) >> 5;
4047
		n_s++;
4048
		JANUS_LOG(LOG_HUGE, "There are %d spatial layers\n", n_s);
4049
		uint8_t ybit = (vp9pd & 0x10);
4050
		uint8_t gbit = (vp9pd & 0x08);
4051
		if(ybit) {
4052
			/* Iterate on all spatial layers and get resolution */
4053
			buffer++;
4054
			len--;
4055
			int i=0;
4056
			for(i=0; i<n_s; i++) {
4057
				/* Been there, done that: skip skip skip */
4058
				buffer += 4;
4059
				len -= 4;
4060
			}
4061
		}
4062
		if(gbit) {
4063
			if(!ybit) {
4064
				buffer++;
4065
				len--;
4066
			}
4067
			uint8_t n_g = *buffer;
4068
			JANUS_LOG(LOG_HUGE, "There are %u frames in a GOF\n", n_g);
4069
			buffer++;
4070
			len--;
4071
			if(n_g > 0) {
4072
				int i=0;
4073
				for(i=0; i<n_g; i++) {
4074
					/* Read the R bits */
4075
					vp9pd = *buffer;
4076
					int r = (vp9pd & 0x0C) >> 2;
4077
					if(r > 0) {
4078
						/* Skip reference indices */
4079
						buffer += r;
4080
						len -= r;
4081
					}
4082
					buffer++;
4083
					len--;
4084
				}
4085
			}
4086
		}
4087
	}
4088
	return 0;
4089
}
3831 4090

  
3832 4091
/* Helper to quickly relay RTP packets from publishers to subscribers */
3833 4092
static void janus_videoroom_relay_rtp_packet(gpointer data, gpointer user_data) {
......
3862 4121
			/* Nope, don't relay */
3863 4122
			return;
3864 4123
		}
4124
		/* Check if there's any SVC info to take into account */
4125
		gboolean override_mark_bit = FALSE, has_marker_bit = packet->data->markerbit;
4126
		if(packet->svc) {
4127
			/* There is: check if this is a layer that can be dropped for this viewer
4128
			 * Note: Following core inspired by the excellent job done by Sergio Garcia Murillo here:
4129
			 * https://github.com/medooze/media-server/blob/master/src/vp9/VP9LayerSelector.cpp */
4130
			int temporal_layer = listener->temporal_layer;
4131
			if(listener->target_temporal_layer > listener->temporal_layer) {
4132
				/* We need to upscale */
4133
				JANUS_LOG(LOG_WARN, "We need to upscale temporally:\n");
4134
				if(packet->ubit && packet->bbit && packet->temporal_layer <= listener->target_temporal_layer) {
4135
					JANUS_LOG(LOG_WARN, "  -- Upscaling temporal layer: %u --> %u\n",
4136
						packet->temporal_layer, listener->target_temporal_layer);
4137
					listener->temporal_layer = packet->temporal_layer;
4138
					temporal_layer = listener->temporal_layer;
4139
				}
4140
			} else if(listener->target_temporal_layer < listener->temporal_layer) {
4141
				/* We need to downscale */
4142
				JANUS_LOG(LOG_WARN, "We need to downscale temporally:\n");
4143
				if(packet->ebit) {
4144
					JANUS_LOG(LOG_WARN, "  -- Downscaling temporal layer: %u --> %u\n",
4145
						listener->temporal_layer, listener->target_temporal_layer);
4146
					listener->temporal_layer = listener->target_temporal_layer;
4147
				}
4148
			}
4149
			if(temporal_layer < packet->temporal_layer) {
4150
				/* Drop the packet: update the context to make sure sequence number is increased normally later */
4151
				JANUS_LOG(LOG_WARN, "Dropping packet (temporal layer %d < %d)\n", temporal_layer, packet->temporal_layer);
4152
				listener->context.v_base_seq++;
4153
				return;
4154
			}
4155
			int spatial_layer = listener->spatial_layer;
4156
			if(listener->target_spatial_layer > listener->spatial_layer) {
4157
				JANUS_LOG(LOG_WARN, "We need to upscale spatially:\n");
4158
				/* We need to upscale */
4159
				if(packet->pbit == 0 && packet->bbit && packet->spatial_layer == listener->spatial_layer+1) {
4160
					JANUS_LOG(LOG_WARN, "  -- Upscaling spatial layer: %u --> %u\n",
4161
						packet->spatial_layer, listener->target_spatial_layer);
4162
					listener->spatial_layer = packet->spatial_layer;
4163
					spatial_layer = listener->spatial_layer;
4164
				}
4165
			} else if(listener->target_spatial_layer < listener->spatial_layer) {
4166
				/* We need to downscale */
4167
				JANUS_LOG(LOG_WARN, "We need to downscale spatially:\n");
4168
				if(packet->ebit) {
4169
					JANUS_LOG(LOG_WARN, "  -- Downscaling spatial layer: %u --> %u\n",
4170
						listener->spatial_layer, listener->target_spatial_layer);
4171
					listener->spatial_layer = listener->target_spatial_layer;
4172
				}
4173
			}
4174
			if(spatial_layer < packet->spatial_layer) {
4175
				/* Drop the packet: update the context to make sure sequence number is increased normally later */
4176
				JANUS_LOG(LOG_HUGE, "Dropping packet (spatial layer %d < %d)\n", spatial_layer, packet->spatial_layer);
4177
				listener->context.v_base_seq++;
4178
				return;
4179
			} else if(packet->ebit && spatial_layer == packet->spatial_layer) {
4180
				/* If we stop at layer 0, we need a marker bit now, as the one from layer 1 will not be received */
4181
				override_mark_bit = TRUE;
4182
			}
4183
			/* If we got here, we can send the frame: this doesn't necessarily mean it's
4184
			 * one of the layers the user wants, as there may be dependencies involved */
4185
			JANUS_LOG(LOG_HUGE, "Sending packet (spatial=%d, temporal=%d)\n",
4186
				packet->spatial_layer, packet->temporal_layer);
4187
		}
3865 4188
		/* Fix sequence number and timestamp (publisher switching may be involved) */
3866 4189
		janus_rtp_header_update(packet->data, &listener->context, TRUE, 4500);
4190
		if(override_mark_bit && !has_marker_bit) {
4191
			packet->data->markerbit = 1;
4192
		}
3867 4193
		if(gateway != NULL)
3868 4194
			gateway->relay_rtp(session->handle, packet->is_video, (char *)packet->data, packet->length);
4195
		if(override_mark_bit && !has_marker_bit) {
4196
			packet->data->markerbit = 0;
4197
		}
3869 4198
		/* Restore the timestamp and sequence number to what the publisher set them to */
3870 4199
		packet->data->timestamp = htonl(packet->timestamp);
3871 4200
		packet->data->seq_number = htons(packet->seq_number);

Also available in: Unified diff