1 /*
2  * The oRTP library is an RTP (Realtime Transport Protocol - rfc3550) implementation with additional features.
3  * Copyright (C) 2017 Belledonne Communications SARL
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19 
20 #include "videobandwidthestimator.h"
21 #include <ortp/logging.h>
22 #include <math.h>
23 #include <ortp/rtpsession.h>
24 
ortp_video_bandwidth_estimator_new(RtpSession * session)25 OrtpVideoBandwidthEstimator * ortp_video_bandwidth_estimator_new(RtpSession *session) {
26 	OrtpVideoBandwidthEstimator *vbe = (OrtpVideoBandwidthEstimator*)ortp_malloc0(sizeof(OrtpVideoBandwidthEstimator));
27 	vbe->session = session;
28 	vbe->packet_count_min = 5;
29 	vbe->packets_size_max = 30;
30 	vbe->trust_percentage = 90;
31     vbe->nb_packets_computed = 0;
32     vbe->packets = NULL;
33     vbe->last_packet = NULL;
34 	return vbe;
35 }
36 
ortp_video_bandwidth_estimator_destroy(OrtpVideoBandwidthEstimator * vbe)37 void ortp_video_bandwidth_estimator_destroy(OrtpVideoBandwidthEstimator *vbe){
38     ortp_video_bandwidth_estimator_reset(vbe);
39     ortp_free(vbe);
40 }
41 
ortp_video_bandwidth_estimator_reset(OrtpVideoBandwidthEstimator * vbe)42 void ortp_video_bandwidth_estimator_reset(OrtpVideoBandwidthEstimator *vbe) {
43 	ortp_free(vbe->last_packet);
44     vbe->last_packet = NULL;
45     vbe->nb_packets_computed = 0;
46 	vbe->packets = bctbx_list_free_with_data(vbe->packets, ortp_free);
47 }
48 
ortp_video_bandwidth_estimator_set_packets_count_min(OrtpVideoBandwidthEstimator * vbe,unsigned int value)49 void ortp_video_bandwidth_estimator_set_packets_count_min(OrtpVideoBandwidthEstimator *vbe, unsigned int value) {
50     vbe->packet_count_min = value;
51 }
52 
ortp_video_bandwidth_estimator_set_history_max_size(OrtpVideoBandwidthEstimator * vbe,unsigned int value)53 void ortp_video_bandwidth_estimator_set_history_max_size(OrtpVideoBandwidthEstimator *vbe, unsigned int value) {
54     vbe->packets_size_max = value;
55 }
56 
ortp_video_bandwidth_estimator_set_trust(OrtpVideoBandwidthEstimator * vbe,unsigned int value)57 void ortp_video_bandwidth_estimator_set_trust(OrtpVideoBandwidthEstimator *vbe, unsigned int value) {
58     vbe->trust_percentage = value;
59 }
60 
ortp_video_bandwidth_estimator_get_packets_count_min(OrtpVideoBandwidthEstimator * vbe)61 unsigned int ortp_video_bandwidth_estimator_get_packets_count_min(OrtpVideoBandwidthEstimator *vbe) {
62     return vbe->packet_count_min;
63 }
64 
ortp_video_bandwidth_estimator_get_history_max_size(OrtpVideoBandwidthEstimator * vbe)65 unsigned int ortp_video_bandwidth_estimator_get_history_max_size(OrtpVideoBandwidthEstimator *vbe) {
66     return vbe->packets_size_max;
67 }
68 
ortp_video_bandwidth_estimator_get_trust(OrtpVideoBandwidthEstimator * vbe)69 unsigned int ortp_video_bandwidth_estimator_get_trust(OrtpVideoBandwidthEstimator *vbe) {
70     return vbe->trust_percentage;
71 }
72 
compare_float(const float * v1,const float * v2)73 static int compare_float(const float *v1, const float *v2) {
74 	if (*v1 == *v2) return 0;
75 	if (*v1 < *v2) return 1;
76 	return -1;
77 }
78 
ortp_video_bandwidth_estimator_get_estimated_available_bandwidth(OrtpVideoBandwidthEstimator * vbe)79 float ortp_video_bandwidth_estimator_get_estimated_available_bandwidth(OrtpVideoBandwidthEstimator *vbe) {
80     bctbx_list_t *bitrate_sorted = NULL;
81     bctbx_list_t *elem;
82     float *result = NULL;
83     int index = (int)(vbe->trust_percentage * vbe->packets_size_max / 100);
84     for(elem = vbe->packets; elem != NULL; elem = bctbx_list_next(elem)) {
85         OrtpVideoBandwidthEstimatorPacket *packet = (OrtpVideoBandwidthEstimatorPacket *)bctbx_list_get_data(elem);
86         bitrate_sorted = bctbx_list_insert_sorted(bitrate_sorted, &packet->bitrate, (bctbx_compare_func)compare_float);
87     }
88     result = (float *)bctbx_list_nth_data(bitrate_sorted, index);
89     bctbx_list_free(bitrate_sorted);
90     return (float)*result;
91 }
92 
compute_bitrate_add_to_list_and_remove_oldest_value(OrtpVideoBandwidthEstimator * vbe,OrtpVideoBandwidthEstimatorPacket * packet)93 static void compute_bitrate_add_to_list_and_remove_oldest_value(OrtpVideoBandwidthEstimator *vbe, OrtpVideoBandwidthEstimatorPacket *packet) {
94 	float difftime = (float)(packet->recv_last_timestamp.tv_sec - packet->recv_first_timestamp.tv_sec)
95 		+ 1e-6f*(packet->recv_last_timestamp.tv_usec - packet->recv_first_timestamp.tv_usec);
96 	packet->bitrate = (packet->bytes * 8 / difftime);
97 	ortp_debug("[VBE] Bitrate is %f kbits/s computed using %f timedif and %u size", packet->bitrate / 1000, difftime, packet->bytes);
98 
99     vbe->nb_packets_computed += 1;
100 	vbe->packets = bctbx_list_prepend(vbe->packets, packet);
101 
102 	if (bctbx_list_size(vbe->packets) > vbe->packets_size_max) {
103 		void *old_data = bctbx_list_nth_data(vbe->packets, vbe->packets_size_max);
104 		vbe->packets = bctbx_list_remove(vbe->packets, old_data);
105 	}
106 
107     if (vbe->nb_packets_computed % vbe->packets_size_max == 0) {
108         OrtpEvent *ev = ortp_event_new(ORTP_EVENT_NEW_VIDEO_BANDWIDTH_ESTIMATION_AVAILABLE);
109         OrtpEventData *ed = ortp_event_get_data(ev);
110         ed->info.video_bandwidth_available = ortp_video_bandwidth_estimator_get_estimated_available_bandwidth(vbe);
111         ortp_debug("[VBE] Dispatching event ORTP_EVENT_NEW_VIDEO_BANDWIDTH_ESTIMATION_AVAILABLE with value %f kbits/s", ed->info.video_bandwidth_available / 1000);
112         rtp_session_dispatch_event(vbe->session, ev);
113     }
114 }
115 
ortp_video_bandwidth_estimator_process_packet(OrtpVideoBandwidthEstimator * vbe,uint32_t sent_timestamp,const struct timeval * recv_timestamp,int msgsize,bool_t is_last)116 void ortp_video_bandwidth_estimator_process_packet(OrtpVideoBandwidthEstimator *vbe, uint32_t sent_timestamp, const struct timeval *recv_timestamp, int msgsize, bool_t is_last) {
117 	OrtpVideoBandwidthEstimatorPacket *last_packet = vbe->last_packet;
118 	OrtpVideoBandwidthEstimatorPacket *current_packet = NULL;
119 
120 	if (last_packet) {
121 		if (last_packet->sent_timestamp == sent_timestamp) {
122 			current_packet = last_packet;
123 			current_packet->count += 1;
124 			current_packet->bytes += msgsize;
125 			current_packet->recv_last_timestamp.tv_sec = recv_timestamp->tv_sec;
126 			current_packet->recv_last_timestamp.tv_usec = recv_timestamp->tv_usec;
127 
128 			if (is_last && current_packet->count >= vbe->packet_count_min) {
129 				compute_bitrate_add_to_list_and_remove_oldest_value(vbe, current_packet);
130 				vbe->last_packet = NULL;
131 			}
132 		} else {
133 			// This can happen even if it's probability is quite low
134 			if (last_packet->count >= vbe->packet_count_min) {
135 				ortp_warning("[VBE] Last packet not complete but enough packet received (%u), add to packets list", last_packet->count);
136 				compute_bitrate_add_to_list_and_remove_oldest_value(vbe, last_packet);
137 			} else {
138 				ortp_free(vbe->last_packet);
139 			}
140 			vbe->last_packet = NULL;
141 		}
142 	}
143 
144 	if (!current_packet) {
145 		current_packet = (OrtpVideoBandwidthEstimatorPacket*)ortp_malloc0(sizeof(OrtpVideoBandwidthEstimatorPacket));
146 		current_packet->count = 1;
147 		current_packet->bytes = msgsize;
148 		current_packet->sent_timestamp = sent_timestamp;
149 		current_packet->recv_first_timestamp.tv_sec = recv_timestamp->tv_sec;
150 		current_packet->recv_first_timestamp.tv_usec = recv_timestamp->tv_usec;
151 		vbe->last_packet = current_packet;
152 	}
153 }
154