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