return _create_local_media_description(lc,call,id,id);
}
-static int find_port_offset(LinphoneCore *lc){
+static int find_port_offset(LinphoneCore *lc, SalStreamType type){
int offset;
MSList *elem;
- int audio_port;
+ int tried_port;
+ int existing_port;
bool_t already_used=FALSE;
for(offset=0;offset<100;offset+=2){
- audio_port=linphone_core_get_audio_port (lc)+offset;
+ switch (type) {
+ default:
+ case SalAudio:
+ tried_port=linphone_core_get_audio_port (lc)+offset;
+ break;
+ case SalVideo:
+ tried_port=linphone_core_get_video_port (lc)+offset;
+ break;
+ }
already_used=FALSE;
for(elem=lc->calls;elem!=NULL;elem=elem->next){
LinphoneCall *call=(LinphoneCall*)elem->data;
- if (call->audio_port==audio_port) {
+ switch (type) {
+ default:
+ case SalAudio:
+ existing_port = call->audio_port;
+ break;
+ case SalVideo:
+ existing_port = call->video_port;
+ break;
+ }
+ if (existing_port==tried_port) {
already_used=TRUE;
break;
}
return offset;
}
+static int select_random_port(LinphoneCore *lc, SalStreamType type) {
+ MSList *elem;
+ int nb_tries;
+ int tried_port = 0;
+ int existing_port = 0;
+ int min_port = 0, max_port = 0;
+ bool_t already_used = FALSE;
+
+ switch (type) {
+ default:
+ case SalAudio:
+ linphone_core_get_audio_port_range(lc, &min_port, &max_port);
+ break;
+ case SalVideo:
+ linphone_core_get_video_port_range(lc, &min_port, &max_port);
+ break;
+ }
+ tried_port = (rand() % (max_port - min_port) + min_port) & ~0x1;
+ if (tried_port < min_port) tried_port = min_port + 2;
+ for (nb_tries = 0; nb_tries < 100; nb_tries++) {
+ for (elem = lc->calls; elem != NULL; elem = elem->next) {
+ LinphoneCall *call = (LinphoneCall *)elem->data;
+ switch (type) {
+ default:
+ case SalAudio:
+ existing_port = call->audio_port;
+ break;
+ case SalVideo:
+ existing_port = call->video_port;
+ break;
+ }
+ if (existing_port == tried_port) {
+ already_used = TRUE;
+ break;
+ }
+ }
+ if (!already_used) break;
+ }
+ if (nb_tries == 100) {
+ ms_error("Could not find any free port!");
+ return -1;
+ }
+ return tried_port;
+}
+
static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){
int port_offset;
+ int min_port, max_port;
call->magic=linphone_call_magic;
call->refcnt=1;
call->state=LinphoneCallIdle;
call->log=linphone_call_log_new(call, from, to);
call->owns_call_log=TRUE;
linphone_core_notify_all_friends(call->core,LinphoneStatusOnThePhone);
- port_offset=find_port_offset (call->core);
- if (port_offset==-1) return;
- call->audio_port=linphone_core_get_audio_port(call->core)+port_offset;
- call->video_port=linphone_core_get_video_port(call->core)+port_offset;
+ linphone_core_get_audio_port_range(call->core, &min_port, &max_port);
+ if (min_port == max_port) {
+ /* Used fixed RTP audio port. */
+ port_offset=find_port_offset (call->core, SalAudio);
+ if (port_offset==-1) return;
+ call->audio_port=linphone_core_get_audio_port(call->core)+port_offset;
+ } else {
+ /* Select random RTP audio port in the specified range. */
+ call->audio_port = select_random_port(call->core, SalAudio);
+ }
+ linphone_core_get_video_port_range(call->core, &min_port, &max_port);
+ if (min_port == max_port) {
+ /* Used fixed RTP video port. */
+ port_offset=find_port_offset (call->core, SalVideo);
+ if (port_offset==-1) return;
+ call->video_port=linphone_core_get_video_port(call->core)+port_offset;
+ } else {
+ /* Select random RTP video port in the specified range. */
+ call->video_port = select_random_port(call->core, SalVideo);
+ }
linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO], LINPHONE_CALL_STATS_AUDIO);
linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO], LINPHONE_CALL_STATS_VIDEO);
}
static void rtp_config_read(LinphoneCore *lc)
{
- int port;
+ int min_port, max_port;
int jitt_comp;
int nortp_timeout;
bool_t rtp_no_xmit_on_audio_mute;
bool_t adaptive_jitt_comp_enabled;
- port=lp_config_get_int(lc->config,"rtp","audio_rtp_port",7078);
- linphone_core_set_audio_port(lc,port);
+ if (lp_config_get_range(lc->config, "rtp", "audio_rtp_port", &min_port, &max_port, 7078, 7078) == TRUE) {
+ if (min_port <= 0) min_port = 1;
+ if (max_port > 65535) max_port = 65535;
+ linphone_core_set_audio_port_range(lc, min_port, max_port);
+ } else {
+ min_port = lp_config_get_int(lc->config, "rtp", "audio_rtp_port", 7078);
+ linphone_core_set_audio_port(lc, min_port);
+ }
- port=lp_config_get_int(lc->config,"rtp","video_rtp_port",9078);
- if (port==0) port=9078;
- linphone_core_set_video_port(lc,port);
+ if (lp_config_get_range(lc->config, "rtp", "video_rtp_port", &min_port, &max_port, 9078, 9078) == TRUE) {
+ if (min_port <= 0) min_port = 1;
+ if (max_port > 65535) max_port = 65535;
+ linphone_core_set_video_port_range(lc, min_port, max_port);
+ } else {
+ min_port = lp_config_get_int(lc->config, "rtp", "video_rtp_port", 9078);
+ linphone_core_set_video_port(lc, min_port);
+ }
jitt_comp=lp_config_get_int(lc->config,"rtp","audio_jitt_comp",60);
linphone_core_set_audio_jittcomp(lc,jitt_comp);
**/
int linphone_core_get_audio_port(const LinphoneCore *lc)
{
- return lc->rtp_conf.audio_rtp_port;
+ return lc->rtp_conf.audio_rtp_min_port;
+}
+
+/**
+ * Get the audio port range from which is randomly chosen the UDP port used for audio streaming.
+ *
+ * @ingroup network_parameters
+ */
+void linphone_core_get_audio_port_range(const LinphoneCore *lc, int *min_port, int *max_port)
+{
+ *min_port = lc->rtp_conf.audio_rtp_min_port;
+ *max_port = lc->rtp_conf.audio_rtp_max_port;
}
/**
* @ingroup network_parameters
**/
int linphone_core_get_video_port(const LinphoneCore *lc){
- return lc->rtp_conf.video_rtp_port;
+ return lc->rtp_conf.video_rtp_min_port;
+}
+
+/**
+ * Get the video port range from which is randomly chosen the UDP port used for video streaming.
+ *
+ * @ingroup network_parameters
+ */
+void linphone_core_get_video_port_range(const LinphoneCore *lc, int *min_port, int *max_port)
+{
+ *min_port = lc->rtp_conf.video_rtp_min_port;
+ *max_port = lc->rtp_conf.video_rtp_max_port;
}
**/
void linphone_core_set_audio_port(LinphoneCore *lc, int port)
{
- lc->rtp_conf.audio_rtp_port=port;
+ lc->rtp_conf.audio_rtp_min_port=lc->rtp_conf.audio_rtp_max_port=port;
+}
+
+/**
+ * Sets the UDP port range from which to randomly select the port used for audio streaming.
+ */
+void linphone_core_set_audio_port_range(LinphoneCore *lc, int min_port, int max_port)
+{
+ lc->rtp_conf.audio_rtp_min_port=min_port;
+ lc->rtp_conf.audio_rtp_max_port=max_port;
}
/**
* @ingroup network_parameters
**/
void linphone_core_set_video_port(LinphoneCore *lc, int port){
- lc->rtp_conf.video_rtp_port=port;
+ lc->rtp_conf.video_rtp_min_port=lc->rtp_conf.video_rtp_max_port=port;
+}
+
+/**
+ * Sets the UDP port range from which to randomly select the port used for video streaming.
+ */
+void linphone_core_set_video_port_range(LinphoneCore *lc, int min_port, int max_port)
+{
+ lc->rtp_conf.video_rtp_min_port=min_port;
+ lc->rtp_conf.video_rtp_max_port=max_port;
}
/**
void rtp_config_uninit(LinphoneCore *lc)
{
rtp_config_t *config=&lc->rtp_conf;
- lp_config_set_int(lc->config,"rtp","audio_rtp_port",config->audio_rtp_port);
- lp_config_set_int(lc->config,"rtp","video_rtp_port",config->video_rtp_port);
+ if (config->audio_rtp_min_port == config->audio_rtp_max_port) {
+ lp_config_set_int(lc->config, "rtp", "audio_rtp_port", config->audio_rtp_min_port);
+ } else {
+ lp_config_set_range(lc->config, "rtp", "audio_rtp_port", config->audio_rtp_min_port, config->audio_rtp_max_port);
+ }
+ if (config->video_rtp_min_port == config->video_rtp_max_port) {
+ lp_config_set_int(lc->config, "rtp", "video_rtp_port", config->video_rtp_min_port);
+ } else {
+ lp_config_set_range(lc->config, "rtp", "video_rtp_port", config->video_rtp_min_port, config->video_rtp_max_port);
+ }
lp_config_set_int(lc->config,"rtp","audio_jitt_comp",config->audio_jitt_comp);
lp_config_set_int(lc->config,"rtp","video_jitt_comp",config->video_jitt_comp);
lp_config_set_int(lc->config,"rtp","nortp_timeout",config->nortp_timeout);