summaryrefslogtreecommitdiffstats
path: root/tinyMEDIA/src/tmedia_session.c
diff options
context:
space:
mode:
Diffstat (limited to 'tinyMEDIA/src/tmedia_session.c')
-rwxr-xr-xtinyMEDIA/src/tmedia_session.c3705
1 files changed, 1886 insertions, 1819 deletions
diff --git a/tinyMEDIA/src/tmedia_session.c b/tinyMEDIA/src/tmedia_session.c
index 08348d3..72c924a 100755
--- a/tinyMEDIA/src/tmedia_session.c
+++ b/tinyMEDIA/src/tmedia_session.c
@@ -82,52 +82,56 @@ int tmedia_session_set_ro(tmedia_session_t* self, const tsdp_header_M_t* m);
/*== Predicate function to find session object by media */
static int __pred_find_session_by_media(const tsk_list_item_t *item, const void *media)
{
- if (item && item->data){
- return tsk_stricmp(tmedia_session_get_media((const tmedia_session_t *)item->data), (const char*)media);
- }
- return -1;
+ if (item && item->data) {
+ return tsk_stricmp(tmedia_session_get_media((const tmedia_session_t *)item->data), (const char*)media);
+ }
+ return -1;
}
/*== Predicate function to find session object by type */
static int __pred_find_session_by_type(const tsk_list_item_t *item, const void *type)
{
- if (item && item->data){
- return ((const tmedia_session_t *)item->data)->type - *((tmedia_type_t*)type);
- }
- return -1;
+ if (item && item->data) {
+ return ((const tmedia_session_t *)item->data)->type - *((tmedia_type_t*)type);
+ }
+ return -1;
}
/*== Predicate function to find codec object by format */
static int __pred_find_codec_by_format(const tsk_list_item_t *item, const void *codec)
{
- if (item && item->data && codec){
- return tsk_stricmp(((const tmedia_codec_t*)item->data)->format, ((const tmedia_codec_t*)codec)->format);
- }
- return -1;
+ if (item && item->data && codec) {
+ return tsk_stricmp(((const tmedia_codec_t*)item->data)->format, ((const tmedia_codec_t*)codec)->format);
+ }
+ return -1;
}
/*== Predicate function to find codec object by id */
static int __pred_find_codec_by_id(const tsk_list_item_t *item, const void *id)
{
- if (item && item->data && id){
- if (((const tmedia_codec_t*)item->data)->id == *((const tmedia_codec_id_t*)id)){
- return 0;
- }
- }
- return -1;
+ if (item && item->data && id) {
+ if (((const tmedia_codec_t*)item->data)->id == *((const tmedia_codec_id_t*)id)) {
+ return 0;
+ }
+ }
+ return -1;
}
-static tsk_size_t __flags_sum(const tsk_bool_t *flags, tsk_size_t count) {
- tsk_size_t sum = 0, i;
- for (i = 0; i < count; ++i) {
- if (flags[i] == tsk_true) ++sum;
- }
- return sum;
+static tsk_size_t __flags_sum(const tsk_bool_t *flags, tsk_size_t count)
+{
+ tsk_size_t sum = 0, i;
+ for (i = 0; i < count; ++i) {
+ if (flags[i] == tsk_true) {
+ ++sum;
+ }
+ }
+ return sum;
}
-uint64_t tmedia_session_get_unique_id(){
- static uint64_t __UniqueId = 1; // MUST not be equal to zero
- return __UniqueId++;
+uint64_t tmedia_session_get_unique_id()
+{
+ static uint64_t __UniqueId = 1; // MUST not be equal to zero
+ return __UniqueId++;
}
/**@ingroup tmedia_session_group
@@ -138,135 +142,152 @@ uint64_t tmedia_session_get_unique_id(){
*/
int tmedia_session_init(tmedia_session_t* self, tmedia_type_t type)
{
- int ret = 0;
-
- if (!self){
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
-
- if (!self->initialized){
- /* set values */
- if (!self->id){
- self->id = tmedia_session_get_unique_id();
- }
- self->type = type;
- self->initialized = tsk_true;
- self->bl = tmedia_defaults_get_bl();
- self->codecs_allowed = tmedia_codec_id_all;
- self->bypass_encoding = tmedia_defaults_get_bypass_encoding();
- self->bypass_decoding = tmedia_defaults_get_bypass_decoding();
- /* SSL certificates */{
- const char* priv_path = tsk_null, *pub_path = tsk_null, *ca_path = tsk_null;
- tsk_bool_t verify = tsk_false;
- if ((ret = tmedia_defaults_get_ssl_certs(&priv_path, &pub_path, &ca_path, &verify))) {
- return ret;
- }
- self->dtls.file_pvk = tsk_strdup(priv_path);
- self->dtls.file_pbk = tsk_strdup(pub_path);
- self->dtls.file_ca = tsk_strdup(ca_path);
- self->dtls.verify = verify;
- }
- /* load associated codecs */
- ret = _tmedia_session_load_codecs(self);
- }
-
- return 0;
+ int ret = 0;
+
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if (!self->initialized) {
+ /* set values */
+ if (!self->id) {
+ self->id = tmedia_session_get_unique_id();
+ }
+ self->type = type;
+ self->initialized = tsk_true;
+ self->bl = tmedia_defaults_get_bl();
+ self->codecs_allowed = tmedia_codec_id_all;
+ self->bypass_encoding = tmedia_defaults_get_bypass_encoding();
+ self->bypass_decoding = tmedia_defaults_get_bypass_decoding();
+ /* SSL certificates */{
+ const char* priv_path = tsk_null, *pub_path = tsk_null, *ca_path = tsk_null;
+ tsk_bool_t verify = tsk_false;
+ if ((ret = tmedia_defaults_get_ssl_certs(&priv_path, &pub_path, &ca_path, &verify))) {
+ return ret;
+ }
+ self->dtls.file_pvk = tsk_strdup(priv_path);
+ self->dtls.file_pbk = tsk_strdup(pub_path);
+ self->dtls.file_ca = tsk_strdup(ca_path);
+ self->dtls.verify = verify;
+ }
+ /* QoS metrics */
+ self->qos_metrics.q1 = 0.f;
+ self->qos_metrics.q2 = 0.f;
+ self->qos_metrics.q3 = 0.f;
+ self->qos_metrics.q4 = 0.f;
+ self->qos_metrics.qvag = 1.f;
+ self->qos_metrics.last_update_time = 0;
+ self->qos_metrics.bw_up_est_kbps = 0;
+ self->qos_metrics.bw_down_est_kbps = 0;
+ self->qos_metrics.video_out_width = 0;
+ self->qos_metrics.video_out_height = 0;
+ self->qos_metrics.video_in_width = 0;
+ self->qos_metrics.video_in_height = 0;
+ self->qos_metrics.video_in_avg_fps = 0;
+ self->qos_metrics.video_dec_avg_time = 0;
+ self->qos_metrics.video_enc_avg_time = 0;
+
+ /* load associated codecs */
+ ret = _tmedia_session_load_codecs(self);
+ }
+
+ return 0;
}
int tmedia_session_set(tmedia_session_t* self, ...)
{
- va_list ap;
- tmedia_params_L_t* params;
-
- if (!self || !self->plugin || !self->plugin->set){
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
-
- va_start(ap, self);
- if ((params = tmedia_params_create_2(&ap))){
- const tsk_list_item_t *item;
- const tmedia_param_t* param;
- tsk_list_foreach(item, params){
- if (!(param = item->data)){
- continue;
- }
- if ((self->type & param->media_type)){
- self->plugin->set(self, param);
- }
- }
- TSK_OBJECT_SAFE_FREE(params);
- }
- va_end(ap);
- return 0;
+ va_list ap;
+ tmedia_params_L_t* params;
+
+ if (!self || !self->plugin || !self->plugin->set) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ va_start(ap, self);
+ if ((params = tmedia_params_create_2(&ap))) {
+ const tsk_list_item_t *item;
+ const tmedia_param_t* param;
+ tsk_list_foreach(item, params) {
+ if (!(param = item->data)) {
+ continue;
+ }
+ if ((self->type & param->media_type)) {
+ self->plugin->set(self, param);
+ }
+ }
+ TSK_OBJECT_SAFE_FREE(params);
+ }
+ va_end(ap);
+ return 0;
}
tsk_bool_t tmedia_session_set_2(tmedia_session_t* self, const tmedia_param_t* param)
{
- if (!self || !param){
- TSK_DEBUG_ERROR("Invalid parameter");
- return tsk_false;
- }
-
- if (param->plugin_type == tmedia_ppt_session){
- if (param->value_type == tmedia_pvt_int32){
- if (tsk_striequals(param->key, "codecs-supported")){
- //if(self->M.lo){
- // TSK_DEBUG_WARN("Cannot change codec values at this stage");
- //}
- //else{
- int32_t codecs_allowed = *((int32_t*)param->value);
- if (self->codecs_allowed != codecs_allowed){
- self->codecs_allowed = codecs_allowed;
- return (_tmedia_session_load_codecs(self) == 0);
- }
- return 0;
- //}
- return tsk_true;
- }
- else if (tsk_striequals(param->key, "bypass-encoding")){
- self->bypass_encoding = *((int32_t*)param->value);
- return tsk_true;
- }
- else if (tsk_striequals(param->key, "bypass-decoding")){
- self->bypass_decoding = *((int32_t*)param->value);
- return tsk_true;
- }
- else if (tsk_striequals(param->key, "dtls-cert-verify")){
- self->dtls.verify = *((int32_t*)param->value) ? tsk_true : tsk_false;
- return tsk_true;
- }
- }
- else if (param->value_type == tmedia_pvt_pchar){
- if (tsk_striequals(param->key, "dtls-file-ca")){
- tsk_strupdate(&self->dtls.file_ca, param->value);
- return tsk_true;
- }
- else if (tsk_striequals(param->key, "dtls-file-pbk")){
- tsk_strupdate(&self->dtls.file_pbk, param->value);
- return tsk_true;
- }
- else if (tsk_striequals(param->key, "dtls-file-pvk")){
- tsk_strupdate(&self->dtls.file_pvk, param->value);
- return tsk_true;
- }
- }
- }
-
- return tsk_false;
+ if (!self || !param) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_false;
+ }
+
+ if (param->plugin_type == tmedia_ppt_session) {
+ if (param->value_type == tmedia_pvt_int32) {
+ if (tsk_striequals(param->key, "codecs-supported")) {
+ //if(self->M.lo){
+ // TSK_DEBUG_WARN("Cannot change codec values at this stage");
+ //}
+ //else{
+ int32_t codecs_allowed = *((int32_t*)param->value);
+ if (self->codecs_allowed != codecs_allowed) {
+ self->codecs_allowed = codecs_allowed;
+ return (_tmedia_session_load_codecs(self) == 0);
+ }
+ return 0;
+ //}
+ return tsk_true;
+ }
+ else if (tsk_striequals(param->key, "bypass-encoding")) {
+ self->bypass_encoding = *((int32_t*)param->value);
+ return tsk_true;
+ }
+ else if (tsk_striequals(param->key, "bypass-decoding")) {
+ self->bypass_decoding = *((int32_t*)param->value);
+ return tsk_true;
+ }
+ else if (tsk_striequals(param->key, "dtls-cert-verify")) {
+ self->dtls.verify = *((int32_t*)param->value) ? tsk_true : tsk_false;
+ return tsk_true;
+ }
+ }
+ else if (param->value_type == tmedia_pvt_pchar) {
+ if (tsk_striequals(param->key, "dtls-file-ca")) {
+ tsk_strupdate(&self->dtls.file_ca, param->value);
+ return tsk_true;
+ }
+ else if (tsk_striequals(param->key, "dtls-file-pbk")) {
+ tsk_strupdate(&self->dtls.file_pbk, param->value);
+ return tsk_true;
+ }
+ else if (tsk_striequals(param->key, "dtls-file-pvk")) {
+ tsk_strupdate(&self->dtls.file_pvk, param->value);
+ return tsk_true;
+ }
+ }
+ }
+
+ return tsk_false;
}
int tmedia_session_get(tmedia_session_t* self, tmedia_param_t* param)
{
- if (!self || !param) {
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
- if (self->plugin && self->plugin->get) {
- return self->plugin->get(self, param);
- }
- return -2;
+ if (!self || !param) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if (self->plugin && self->plugin->get) {
+ return self->plugin->get(self, param);
+ }
+ return -2;
}
/**@ingroup tmedia_session_group
@@ -280,9 +301,9 @@ int tmedia_session_get(tmedia_session_t* self, tmedia_param_t* param)
*/
int tmedia_session_cmp(const tsk_object_t* sess1, const tsk_object_t* sess2)
{
- int ret;
- tsk_subsat_int32_ptr(sess1, sess2, &ret);
- return ret;
+ int ret;
+ tsk_subsat_int32_ptr(sess1, sess2, &ret);
+ return ret;
}
/**@ingroup tmedia_session_group
@@ -293,22 +314,22 @@ int tmedia_session_cmp(const tsk_object_t* sess1, const tsk_object_t* sess2)
*/
int tmedia_session_plugin_register(const tmedia_session_plugin_def_t* plugin)
{
- tsk_size_t i;
- if (!plugin){
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
+ tsk_size_t i;
+ if (!plugin) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
- /* add or replace the plugin */
- for (i = 0; i < TMED_SESSION_MAX_PLUGINS; i++){
- if (!__tmedia_session_plugins[i] || (__tmedia_session_plugins[i] == plugin)){
- __tmedia_session_plugins[i] = plugin;
- return 0;
- }
- }
+ /* add or replace the plugin */
+ for (i = 0; i < TMED_SESSION_MAX_PLUGINS; i++) {
+ if (!__tmedia_session_plugins[i] || (__tmedia_session_plugins[i] == plugin)) {
+ __tmedia_session_plugins[i] = plugin;
+ return 0;
+ }
+ }
- TSK_DEBUG_ERROR("There are already %d plugins.", TMED_SESSION_MAX_PLUGINS);
- return -2;
+ TSK_DEBUG_ERROR("There are already %d plugins.", TMED_SESSION_MAX_PLUGINS);
+ return -2;
}
/**@ingroup tmedia_session_group
@@ -316,20 +337,20 @@ int tmedia_session_plugin_register(const tmedia_session_plugin_def_t* plugin)
*/
const tmedia_session_plugin_def_t* tmedia_session_plugin_find_by_media(const char* media)
{
- tsk_size_t i = 0;
- if (tsk_strnullORempty(media)){
- TSK_DEBUG_ERROR("Invalid parameter");
- return tsk_null;
- }
+ tsk_size_t i = 0;
+ if (tsk_strnullORempty(media)) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
- /* add or replace the plugin */
- while ((i < TMED_SESSION_MAX_PLUGINS) && (__tmedia_session_plugins[i])){
- if (tsk_striequals(__tmedia_session_plugins[i]->media, media)){
- return __tmedia_session_plugins[i];
- }
- i++;
- }
- return tsk_null;
+ /* add or replace the plugin */
+ while ((i < TMED_SESSION_MAX_PLUGINS) && (__tmedia_session_plugins[i])) {
+ if (tsk_striequals(__tmedia_session_plugins[i]->media, media)) {
+ return __tmedia_session_plugins[i];
+ }
+ i++;
+ }
+ return tsk_null;
}
/**@ingroup tmedia_session_group
@@ -339,35 +360,35 @@ const tmedia_session_plugin_def_t* tmedia_session_plugin_find_by_media(const cha
*/
int tmedia_session_plugin_unregister(const tmedia_session_plugin_def_t* plugin)
{
- tsk_size_t i;
- tsk_bool_t found = tsk_false;
- if (!plugin){
- TSK_DEBUG_ERROR("Invalid Parameter");
- return -1;
- }
-
- /* find the plugin to unregister */
- for (i = 0; i < TMED_SESSION_MAX_PLUGINS && __tmedia_session_plugins[i]; i++){
- if (__tmedia_session_plugins[i] == plugin){
- __tmedia_session_plugins[i] = tsk_null;
- found = tsk_true;
- break;
- }
- }
-
- /* compact */
- if (found){
- for (; i < (TMED_SESSION_MAX_PLUGINS - 1); i++){
- if (__tmedia_session_plugins[i + 1]){
- __tmedia_session_plugins[i] = __tmedia_session_plugins[i + 1];
- }
- else{
- break;
- }
- }
- __tmedia_session_plugins[i] = tsk_null;
- }
- return (found ? 0 : -2);
+ tsk_size_t i;
+ tsk_bool_t found = tsk_false;
+ if (!plugin) {
+ TSK_DEBUG_ERROR("Invalid Parameter");
+ return -1;
+ }
+
+ /* find the plugin to unregister */
+ for (i = 0; i < TMED_SESSION_MAX_PLUGINS && __tmedia_session_plugins[i]; i++) {
+ if (__tmedia_session_plugins[i] == plugin) {
+ __tmedia_session_plugins[i] = tsk_null;
+ found = tsk_true;
+ break;
+ }
+ }
+
+ /* compact */
+ if (found) {
+ for (; i < (TMED_SESSION_MAX_PLUGINS - 1); i++) {
+ if (__tmedia_session_plugins[i + 1]) {
+ __tmedia_session_plugins[i] = __tmedia_session_plugins[i + 1];
+ }
+ else {
+ break;
+ }
+ }
+ __tmedia_session_plugins[i] = tsk_null;
+ }
+ return (found ? 0 : -2);
}
/**@ingroup tmedia_session_group
@@ -377,252 +398,268 @@ int tmedia_session_plugin_unregister(const tmedia_session_plugin_def_t* plugin)
*/
tmedia_session_t* tmedia_session_create(tmedia_type_t type)
{
- tmedia_session_t* session = tsk_null;
- const tmedia_session_plugin_def_t* plugin;
- tsk_size_t i = 0;
+ tmedia_session_t* session = tsk_null;
+ const tmedia_session_plugin_def_t* plugin;
+ tsk_size_t i = 0;
- while ((i < TMED_SESSION_MAX_PLUGINS) && (plugin = __tmedia_session_plugins[i++])){
- if (plugin->objdef && (plugin->type == type)){
- if ((session = tsk_object_new(plugin->objdef))){
- if (!session->initialized){
- tmedia_session_init(session, type);
- }
- session->plugin = plugin;
- }
- break;
- }
- }
- return session;
+ while ((i < TMED_SESSION_MAX_PLUGINS) && (plugin = __tmedia_session_plugins[i++])) {
+ if (plugin->objdef && (plugin->type == type)) {
+ if ((session = tsk_object_new(plugin->objdef))) {
+ if (!session->initialized) {
+ tmedia_session_init(session, type);
+ }
+ session->plugin = plugin;
+ }
+ break;
+ }
+ }
+ return session;
}
/* internal funtion: prepare lo */
static int _tmedia_session_prepare(tmedia_session_t* self)
{
- int ret;
- if (!self || !self->plugin || !self->plugin->prepare){
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
- if (self->prepared){
- TSK_DEBUG_WARN("Session already prepared");
- return 0;
- }
- if ((ret = self->plugin->prepare(self))){
- TSK_DEBUG_ERROR("Failed to prepare the session");
- }
- else{
- self->prepared = tsk_true;
- }
- return ret;
+ int ret;
+ if (!self || !self->plugin || !self->plugin->prepare) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if (self->prepared) {
+ TSK_DEBUG_WARN("Session already prepared");
+ return 0;
+ }
+ if ((ret = self->plugin->prepare(self))) {
+ TSK_DEBUG_ERROR("Failed to prepare the session");
+ }
+ else {
+ self->prepared = tsk_true;
+ }
+ return ret;
}
/* internal function used to set remote offer */
int _tmedia_session_set_ro(tmedia_session_t* self, const tsdp_header_M_t* m)
{
- int ret;
- if (!self || !self->plugin || !self->plugin->set_remote_offer){
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
- if (!(ret = self->plugin->set_remote_offer(self, m))){
- self->ro_changed = tsk_true;
- self->ro_held = tsdp_header_M_is_held(m, tsk_false);
- }
- return ret;
+ int ret;
+ if (!self || !self->plugin || !self->plugin->set_remote_offer) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if (!(ret = self->plugin->set_remote_offer(self, m))) {
+ self->ro_changed = tsk_true;
+ self->ro_held = tsdp_header_M_is_held(m, tsk_false);
+ }
+ return ret;
}
/* internal function: get media */
const char* tmedia_session_get_media(const tmedia_session_t* self)
{
- if (!self || !self->plugin){
- TSK_DEBUG_ERROR("Invalid parameter");
- return tsk_null;
- }
+ if (!self || !self->plugin) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
- /* ghost? */
- if (self->plugin == tmedia_session_ghost_plugin_def_t){
- return ((const tmedia_session_ghost_t*)self)->media;
- }
- else{
- return self->plugin->media;
- }
+ /* ghost? */
+ if (self->plugin == tmedia_session_ghost_plugin_def_t) {
+ return ((const tmedia_session_ghost_t*)self)->media;
+ }
+ else {
+ return self->plugin->media;
+ }
}
/* internal function: get local offer */
const tsdp_header_M_t* tmedia_session_get_lo(tmedia_session_t* self)
{
- const tsdp_header_M_t* m;
+ const tsdp_header_M_t* m;
- if (!self || !self->plugin || !self->plugin->get_local_offer){
- TSK_DEBUG_ERROR("Invalid parameter");
- return tsk_null;
- }
+ if (!self || !self->plugin || !self->plugin->get_local_offer) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
- if ((m = self->plugin->get_local_offer(self))){
- self->ro_changed = tsk_false; /* we should have a fresh local offer (based on the latest ro) */
- }
- return m;
+ if ((m = self->plugin->get_local_offer(self))) {
+ self->ro_changed = tsk_false; /* we should have a fresh local offer (based on the latest ro) */
+ }
+ return m;
}
/* Match a codec */
tmedia_codecs_L_t* tmedia_session_match_codec(tmedia_session_t* self, const tsdp_header_M_t* M)
{
- const tmedia_codec_t *codec;
- char *rtpmap = tsk_null, *fmtp = tsk_null, *image_attr = tsk_null, *name = tsk_null;
- const tsdp_fmt_t* fmt;
- const tsk_list_item_t *it1, *it2;
- tsk_bool_t found = tsk_false;
- tmedia_codecs_L_t* matchingCodecs = tsk_null;
-
- if (!self || !M){
- TSK_DEBUG_ERROR("Invalid parameter");
- return tsk_null;
- }
-
-
- /* foreach format */
- tsk_list_foreach(it1, M->FMTs){
- fmt = it1->data;
-
- /* foreach codec */
- tsk_list_foreach(it2, self->codecs){
- /* 'tmedia_codec_id_none' is used for fake codecs (e.g. dtmf or msrp) and should not be filtered beacuse of backward compatibility*/
- if (!(codec = it2->data) || !codec->plugin || !(codec->id == tmedia_codec_id_none || (codec->id & self->codecs_allowed))){
- continue;
- }
-
- // Guard to avoid matching a codec more than once
- // For example, H.264 codecs without profiles (Jitsi, Tiscali PC client) to distinguish them could match more than once
- if (matchingCodecs && tsk_list_find_object_by_pred(matchingCodecs, __pred_find_codec_by_format, codec)){
- continue;
- }
-
- // Dyn. payload type
- if (codec->dyn && (rtpmap = tsdp_header_M_get_rtpmap(M, fmt->value))){
- int32_t rate, channels;
- /* parse rtpmap */
- if (tmedia_parse_rtpmap(rtpmap, &name, &rate, &channels)){
- goto next;
- }
-
- /* compare name and rate... what about channels? */
- if (tsk_striequals(name, codec->name) && (!rate || !codec->plugin->rate || (codec->plugin->rate == rate))){
- goto compare_fmtp;
- }
- }
- // Fixed payload type
- else{
- if (tsk_striequals(fmt->value, codec->format)){
- goto compare_fmtp;
- }
- }
-
- /* rtpmap do not match: free strings and try next codec */
- goto next;
-
- compare_fmtp:
- if ((fmtp = tsdp_header_M_get_fmtp(M, fmt->value))){ /* remote have fmtp? */
- if (tmedia_codec_sdp_att_match(codec, "fmtp", fmtp)){ /* fmtp matches? */
- if (codec->type & tmedia_video) goto compare_imageattr;
- else found = tsk_true;
- }
- else goto next;
- }
- else{ /* no fmtp -> always match */
- if (codec->type & tmedia_video) goto compare_imageattr;
- else found = tsk_true;
- }
-
- compare_imageattr:
- if (codec->type & tmedia_video){
- if ((image_attr = tsdp_header_M_get_imageattr(M, fmt->value))){
- if (tmedia_codec_sdp_att_match(codec, "imageattr", image_attr)) found = tsk_true;
- }
- else found = tsk_true;
- }
-
- // update neg. format
- if (found) tsk_strupdate((char**)&codec->neg_format, fmt->value);
-
- next:
- TSK_FREE(name);
- TSK_FREE(fmtp);
- TSK_FREE(rtpmap);
- TSK_FREE(image_attr);
- if (found){
- tmedia_codec_t * copy;
- if (!matchingCodecs){
- matchingCodecs = tsk_list_create();
- }
- copy = tsk_object_ref((void*)codec);
- tsk_list_push_back_data(matchingCodecs, (void**)&copy);
-
- found = tsk_false;
- break;
- }
- }
- }
-
-
- return matchingCodecs;
+ const tmedia_codec_t *codec;
+ char *rtpmap = tsk_null, *fmtp = tsk_null, *image_attr = tsk_null, *name = tsk_null;
+ const tsdp_fmt_t* fmt;
+ const tsk_list_item_t *it1, *it2;
+ tsk_bool_t found = tsk_false;
+ tmedia_codecs_L_t* matchingCodecs = tsk_null;
+
+ if (!self || !M) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
+
+
+ /* foreach format */
+ tsk_list_foreach(it1, M->FMTs) {
+ fmt = it1->data;
+
+ /* foreach codec */
+ tsk_list_foreach(it2, self->codecs) {
+ /* 'tmedia_codec_id_none' is used for fake codecs (e.g. dtmf or msrp) and should not be filtered beacuse of backward compatibility*/
+ if (!(codec = it2->data) || !codec->plugin || !(codec->id == tmedia_codec_id_none || (codec->id & self->codecs_allowed))) {
+ continue;
+ }
+
+ // Guard to avoid matching a codec more than once
+ // For example, H.264 codecs without profiles (Jitsi, Tiscali PC client) to distinguish them could match more than once
+ if (matchingCodecs && tsk_list_find_object_by_pred(matchingCodecs, __pred_find_codec_by_format, codec)) {
+ continue;
+ }
+
+ // Dyn. payload type
+ if (codec->dyn && (rtpmap = tsdp_header_M_get_rtpmap(M, fmt->value))) {
+ int32_t rate, channels;
+ /* parse rtpmap */
+ if (tmedia_parse_rtpmap(rtpmap, &name, &rate, &channels)) {
+ goto next;
+ }
+
+ /* compare name and rate... what about channels? */
+ if (tsk_striequals(name, codec->name) && (!rate || !codec->plugin->rate || (codec->plugin->rate == rate))) {
+ goto compare_fmtp;
+ }
+ }
+ // Fixed payload type
+ else {
+ if (tsk_striequals(fmt->value, codec->format)) {
+ goto compare_fmtp;
+ }
+ }
+
+ /* rtpmap do not match: free strings and try next codec */
+ goto next;
+
+compare_fmtp:
+ if ((fmtp = tsdp_header_M_get_fmtp(M, fmt->value))) { /* remote have fmtp? */
+ if (tmedia_codec_sdp_att_match(codec, "fmtp", fmtp)) { /* fmtp matches? */
+ if (codec->type & tmedia_video) {
+ goto compare_imageattr;
+ }
+ else {
+ found = tsk_true;
+ }
+ }
+ else {
+ goto next;
+ }
+ }
+ else { /* no fmtp -> always match */
+ if (codec->type & tmedia_video) {
+ goto compare_imageattr;
+ }
+ else {
+ found = tsk_true;
+ }
+ }
+
+compare_imageattr:
+ if (codec->type & tmedia_video) {
+ if ((image_attr = tsdp_header_M_get_imageattr(M, fmt->value))) {
+ if (tmedia_codec_sdp_att_match(codec, "imageattr", image_attr)) {
+ found = tsk_true;
+ }
+ }
+ else {
+ found = tsk_true;
+ }
+ }
+
+ // update neg. format
+ if (found) {
+ tsk_strupdate((char**)&codec->neg_format, fmt->value);
+ }
+
+next:
+ TSK_FREE(name);
+ TSK_FREE(fmtp);
+ TSK_FREE(rtpmap);
+ TSK_FREE(image_attr);
+ if (found) {
+ tmedia_codec_t * copy;
+ if (!matchingCodecs) {
+ matchingCodecs = tsk_list_create();
+ }
+ copy = tsk_object_ref((void*)codec);
+ tsk_list_push_back_data(matchingCodecs, (void**)&copy);
+
+ found = tsk_false;
+ break;
+ }
+ }
+ }
+
+
+ return matchingCodecs;
}
int tmedia_session_set_onrtcp_cbfn(tmedia_session_t* self, const void* context, tmedia_session_rtcp_onevent_cb_f func)
{
- if (self && self->plugin && self->plugin->rtcp.set_onevent_cbfn){
- return self->plugin->rtcp.set_onevent_cbfn(self, context, func);
- }
- return -1;
+ if (self && self->plugin && self->plugin->rtcp.set_onevent_cbfn) {
+ return self->plugin->rtcp.set_onevent_cbfn(self, context, func);
+ }
+ return -1;
}
int tmedia_session_send_rtcp_event(tmedia_session_t* self, tmedia_rtcp_event_type_t event_type, uint32_t ssrc_media)
{
- if (self && self->plugin && self->plugin->rtcp.send_event){
- return self->plugin->rtcp.send_event(self, event_type, ssrc_media);
- }
- TSK_DEBUG_INFO("Not sending RTCP event with SSRC = %u because no callback function found", ssrc_media);
- return -1;
+ if (self && self->plugin && self->plugin->rtcp.send_event) {
+ return self->plugin->rtcp.send_event(self, event_type, ssrc_media);
+ }
+ TSK_DEBUG_INFO("Not sending RTCP event with SSRC = %u because no callback function found", ssrc_media);
+ return -1;
}
int tmedia_session_recv_rtcp_event(tmedia_session_t* self, tmedia_rtcp_event_type_t event_type, uint32_t ssrc_media)
{
- if (self && self->plugin && self->plugin->rtcp.recv_event){
- return self->plugin->rtcp.recv_event(self, event_type, ssrc_media);
- }
- TSK_DEBUG_INFO("Not receiving RTCP event with SSRC = %u because no callback function found", ssrc_media);
- return -1;
+ if (self && self->plugin && self->plugin->rtcp.recv_event) {
+ return self->plugin->rtcp.recv_event(self, event_type, ssrc_media);
+ }
+ TSK_DEBUG_INFO("Not receiving RTCP event with SSRC = %u because no callback function found", ssrc_media);
+ return -1;
}
int tmedia_session_set_onerror_cbfn(tmedia_session_t* self, const void* usrdata, tmedia_session_onerror_cb_f fun)
{
- if (!self){
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
- self->onerror_cb.fun = fun;
- self->onerror_cb.usrdata = usrdata;
- return 0;
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ self->onerror_cb.fun = fun;
+ self->onerror_cb.usrdata = usrdata;
+ return 0;
}
int tmedia_session_set_rfc5168_cbfn(tmedia_session_t* self, const void* usrdata, tmedia_session_rfc5168_cb_f fun)
{
- if (!self) {
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
- self->rfc5168_cb.fun = fun;
- self->rfc5168_cb.usrdata = usrdata;
- return 0;
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ self->rfc5168_cb.fun = fun;
+ self->rfc5168_cb.usrdata = usrdata;
+ return 0;
}
int tmedia_session_set_bfcp_cbfn(tmedia_session_t* self, const void* usrdata, tmedia_session_bfcp_cb_f fun)
{
- if (!self) {
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
- self->bfcp_cb.fun = fun;
- self->bfcp_cb.usrdata = usrdata;
- return 0;
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ self->bfcp_cb.fun = fun;
+ self->bfcp_cb.usrdata = usrdata;
+ return 0;
}
/**@ingroup tmedia_session_group
@@ -632,28 +669,28 @@ int tmedia_session_set_bfcp_cbfn(tmedia_session_t* self, const void* usrdata, tm
*/
int tmedia_session_deinit(tmedia_session_t* self)
{
- if (!self){
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
- /* free codecs */
- TSK_OBJECT_SAFE_FREE(self->codecs);
- TSK_OBJECT_SAFE_FREE(self->neg_codecs);
+ /* free codecs */
+ TSK_OBJECT_SAFE_FREE(self->codecs);
+ TSK_OBJECT_SAFE_FREE(self->neg_codecs);
- /* free lo, no and ro */
- TSK_OBJECT_SAFE_FREE(self->M.lo);
- TSK_OBJECT_SAFE_FREE(self->M.ro);
+ /* free lo, no and ro */
+ TSK_OBJECT_SAFE_FREE(self->M.lo);
+ TSK_OBJECT_SAFE_FREE(self->M.ro);
- /* QoS */
- TSK_OBJECT_SAFE_FREE(self->qos);
+ /* QoS */
+ TSK_OBJECT_SAFE_FREE(self->qos);
- /* DTLS */
- TSK_FREE(self->dtls.file_ca);
- TSK_FREE(self->dtls.file_pbk);
- TSK_FREE(self->dtls.file_pvk);
+ /* DTLS */
+ TSK_FREE(self->dtls.file_ca);
+ TSK_FREE(self->dtls.file_pbk);
+ TSK_FREE(self->dtls.file_pvk);
- return 0;
+ return 0;
}
/**@ingroup tmedia_session_group
@@ -664,109 +701,109 @@ int tmedia_session_deinit(tmedia_session_t* self)
*/
int tmedia_session_audio_send_dtmf(tmedia_session_audio_t* self, uint8_t event)
{
- if (!self || !TMEDIA_SESSION(self)->plugin || !TMEDIA_SESSION(self)->plugin->audio.send_dtmf){
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
- return TMEDIA_SESSION(self)->plugin->audio.send_dtmf(TMEDIA_SESSION(self), event);
+ if (!self || !TMEDIA_SESSION(self)->plugin || !TMEDIA_SESSION(self)->plugin->audio.send_dtmf) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ return TMEDIA_SESSION(self)->plugin->audio.send_dtmf(TMEDIA_SESSION(self), event);
}
int tmedia_session_t140_set_ondata_cbfn(tmedia_session_t* self, const void* context, tmedia_session_t140_ondata_cb_f func)
{
- if (self && self->plugin && self->plugin->t140.set_ondata_cbfn){
- return self->plugin->t140.set_ondata_cbfn(self, context, func);
- }
- return -1;
+ if (self && self->plugin && self->plugin->t140.set_ondata_cbfn) {
+ return self->plugin->t140.set_ondata_cbfn(self, context, func);
+ }
+ return -1;
}
int tmedia_session_t140_send_data(tmedia_session_t* self, enum tmedia_t140_data_type_e data_type, const void* data_ptr, unsigned data_size)
{
- if (self && self->plugin && self->plugin->t140.send_data){
- return self->plugin->t140.send_data(self, data_type, data_ptr, data_size);
- }
- return -1;
+ if (self && self->plugin && self->plugin->t140.send_data) {
+ return self->plugin->t140.send_data(self, data_type, data_ptr, data_size);
+ }
+ return -1;
}
/* internal function used to prepare a session */
int _tmedia_session_load_codecs(tmedia_session_t* self)
{
- tsk_size_t i = 0;
- tmedia_codec_t* codec;
- const tmedia_codec_plugin_def_t* plugin;
- const tsk_list_item_t* item;
- tmedia_type_t type;
-
- if (!self){
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
-
- if (!self->codecs && !(self->codecs = tsk_list_create())){
- TSK_DEBUG_ERROR("Failed to create new list");
- return -1;
- }
-
- tsk_list_lock(self->codecs);
-
- /* remove old codecs */
- tsk_list_clear_items(self->codecs);
-
- type = self->type;
- if ((type & tmedia_bfcp_video) == tmedia_bfcp_video) {
- type |= tmedia_video;
- }
- if ((type & tmedia_bfcp_audio) == tmedia_bfcp_audio) {
- type |= tmedia_audio;
- }
-
- /* for each registered plugin create a session instance */
- while ((i < TMED_CODEC_MAX_PLUGINS) && (plugin = __tmedia_codec_plugins[i++])){
- /* 'tmedia_codec_id_none' is used for fake codecs (e.g. dtmf, bfcp or msrp) and should not be filtered beacuse of backward compatibility*/
- if ((plugin->type & type) && (plugin->codec_id == tmedia_codec_id_none || (plugin->codec_id & self->codecs_allowed))){
- // do not load bfcp codec for "audiobfcp" and "videobfcp" session
- if ((plugin->type == tmedia_bfcp) && (type != tmedia_bfcp)) {
- continue;
- }
- if ((codec = tmedia_codec_create(plugin->format))){
- if (!self->codecs){
- self->codecs = tsk_list_create();
- }
- tsk_list_push_back_data(self->codecs, (void**)(&codec));
- }
- }
- }
-
- // filter negotiated codecs with the newly loaded codecs
- if (1){ // code valid for all use-cases but for now it's not fully tested and not needed for the clients
- filter_neg_codecs:
- tsk_list_foreach(item, self->neg_codecs){
- if (!(codec = (item->data))){
- continue;
- }
- if (!(tsk_list_find_item_by_pred(self->codecs, __pred_find_codec_by_id, &codec->id))){
- const char* codec_name = codec->plugin ? codec->plugin->name : "unknown";
- const char* neg_format = codec->neg_format ? codec->neg_format : codec->format;
- TSK_DEBUG_INFO("Codec '%s' with format '%s' was negotiated but [supported codecs] updated without it -> removing", codec_name, neg_format);
- // update sdp and remove the codec from the list
- if (self->M.lo && !TSK_LIST_IS_EMPTY(self->M.lo->FMTs)){
- if (self->M.lo->FMTs->head->next == tsk_null && tsdp_header_M_have_fmt(self->M.lo, neg_format)){ // single item?
- // rejecting a media with port equal to zero requires at least one format
- TSK_DEBUG_INFO("[supported codecs] updated but do not remove codec with name='%s' and format='%s' because it's the last one", codec_name, neg_format);
- self->M.lo->port = 0;
- }
- else{
- tsdp_header_M_remove_fmt(self->M.lo, neg_format);
- }
- }
- tsk_list_remove_item_by_data(self->neg_codecs, codec);
- goto filter_neg_codecs;
- }
- }
- }
-
- tsk_list_unlock(self->codecs);
-
- return 0;
+ tsk_size_t i = 0;
+ tmedia_codec_t* codec;
+ const tmedia_codec_plugin_def_t* plugin;
+ const tsk_list_item_t* item;
+ tmedia_type_t type;
+
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if (!self->codecs && !(self->codecs = tsk_list_create())) {
+ TSK_DEBUG_ERROR("Failed to create new list");
+ return -1;
+ }
+
+ tsk_list_lock(self->codecs);
+
+ /* remove old codecs */
+ tsk_list_clear_items(self->codecs);
+
+ type = self->type;
+ if ((type & tmedia_bfcp_video) == tmedia_bfcp_video) {
+ type |= tmedia_video;
+ }
+ if ((type & tmedia_bfcp_audio) == tmedia_bfcp_audio) {
+ type |= tmedia_audio;
+ }
+
+ /* for each registered plugin create a session instance */
+ while ((i < TMED_CODEC_MAX_PLUGINS) && (plugin = __tmedia_codec_plugins[i++])) {
+ /* 'tmedia_codec_id_none' is used for fake codecs (e.g. dtmf, bfcp or msrp) and should not be filtered beacuse of backward compatibility*/
+ if ((plugin->type & type) && (plugin->codec_id == tmedia_codec_id_none || (plugin->codec_id & self->codecs_allowed))) {
+ // do not load bfcp codec for "audiobfcp" and "videobfcp" session
+ if ((plugin->type == tmedia_bfcp) && (type != tmedia_bfcp)) {
+ continue;
+ }
+ if ((codec = tmedia_codec_create(plugin->format))) {
+ if (!self->codecs) {
+ self->codecs = tsk_list_create();
+ }
+ tsk_list_push_back_data(self->codecs, (void**)(&codec));
+ }
+ }
+ }
+
+ // filter negotiated codecs with the newly loaded codecs
+ if (1) { // code valid for all use-cases but for now it's not fully tested and not needed for the clients
+filter_neg_codecs:
+ tsk_list_foreach(item, self->neg_codecs) {
+ if (!(codec = (item->data))) {
+ continue;
+ }
+ if (!(tsk_list_find_item_by_pred(self->codecs, __pred_find_codec_by_id, &codec->id))) {
+ const char* codec_name = codec->plugin ? codec->plugin->name : "unknown";
+ const char* neg_format = codec->neg_format ? codec->neg_format : codec->format;
+ TSK_DEBUG_INFO("Codec '%s' with format '%s' was negotiated but [supported codecs] updated without it -> removing", codec_name, neg_format);
+ // update sdp and remove the codec from the list
+ if (self->M.lo && !TSK_LIST_IS_EMPTY(self->M.lo->FMTs)) {
+ if (self->M.lo->FMTs->head->next == tsk_null && tsdp_header_M_have_fmt(self->M.lo, neg_format)) { // single item?
+ // rejecting a media with port equal to zero requires at least one format
+ TSK_DEBUG_INFO("[supported codecs] updated but do not remove codec with name='%s' and format='%s' because it's the last one", codec_name, neg_format);
+ self->M.lo->port = 0;
+ }
+ else {
+ tsdp_header_M_remove_fmt(self->M.lo, neg_format);
+ }
+ }
+ tsk_list_remove_item_by_data(self->neg_codecs, codec);
+ goto filter_neg_codecs;
+ }
+ }
+ }
+
+ tsk_list_unlock(self->codecs);
+
+ return 0;
}
@@ -781,155 +818,169 @@ int _tmedia_session_load_codecs(tmedia_session_t* self)
*/
tmedia_session_mgr_t* tmedia_session_mgr_create(tmedia_type_t type, const char* addr, tsk_bool_t ipv6, tsk_bool_t offerer)
{
- tmedia_session_mgr_t* mgr;
+ tmedia_session_mgr_t* mgr;
- if (!(mgr = tsk_object_new(tmedia_session_mgr_def_t))){
- TSK_DEBUG_ERROR("Failed to create Media Session manager");
- return tsk_null;
- }
+ if (!(mgr = tsk_object_new(tmedia_session_mgr_def_t))) {
+ TSK_DEBUG_ERROR("Failed to create Media Session manager");
+ return tsk_null;
+ }
- /* init */
- mgr->type = type;
- mgr->addr = tsk_strdup(addr);
- mgr->ipv6 = ipv6;
+ /* init */
+ mgr->type = type;
+ mgr->addr = tsk_strdup(addr);
+ mgr->ipv6 = ipv6;
- /* load sessions (will allow us to generate lo) */
- if (offerer){
- mgr->offerer = tsk_true;
- //if(_tmedia_session_mgr_load_sessions(mgr)){
- /* Do nothing */
- // TSK_DEBUG_ERROR("Failed to load sessions");
- //}
- }
+ /* load sessions (will allow us to generate lo) */
+ if (offerer) {
+ mgr->offerer = tsk_true;
+ //if(_tmedia_session_mgr_load_sessions(mgr)){
+ /* Do nothing */
+ // TSK_DEBUG_ERROR("Failed to load sessions");
+ //}
+ }
- return mgr;
+ return mgr;
}
/**@ingroup tmedia_session_group
*/
int tmedia_session_mgr_set_media_type(tmedia_session_mgr_t* self, tmedia_type_t type)
{
- static tsk_bool_t __force_set = tsk_false;
- return tmedia_session_mgr_set_media_type_2(self, type, __force_set);
+ static tsk_bool_t __force_set = tsk_false;
+ return tmedia_session_mgr_set_media_type_2(self, type, __force_set);
}
/**@ingroup tmedia_session_group
*/
int tmedia_session_mgr_set_media_type_2(tmedia_session_mgr_t* self, tmedia_type_t type, tsk_bool_t force)
{
- if (!self) {
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
- if (force || self->type != type) {
- self->mediaType_changed = tsk_true;
- self->type = type;
- }
- return 0;
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if (force || self->type != type) {
+ self->mediaType_changed = tsk_true;
+ self->type = type;
+ }
+ return 0;
}
// special set() case
int tmedia_session_mgr_set_codecs_supported(tmedia_session_mgr_t* self, tmedia_codec_id_t codecs_supported)
{
- int ret = 0;
- if (!self){
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
-
- // calling set() could create zombies (media sessions with port equal to zero)
- ret = tmedia_session_mgr_set(self,
- TMEDIA_SESSION_SET_INT32(self->type, "codecs-supported", codecs_supported),
- tsk_null);
- if (ret == 0 && self->sdp.lo){
- // update type (will discard zombies)
- tmedia_type_t new_type = tmedia_type_from_sdp(self->sdp.lo);
- if (new_type != self->type){
- TSK_DEBUG_INFO("codecs-supported updated and media type changed from %d to %d", self->type, new_type);
- self->type = new_type;
- }
- }
- return ret;
+ int ret = 0;
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ // calling set() could create zombies (media sessions with port equal to zero)
+ ret = tmedia_session_mgr_set(self,
+ TMEDIA_SESSION_SET_INT32(self->type, "codecs-supported", codecs_supported),
+ tsk_null);
+ if (ret == 0 && self->sdp.lo) {
+ // update type (will discard zombies)
+ tmedia_type_t new_type = tmedia_type_from_sdp(self->sdp.lo);
+ if (new_type != self->type) {
+ TSK_DEBUG_INFO("codecs-supported updated and media type changed from %d to %d", self->type, new_type);
+ self->type = new_type;
+ }
+ }
+ return ret;
}
/**@ingroup tmedia_session_group
*/
tmedia_session_t* tmedia_session_mgr_find(tmedia_session_mgr_t* self, tmedia_type_t type)
{
- tmedia_session_t* session;
+ tmedia_session_t* session;
- tsk_list_lock(self->sessions);
- session = (tmedia_session_t*)tsk_list_find_object_by_pred(self->sessions, __pred_find_session_by_type, &type);
- tsk_list_unlock(self->sessions);
+ tsk_list_lock(self->sessions);
+ session = (tmedia_session_t*)tsk_list_find_object_by_pred(self->sessions, __pred_find_session_by_type, &type);
+ tsk_list_unlock(self->sessions);
- return tsk_object_ref(session);
+ return tsk_object_ref(session);
}
/**@ingroup tmedia_session_group
*/
int tmedia_session_mgr_set_natt_ctx(tmedia_session_mgr_t* self, struct tnet_nat_ctx_s* natt_ctx, const char* public_addr)
{
- if (!self || !natt_ctx){
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
- TSK_OBJECT_SAFE_FREE(self->natt_ctx);
- self->natt_ctx = tsk_object_ref(natt_ctx);
- tsk_strupdate(&self->public_addr, public_addr);
+ if (!self || !natt_ctx) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ TSK_OBJECT_SAFE_FREE(self->natt_ctx);
+ self->natt_ctx = tsk_object_ref(natt_ctx);
+ tsk_strupdate(&self->public_addr, public_addr);
- tmedia_session_mgr_set(self,
- TMEDIA_SESSION_SET_POBJECT(self->type, "natt-ctx", self->natt_ctx),
- TMEDIA_SESSION_SET_NULL());
- return 0;
+ tmedia_session_mgr_set(self,
+ TMEDIA_SESSION_SET_POBJECT(self->type, "natt-ctx", self->natt_ctx),
+ TMEDIA_SESSION_SET_NULL());
+ return 0;
}
// @deprecated
int tmedia_session_mgr_set_ice_ctx(tmedia_session_mgr_t* self, struct tnet_ice_ctx_s* ctx_audio, struct tnet_ice_ctx_s* ctx_video)
{
- if (!self){
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
- TSK_OBJECT_SAFE_FREE(self->ice.ctx_audio); // backward compatibility
- TSK_OBJECT_SAFE_FREE(self->ice.ctx_video); // backward compatibility
- if (self->type & tmedia_audio) {
- tmedia_session_mgr_set_ice_ctx_2(self, tmedia_audio, ctx_audio);
- }
- if (self->type & tmedia_video) {
- tmedia_session_mgr_set_ice_ctx_2(self, tmedia_video, ctx_video);
- }
- return 0;
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ TSK_OBJECT_SAFE_FREE(self->ice.ctx_audio); // backward compatibility
+ TSK_OBJECT_SAFE_FREE(self->ice.ctx_video); // backward compatibility
+ if (self->type & tmedia_audio) {
+ tmedia_session_mgr_set_ice_ctx_2(self, tmedia_audio, ctx_audio);
+ }
+ if (self->type & tmedia_video) {
+ tmedia_session_mgr_set_ice_ctx_2(self, tmedia_video, ctx_video);
+ }
+ return 0;
}
int tmedia_session_mgr_set_ice_ctx_2(tmedia_session_mgr_t* self, tmedia_type_t type, struct tnet_ice_ctx_s* ctx)
{
- if (!self){
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
- if ((self->type & type) == type) {
- struct tnet_ice_ctx_s **_ctx = tsk_null;
- switch (type) {
- case tmedia_audio: _ctx = &self->ice.ctx_audio; break;
- case tmedia_video: _ctx = &self->ice.ctx_video; break;
- case tmedia_bfcp_video: _ctx = &self->ice.ctx_bfcpvid; break;
- default: TSK_DEBUG_ERROR("Media type(%d) not supported by this session manager", type); return -2;
- }
- TSK_OBJECT_SAFE_FREE((*_ctx));
- *_ctx = tsk_object_ref(ctx);
- return tmedia_session_mgr_set(self,
- TMEDIA_SESSION_SET_POBJECT(type, "ice-ctx", ctx),
- TMEDIA_SESSION_SET_NULL());
- }
- else if (!ctx) { //cleanup
- switch (type) {
- case tmedia_audio: TSK_OBJECT_SAFE_FREE(self->ice.ctx_audio); return 0;
- case tmedia_video: TSK_OBJECT_SAFE_FREE(self->ice.ctx_video); return 0;
- case tmedia_bfcp_video: TSK_OBJECT_SAFE_FREE(self->ice.ctx_bfcpvid); return 0;
- }
- }
- TSK_DEBUG_ERROR("Ignoring ICE context definition for media type %d", type);
- return -2;
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if ((self->type & type) == type) {
+ struct tnet_ice_ctx_s **_ctx = tsk_null;
+ switch (type) {
+ case tmedia_audio:
+ _ctx = &self->ice.ctx_audio;
+ break;
+ case tmedia_video:
+ _ctx = &self->ice.ctx_video;
+ break;
+ case tmedia_bfcp_video:
+ _ctx = &self->ice.ctx_bfcpvid;
+ break;
+ default:
+ TSK_DEBUG_ERROR("Media type(%d) not supported by this session manager", type);
+ return -2;
+ }
+ TSK_OBJECT_SAFE_FREE((*_ctx));
+ *_ctx = tsk_object_ref(ctx);
+ return tmedia_session_mgr_set(self,
+ TMEDIA_SESSION_SET_POBJECT(type, "ice-ctx", ctx),
+ TMEDIA_SESSION_SET_NULL());
+ }
+ else if (!ctx) { //cleanup
+ switch (type) {
+ case tmedia_audio:
+ TSK_OBJECT_SAFE_FREE(self->ice.ctx_audio);
+ return 0;
+ case tmedia_video:
+ TSK_OBJECT_SAFE_FREE(self->ice.ctx_video);
+ return 0;
+ case tmedia_bfcp_video:
+ TSK_OBJECT_SAFE_FREE(self->ice.ctx_bfcpvid);
+ return 0;
+ }
+ }
+ TSK_DEBUG_ERROR("Ignoring ICE context definition for media type %d", type);
+ return -2;
}
/**@ingroup tmedia_session_group
@@ -942,7 +993,7 @@ int tmedia_session_mgr_set_ice_ctx_2(tmedia_session_mgr_t* self, tmedia_type_t t
*/
int tmedia_session_mgr_start(tmedia_session_mgr_t* self)
{
- return _tmedia_session_mgr_start(self, kSessionIndexAll);
+ return _tmedia_session_mgr_start(self, kSessionIndexAll);
}
/**@ingroup tmedia_session_group
@@ -953,19 +1004,19 @@ int tmedia_session_mgr_start(tmedia_session_mgr_t* self)
*/
int tmedia_session_mgr_set(tmedia_session_mgr_t* self, ...)
{
- va_list ap;
- int ret;
+ va_list ap;
+ int ret;
- if (!self){
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
- va_start(ap, self);
- ret = tmedia_session_mgr_set_2(self, &ap);
- va_end(ap);
+ va_start(ap, self);
+ ret = tmedia_session_mgr_set_2(self, &ap);
+ va_end(ap);
- return ret;
+ return ret;
}
/**@ingroup tmedia_session_group
@@ -976,29 +1027,29 @@ int tmedia_session_mgr_set(tmedia_session_mgr_t* self, ...)
*/
int tmedia_session_mgr_set_2(tmedia_session_mgr_t* self, va_list *app)
{
- tmedia_params_L_t* params;
+ tmedia_params_L_t* params;
- if (!self || !app){
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
+ if (!self || !app) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
- if ((params = tmedia_params_create_2(app))){
- if (!self->params){
- self->params = tsk_object_ref(params);
- }
- else{
- tsk_list_pushback_list(self->params, params);
- }
- TSK_OBJECT_SAFE_FREE(params);
- }
+ if ((params = tmedia_params_create_2(app))) {
+ if (!self->params) {
+ self->params = tsk_object_ref(params);
+ }
+ else {
+ tsk_list_pushback_list(self->params, params);
+ }
+ TSK_OBJECT_SAFE_FREE(params);
+ }
- /* load params if we already have sessions */
- if (!TSK_LIST_IS_EMPTY(self->sessions)){
- _tmedia_session_mgr_apply_params(self);
- }
+ /* load params if we already have sessions */
+ if (!TSK_LIST_IS_EMPTY(self->sessions)) {
+ _tmedia_session_mgr_apply_params(self);
+ }
- return 0;
+ return 0;
}
/**@ingroup tmedia_session_group
@@ -1009,59 +1060,59 @@ int tmedia_session_mgr_set_2(tmedia_session_mgr_t* self, va_list *app)
*/
int tmedia_session_mgr_set_3(tmedia_session_mgr_t* self, const tmedia_params_L_t* params)
{
- if (!self || !params){
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
+ if (!self || !params) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
- if (!self->params){
- self->params = tsk_list_create();
- }
- tsk_list_pushback_list(self->params, params);
+ if (!self->params) {
+ self->params = tsk_list_create();
+ }
+ tsk_list_pushback_list(self->params, params);
- /* load params if we already have sessions */
- if (!TSK_LIST_IS_EMPTY(self->sessions)){
- _tmedia_session_mgr_apply_params(self);
- }
+ /* load params if we already have sessions */
+ if (!TSK_LIST_IS_EMPTY(self->sessions)) {
+ _tmedia_session_mgr_apply_params(self);
+ }
- return 0;
+ return 0;
}
int tmedia_session_mgr_get(tmedia_session_mgr_t* self, ...)
{
- va_list ap;
- int ret = 0;
- tmedia_params_L_t* params;
- const tsk_list_item_t *item1, *item2;
-
- if (!self){
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
-
- va_start(ap, self);
-
- if ((params = tmedia_params_create_2(&ap))){
- tmedia_session_t* session;
- tmedia_param_t* param;
- tsk_list_foreach(item2, params){
- if ((param = item2->data)){
- tsk_list_foreach(item1, self->sessions){
- if (!(session = (tmedia_session_t*)item1->data) || !session->plugin){
- continue;
- }
- if ((session->type & param->media_type) == session->type && session->plugin->set){
- ret = session->plugin->get(session, param);
- }
- }
- }
- }
- TSK_OBJECT_SAFE_FREE(params);
- }
-
- va_end(ap);
-
- return ret;
+ va_list ap;
+ int ret = 0;
+ tmedia_params_L_t* params;
+ const tsk_list_item_t *item1, *item2;
+
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ va_start(ap, self);
+
+ if ((params = tmedia_params_create_2(&ap))) {
+ tmedia_session_t* session;
+ tmedia_param_t* param;
+ tsk_list_foreach(item2, params) {
+ if ((param = item2->data)) {
+ tsk_list_foreach(item1, self->sessions) {
+ if (!(session = (tmedia_session_t*)item1->data) || !session->plugin) {
+ continue;
+ }
+ if ((session->type & param->media_type) == session->type && session->plugin->set) {
+ ret = session->plugin->get(session, param);
+ }
+ }
+ }
+ }
+ TSK_OBJECT_SAFE_FREE(params);
+ }
+
+ va_end(ap);
+
+ return ret;
}
/**@ingroup tmedia_session_group
@@ -1073,7 +1124,7 @@ int tmedia_session_mgr_get(tmedia_session_mgr_t* self, ...)
*/
int tmedia_session_mgr_stop(tmedia_session_mgr_t* self)
{
- return _tmedia_session_mgr_stop(self, kSessionIndexAll);
+ return _tmedia_session_mgr_stop(self, kSessionIndexAll);
}
/**@ingroup tmedia_session_group
@@ -1081,7 +1132,7 @@ int tmedia_session_mgr_stop(tmedia_session_mgr_t* self)
*/
const tsdp_message_t* tmedia_session_mgr_get_lo(tmedia_session_mgr_t* self)
{
- return _tmedia_session_mgr_get_lo(self, kSkipSessionLoadFalse, kForceUpdateLOFalse);
+ return _tmedia_session_mgr_get_lo(self, kSkipSessionLoadFalse, kForceUpdateLOFalse);
}
@@ -1090,486 +1141,503 @@ const tsdp_message_t* tmedia_session_mgr_get_lo(tmedia_session_mgr_t* self)
*/
int tmedia_session_mgr_set_ro(tmedia_session_mgr_t* self, const tsdp_message_t* sdp, tmedia_ro_type_t ro_type)
{
- const tmedia_session_t* ms;
- const tsdp_header_M_t* M;
- const tsdp_header_C_t* C; /* global "c=" line */
- const tsdp_header_O_t* O;
- tsk_size_t index = 0;
- tsk_size_t active_sessions_count = 0, m_lines_count = 0;
- int ret = 0;
- tsk_bool_t found;
- tsk_bool_t stopped_to_reconf[TMEDIA_SESSION_MAX_LINES] = { tsk_false };
- tsk_bool_t is_ro_codecs_changed[TMEDIA_SESSION_MAX_LINES] = { tsk_false };
- tsk_bool_t is_local_encoder_still_ok[TMEDIA_SESSION_MAX_LINES] = { tsk_false }; // decoder is dynamically mapped for each incoming rtp frame -> no need to check it
- tsk_bool_t is_ro_network_info_changed[TMEDIA_SESSION_MAX_LINES] = { tsk_false };
- tsk_bool_t is_ro_hold_resume_changed[TMEDIA_SESSION_MAX_LINES] = { tsk_false };
- tsk_bool_t is_ro_loopback_address[TMEDIA_SESSION_MAX_LINES] = { tsk_false };
- tsk_bool_t is_ice_enabled[TMEDIA_SESSION_MAX_LINES] = { tsk_false };
- tsk_bool_t is_ice_restart[TMEDIA_SESSION_MAX_LINES] = { tsk_false };
- tsk_bool_t is_dtls_fingerprint_changed[TMEDIA_SESSION_MAX_LINES] = { tsk_false };
+ const tmedia_session_t* ms;
+ const tsdp_header_M_t* M;
+ const tsdp_header_C_t* C; /* global "c=" line */
+ const tsdp_header_O_t* O;
+ tsk_size_t index = 0;
+ tsk_size_t active_sessions_count = 0, m_lines_count = 0;
+ int ret = 0;
+ tsk_bool_t found;
+ tsk_bool_t stopped_to_reconf[TMEDIA_SESSION_MAX_LINES] = { tsk_false };
+ tsk_bool_t is_ro_codecs_changed[TMEDIA_SESSION_MAX_LINES] = { tsk_false };
+ tsk_bool_t is_local_encoder_still_ok[TMEDIA_SESSION_MAX_LINES] = { tsk_false }; // decoder is dynamically mapped for each incoming rtp frame -> no need to check it
+ tsk_bool_t is_ro_network_info_changed[TMEDIA_SESSION_MAX_LINES] = { tsk_false };
+ tsk_bool_t is_ro_hold_resume_changed[TMEDIA_SESSION_MAX_LINES] = { tsk_false };
+ tsk_bool_t is_ro_loopback_address[TMEDIA_SESSION_MAX_LINES] = { tsk_false };
+ tsk_bool_t is_ice_enabled[TMEDIA_SESSION_MAX_LINES] = { tsk_false };
+ tsk_bool_t is_ice_restart[TMEDIA_SESSION_MAX_LINES] = { tsk_false };
+ tsk_bool_t is_dtls_fingerprint_changed[TMEDIA_SESSION_MAX_LINES] = { tsk_false };
tsk_bool_t is_sdes_crypto_changed[TMEDIA_SESSION_MAX_LINES] = { tsk_false };
- tmedia_type_t media_types[TMEDIA_SESSION_MAX_LINES] = { tmedia_none };
- tsk_bool_t is_media_type_changed = tsk_false;
- tsk_bool_t is_ro_media_lines_changed = tsk_false;
- tsk_bool_t had_ro_sdp, had_lo_sdp, had_ro_provisional, is_ro_provisional_final_matching = tsk_false;
- tsk_bool_t is_new_mediatype_striped = tsk_false;
- tmedia_qos_stype_t qos_type = tmedia_qos_stype_none;
- tmedia_type_t new_mediatype = tmedia_none;
- tmedia_sessions_L_t *list_tmp_sessions;
-
- if (!self || !sdp) {
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
- if (!(list_tmp_sessions = tsk_list_create())) {
- TSK_DEBUG_ERROR("Failed to create tmp list");
- return -2;
- }
-
- tsk_safeobj_lock(self);
- tsk_list_lock(self->sessions);
-
- new_mediatype = tmedia_type_from_sdp(sdp);
- had_ro_sdp = (self->sdp.ro != tsk_null);
- had_lo_sdp = (self->sdp.lo != tsk_null);
- had_ro_provisional = (had_ro_sdp && self->ro_provisional);
-
- // Remove BFCP offer if not locally enabled. Only the client can init BFCP session.
- if ((ro_type & tmedia_ro_type_offer)) {
- if (!(self->type & tmedia_bfcp_video)) {
- is_new_mediatype_striped |= (new_mediatype & tmedia_bfcp_video);
- new_mediatype &= ~tmedia_bfcp_video;
- }
- if (!(self->type & tmedia_bfcp_audio)) {
- is_new_mediatype_striped |= (new_mediatype & tmedia_bfcp_video);
- new_mediatype &= ~tmedia_bfcp_audio;
- }
- if (!(self->type & tmedia_bfcp)) {
- is_new_mediatype_striped |= (new_mediatype & tmedia_bfcp_video);
- new_mediatype &= ~tmedia_bfcp;
- }
- }
-
- /* RFC 3264 subcaluse 8
- When issuing an offer that modifies the session, the "o=" line of the new SDP MUST be identical to that in the previous SDP,
- except that the version in the origin field MUST increment by one from the previous SDP. If the version in the origin line
- does not increment, the SDP MUST be identical to the SDP with that version number. The answerer MUST be prepared to receive
- an offer that contains SDP with a version that has not changed; this is effectively a no-op.
- */
- if ((O = (const tsdp_header_O_t*)tsdp_message_get_header(sdp, tsdp_htype_O))){
- tsk_bool_t is_ro_provisional;
- if (self->sdp.ro_ver == (int32_t)O->sess_version){
- TSK_DEBUG_INFO("Remote offer has not changed");
- ret = 0;
- goto bail;
- }
- // Last provisional and new final sdp messages match only if:
- // - session version diff is == 1
- // - previous sdp was provisional and new one is final
- // - the new final sdp is inside an answer
- is_ro_provisional = ((ro_type & tmedia_ro_type_provisional) == tmedia_ro_type_provisional);
- is_ro_provisional_final_matching = ((had_ro_provisional && !is_ro_provisional) && ((self->sdp.ro_ver + 1) == O->sess_version) && ((ro_type & tmedia_ro_type_answer) == tmedia_ro_type_answer));
- self->sdp.ro_ver = (int32_t)O->sess_version;
- }
- else{
- TSK_DEBUG_ERROR("o= line is missing");
- ret = -2;
- goto bail;
- }
-
- /* SDP comparison */
- if ((sdp && self->sdp.ro)){
- const tsdp_header_M_t *M0, *M1;
- const tsdp_header_C_t *C0, *C1;
- const tsdp_header_A_t *A0, *A1;
- const tsdp_header_A_t *A0_sess_fp, *A1_sess_fp; // session-level fingerprints
- tsdp_header_M_diff_t med_level_diff; // media-level diff
- index = 0;
- A0_sess_fp = tsdp_message_get_headerA(self->sdp.ro, "fingerprint");
- A1_sess_fp = tsdp_message_get_headerA(sdp, "fingerprint");
- while ((M0 = (const tsdp_header_M_t*)tsdp_message_get_headerAt(self->sdp.ro, tsdp_htype_M, index))){
- ++m_lines_count;
- if (m_lines_count >= TMEDIA_SESSION_MAX_LINES) {
- TSK_DEBUG_ERROR("Too many m-lines %u>%u", (unsigned)m_lines_count, (unsigned)TMEDIA_SESSION_MAX_LINES);
- ret = -2;
- goto bail;
- }
- M1 = (const tsdp_header_M_t*)tsdp_message_get_headerAt(sdp, tsdp_htype_M, index);
- // media-level diffs
-
- if ((ret = tsdp_header_M_diff(M0, M1, &med_level_diff)) != 0) {
- goto bail;
- }
- if (med_level_diff & tsdp_header_M_diff_hold_resume) is_ro_hold_resume_changed[index] = tsk_true;
- if (med_level_diff & tsdp_header_M_diff_index) is_ro_media_lines_changed = tsk_true;
- if (med_level_diff & tsdp_header_M_diff_codecs) is_ro_codecs_changed[index] = tsk_true;
- if (med_level_diff & tsdp_header_M_diff_network_info) is_ro_network_info_changed[index] = tsk_true;
- if (tmedia_defaults_get_ice_enabled() && (med_level_diff & tsdp_header_M_diff_ice_enabled)) is_ice_enabled[index] = tsk_true;
- if (tmedia_defaults_get_ice_enabled() && (med_level_diff & tsdp_header_M_diff_ice_restart)) is_ice_restart[index] = tsk_true;
- if (med_level_diff & tsdp_header_M_diff_dtls_fingerprint) is_dtls_fingerprint_changed[index] = tsk_true;
- if (med_level_diff & tsdp_header_M_diff_sdes_crypto) is_sdes_crypto_changed[index] = tsk_true;
- if (med_level_diff & tsdp_header_M_diff_media_type); // cannot happen as media must keep same index
-
- // dtls fingerprint (session-level)
- if (!is_dtls_fingerprint_changed[index]) {
- A0 = tsdp_header_M_findA_at(M0, "fingerprint", 0);
- A1 = M1 ? tsdp_header_M_findA_at(M1, "fingerprint", 0) : tsk_null;
- is_dtls_fingerprint_changed[index] = (A0 && A1 && !tsk_striequals(A0->value, A1->value));
- }
- // network info (session-level)
- if (!is_ro_network_info_changed[index]) {
- C0 = (const tsdp_header_C_t*)tsdp_message_get_headerAt(self->sdp.ro, tsdp_htype_C, index);
- C1 = (const tsdp_header_C_t*)tsdp_message_get_headerAt(sdp, tsdp_htype_C, index);
- // Connection informations must be both "null" or "not-null"
- if (!(is_ro_network_info_changed[index] = !((C0 && C1) || (!C0 && !C1)))){
- if (C0) {
- is_ro_network_info_changed[index] = (!tsk_strequals(C1->addr, C0->addr) || !tsk_strequals(C1->nettype, C0->nettype) || !tsk_strequals(C1->addrtype, C0->addrtype));
- }
- }
- }
+ tmedia_type_t media_types[TMEDIA_SESSION_MAX_LINES] = { tmedia_none };
+ tsk_bool_t is_media_type_changed = tsk_false;
+ tsk_bool_t is_ro_media_lines_changed = tsk_false;
+ tsk_bool_t had_ro_sdp, had_lo_sdp, had_ro_provisional, is_ro_provisional_final_matching = tsk_false;
+ tsk_bool_t is_new_mediatype_striped = tsk_false;
+ tmedia_qos_stype_t qos_type = tmedia_qos_stype_none;
+ tmedia_type_t new_mediatype = tmedia_none;
+ tmedia_sessions_L_t *list_tmp_sessions;
+
+ if (!self || !sdp) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ if (!(list_tmp_sessions = tsk_list_create())) {
+ TSK_DEBUG_ERROR("Failed to create tmp list");
+ return -2;
+ }
+
+ tsk_safeobj_lock(self);
+ tsk_list_lock(self->sessions);
+
+ new_mediatype = tmedia_type_from_sdp(sdp);
+ had_ro_sdp = (self->sdp.ro != tsk_null);
+ had_lo_sdp = (self->sdp.lo != tsk_null);
+ had_ro_provisional = (had_ro_sdp && self->ro_provisional);
+
+ // Remove BFCP offer if not locally enabled. Only the client can init BFCP session.
+ if ((ro_type & tmedia_ro_type_offer)) {
+ if (!(self->type & tmedia_bfcp_video)) {
+ is_new_mediatype_striped |= (new_mediatype & tmedia_bfcp_video);
+ new_mediatype &= ~tmedia_bfcp_video;
+ }
+ if (!(self->type & tmedia_bfcp_audio)) {
+ is_new_mediatype_striped |= (new_mediatype & tmedia_bfcp_video);
+ new_mediatype &= ~tmedia_bfcp_audio;
+ }
+ if (!(self->type & tmedia_bfcp)) {
+ is_new_mediatype_striped |= (new_mediatype & tmedia_bfcp_video);
+ new_mediatype &= ~tmedia_bfcp;
+ }
+ }
+
+ /* RFC 3264 subcaluse 8
+ When issuing an offer that modifies the session, the "o=" line of the new SDP MUST be identical to that in the previous SDP,
+ except that the version in the origin field MUST increment by one from the previous SDP. If the version in the origin line
+ does not increment, the SDP MUST be identical to the SDP with that version number. The answerer MUST be prepared to receive
+ an offer that contains SDP with a version that has not changed; this is effectively a no-op.
+ */
+ if ((O = (const tsdp_header_O_t*)tsdp_message_get_header(sdp, tsdp_htype_O))) {
+ tsk_bool_t is_ro_provisional;
+ if (self->sdp.ro_ver == (int32_t)O->sess_version) {
+ TSK_DEBUG_INFO("Remote offer has not changed");
+ ret = 0;
+ goto bail;
+ }
+ // Last provisional and new final sdp messages match only if:
+ // - session version diff is == 1
+ // - previous sdp was provisional and new one is final
+ // - the new final sdp is inside an answer
+ is_ro_provisional = ((ro_type & tmedia_ro_type_provisional) == tmedia_ro_type_provisional);
+ is_ro_provisional_final_matching = ((had_ro_provisional && !is_ro_provisional) && ((self->sdp.ro_ver + 1) == O->sess_version) && ((ro_type & tmedia_ro_type_answer) == tmedia_ro_type_answer));
+ self->sdp.ro_ver = (int32_t)O->sess_version;
+ }
+ else {
+ TSK_DEBUG_ERROR("o= line is missing");
+ ret = -2;
+ goto bail;
+ }
+
+ /* SDP comparison */
+ if ((sdp && self->sdp.ro)) {
+ const tsdp_header_M_t *M0, *M1;
+ const tsdp_header_C_t *C0, *C1;
+ const tsdp_header_A_t *A0, *A1;
+ const tsdp_header_A_t *A0_sess_fp, *A1_sess_fp; // session-level fingerprints
+ tsdp_header_M_diff_t med_level_diff; // media-level diff
+ index = 0;
+ A0_sess_fp = tsdp_message_get_headerA(self->sdp.ro, "fingerprint");
+ A1_sess_fp = tsdp_message_get_headerA(sdp, "fingerprint");
+ while ((M0 = (const tsdp_header_M_t*)tsdp_message_get_headerAt(self->sdp.ro, tsdp_htype_M, index))) {
+ ++m_lines_count;
+ if (m_lines_count >= TMEDIA_SESSION_MAX_LINES) {
+ TSK_DEBUG_ERROR("Too many m-lines %u>%u", (unsigned)m_lines_count, (unsigned)TMEDIA_SESSION_MAX_LINES);
+ ret = -2;
+ goto bail;
+ }
+ M1 = (const tsdp_header_M_t*)tsdp_message_get_headerAt(sdp, tsdp_htype_M, index);
+ // media-level diffs
+
+ if ((ret = tsdp_header_M_diff(M0, M1, &med_level_diff)) != 0) {
+ goto bail;
+ }
+ if (med_level_diff & tsdp_header_M_diff_hold_resume) {
+ is_ro_hold_resume_changed[index] = tsk_true;
+ }
+ if (med_level_diff & tsdp_header_M_diff_index) {
+ is_ro_media_lines_changed = tsk_true;
+ }
+ if (med_level_diff & tsdp_header_M_diff_codecs) {
+ is_ro_codecs_changed[index] = tsk_true;
+ }
+ if (med_level_diff & tsdp_header_M_diff_network_info) {
+ is_ro_network_info_changed[index] = tsk_true;
+ }
+ if (tmedia_defaults_get_ice_enabled() && (med_level_diff & tsdp_header_M_diff_ice_enabled)) {
+ is_ice_enabled[index] = tsk_true;
+ }
+ if (tmedia_defaults_get_ice_enabled() && (med_level_diff & tsdp_header_M_diff_ice_restart)) {
+ is_ice_restart[index] = tsk_true;
+ }
+ if (med_level_diff & tsdp_header_M_diff_dtls_fingerprint) {
+ is_dtls_fingerprint_changed[index] = tsk_true;
+ }
+ if (med_level_diff & tsdp_header_M_diff_sdes_crypto) {
+ is_sdes_crypto_changed[index] = tsk_true;
+ }
+ if (med_level_diff & tsdp_header_M_diff_media_type); // cannot happen as media must keep same index
+
+ // dtls fingerprint (session-level)
+ if (!is_dtls_fingerprint_changed[index]) {
+ A0 = tsdp_header_M_findA_at(M0, "fingerprint", 0);
+ A1 = M1 ? tsdp_header_M_findA_at(M1, "fingerprint", 0) : tsk_null;
+ is_dtls_fingerprint_changed[index] = (A0 && A1 && !tsk_striequals(A0->value, A1->value));
+ }
+ // network info (session-level)
+ if (!is_ro_network_info_changed[index]) {
+ C0 = (const tsdp_header_C_t*)tsdp_message_get_headerAt(self->sdp.ro, tsdp_htype_C, index);
+ C1 = (const tsdp_header_C_t*)tsdp_message_get_headerAt(sdp, tsdp_htype_C, index);
+ // Connection informations must be both "null" or "not-null"
+ if (!(is_ro_network_info_changed[index] = !((C0 && C1) || (!C0 && !C1)))) {
+ if (C0) {
+ is_ro_network_info_changed[index] = (!tsk_strequals(C1->addr, C0->addr) || !tsk_strequals(C1->nettype, C0->nettype) || !tsk_strequals(C1->addrtype, C0->addrtype));
+ }
+ }
+ }
// TODO: sdes crypo lines (session-level)
- // media type
- media_types[index] = tmedia_type_from_sdp_headerM(M1);
-
- // ice (session-level)
- if (tmedia_defaults_get_ice_enabled()) {
- is_ice_enabled[index] |= tsdp_message_is_ice_enabled(sdp, index);
- is_ice_restart[index] |= tsdp_message_is_ice_restart(sdp, index);
- }
-
- // ro_codecs
- if (had_lo_sdp && is_ro_codecs_changed[index]) {
- // we already have a local sdp (means codecs already negotiated) and the remote is changing the codecs
- tmedia_session_t* ms = (tmedia_session_t*)tsk_object_ref(TSK_OBJECT(_tmedia_session_mgr_find_session_at_index(self->sessions, index)));
- if (ms && ms->prepared) {
- tmedia_codec_t* encoder = tsk_null;
- tmedia_param_t* param_get_codec = tmedia_param_create_get_session(media_types[index], tmedia_pvt_pobject, "codec-encoder", &encoder);
- if (param_get_codec) {
- if (tmedia_session_get(ms, param_get_codec) == 0) {
- if (encoder) {
- const char* codec_name = encoder->plugin ? encoder->plugin->name : "unknown";
- const char* neg_format = encoder->neg_format ? encoder->neg_format : encoder->format;
- if (tsdp_header_M_have_fmt(M1, neg_format) == tsk_true) { // new ro has the old encoder?
- // same rtpmap would produce same encoder -> change nothing
- char* old_rtpmap = tsdp_header_M_get_rtpmap(M0, neg_format);
- char* new_rtpmap = tsdp_header_M_get_rtpmap(M1, neg_format);
- is_local_encoder_still_ok[index] = tsk_striequals(old_rtpmap, new_rtpmap);
- TSK_FREE(old_rtpmap); TSK_FREE(new_rtpmap);
- if (is_local_encoder_still_ok[index]) {
- // TODO: add more checks
- }
- }
- TSK_OBJECT_SAFE_FREE(encoder); // destroying "param_get_codec" won't release "encoder"
- }
- }
- TSK_OBJECT_SAFE_FREE(param_get_codec);
- }
- }
- TSK_OBJECT_SAFE_FREE(ms);
- }
-
- ++index;
- }
- // the index was used against current ro which means at this step there is no longer any media at "index"
- // to be sure that new and old sdp have same number of media lines, we just check that there is no media in the new sdp at "index"
- is_ro_media_lines_changed |= (tsdp_message_get_headerAt(sdp, tsdp_htype_M, index) != tsk_null);
- }
-
- /*
- * Make sure that the provisional response is an preview of the final as explained rfc6337 section 3.1.1. We only check the most important part (IP addr and ports).
- * It's useless to check codecs or any other caps (SRTP, ICE, DTLS...) as our offer haven't changed
- * If the preview is different than the final response than this is a bug on the remote party:
- * As per rfc6337 section 3.1.1.:
- * - [RFC3261] requires all SDP in the responses to the INVITE request to be identical.
- * - After the UAS has sent the answer in a reliable provisional
- response to the INVITE, the UAS should not include any SDPs in
- subsequent responses to the INVITE.
- * If the remote party is buggy, then the newly generated local SDP will be sent in the ACK request
- */
- is_ro_provisional_final_matching &= !(is_ro_media_lines_changed || __flags_sum((const tsk_bool_t*)&is_ro_network_info_changed, m_lines_count));
-
- /* This is to hack fake forking from ZTE => ignore SDP with loopback address in order to not start/stop the camera several
- * times which leads to more than ten seconds for session connection.
- * Gets the global connection line: "c="
- * Loopback address is only invalid on
- */
- if ((C = (const tsdp_header_C_t*)tsdp_message_get_header(sdp, tsdp_htype_C)) && C->addr){
- tsk_bool_t _is_ro_loopback_address = (tsk_striequals("IP4", C->addrtype) && tsk_striequals("127.0.0.1", C->addr))
- || (tsk_striequals("IP6", C->addrtype) && tsk_striequals("::1", C->addr));
- for (index = 0; index < m_lines_count; ++index) {
- is_ro_loopback_address[index] = _is_ro_loopback_address;
- }
- }
-
- /* Check if media type has changed or not
- * For initial offer we don't need to check anything
- */
- if (self->sdp.lo) {
- if ((is_media_type_changed = (new_mediatype != self->type)) || is_new_mediatype_striped) {
- tsk_bool_t force = !!is_new_mediatype_striped;
- tmedia_session_mgr_set_media_type_2(self, new_mediatype, force);
- TSK_DEBUG_INFO("media type has changed");
- }
- }
-
- TSK_DEBUG_INFO(
- "m_lines_count=%u,\n"
- "is_dtls_fingerprint_changed=%u,\n"
+ // media type
+ media_types[index] = tmedia_type_from_sdp_headerM(M1);
+
+ // ice (session-level)
+ if (tmedia_defaults_get_ice_enabled()) {
+ is_ice_enabled[index] |= tsdp_message_is_ice_enabled(sdp, index);
+ is_ice_restart[index] |= tsdp_message_is_ice_restart(sdp, index);
+ }
+
+ // ro_codecs
+ if (had_lo_sdp && is_ro_codecs_changed[index]) {
+ // we already have a local sdp (means codecs already negotiated) and the remote is changing the codecs
+ tmedia_session_t* ms = (tmedia_session_t*)tsk_object_ref(TSK_OBJECT(_tmedia_session_mgr_find_session_at_index(self->sessions, index)));
+ if (ms && ms->prepared) {
+ tmedia_codec_t* encoder = tsk_null;
+ tmedia_param_t* param_get_codec = tmedia_param_create_get_session(media_types[index], tmedia_pvt_pobject, "codec-encoder", &encoder);
+ if (param_get_codec) {
+ if (tmedia_session_get(ms, param_get_codec) == 0) {
+ if (encoder) {
+ const char* codec_name = encoder->plugin ? encoder->plugin->name : "unknown";
+ const char* neg_format = encoder->neg_format ? encoder->neg_format : encoder->format;
+ if (tsdp_header_M_have_fmt(M1, neg_format) == tsk_true) { // new ro has the old encoder?
+ // same rtpmap would produce same encoder -> change nothing
+ char* old_rtpmap = tsdp_header_M_get_rtpmap(M0, neg_format);
+ char* new_rtpmap = tsdp_header_M_get_rtpmap(M1, neg_format);
+ is_local_encoder_still_ok[index] = tsk_striequals(old_rtpmap, new_rtpmap);
+ TSK_FREE(old_rtpmap);
+ TSK_FREE(new_rtpmap);
+ if (is_local_encoder_still_ok[index]) {
+ // TODO: add more checks
+ }
+ }
+ TSK_OBJECT_SAFE_FREE(encoder); // destroying "param_get_codec" won't release "encoder"
+ }
+ }
+ TSK_OBJECT_SAFE_FREE(param_get_codec);
+ }
+ }
+ TSK_OBJECT_SAFE_FREE(ms);
+ }
+
+ ++index;
+ }
+ // the index was used against current ro which means at this step there is no longer any media at "index"
+ // to be sure that new and old sdp have same number of media lines, we just check that there is no media in the new sdp at "index"
+ is_ro_media_lines_changed |= (tsdp_message_get_headerAt(sdp, tsdp_htype_M, index) != tsk_null);
+ }
+
+ /*
+ * Make sure that the provisional response is an preview of the final as explained rfc6337 section 3.1.1. We only check the most important part (IP addr and ports).
+ * It's useless to check codecs or any other caps (SRTP, ICE, DTLS...) as our offer haven't changed
+ * If the preview is different than the final response than this is a bug on the remote party:
+ * As per rfc6337 section 3.1.1.:
+ * - [RFC3261] requires all SDP in the responses to the INVITE request to be identical.
+ * - After the UAS has sent the answer in a reliable provisional
+ response to the INVITE, the UAS should not include any SDPs in
+ subsequent responses to the INVITE.
+ * If the remote party is buggy, then the newly generated local SDP will be sent in the ACK request
+ */
+ is_ro_provisional_final_matching &= !(is_ro_media_lines_changed || __flags_sum((const tsk_bool_t*)&is_ro_network_info_changed, m_lines_count));
+
+ /* This is to hack fake forking from ZTE => ignore SDP with loopback address in order to not start/stop the camera several
+ * times which leads to more than ten seconds for session connection.
+ * Gets the global connection line: "c="
+ * Loopback address is only invalid on
+ */
+ if ((C = (const tsdp_header_C_t*)tsdp_message_get_header(sdp, tsdp_htype_C)) && C->addr) {
+ tsk_bool_t _is_ro_loopback_address = (tsk_striequals("IP4", C->addrtype) && tsk_striequals("127.0.0.1", C->addr))
+ || (tsk_striequals("IP6", C->addrtype) && tsk_striequals("::1", C->addr));
+ for (index = 0; index < m_lines_count; ++index) {
+ is_ro_loopback_address[index] = _is_ro_loopback_address;
+ }
+ }
+
+ /* Check if media type has changed or not
+ * For initial offer we don't need to check anything
+ */
+ if (self->sdp.lo) {
+ if ((is_media_type_changed = (new_mediatype != self->type)) || is_new_mediatype_striped) {
+ tsk_bool_t force = !!is_new_mediatype_striped;
+ tmedia_session_mgr_set_media_type_2(self, new_mediatype, force);
+ TSK_DEBUG_INFO("media type has changed");
+ }
+ }
+
+ TSK_DEBUG_INFO(
+ "m_lines_count=%u,\n"
+ "is_dtls_fingerprint_changed=%u,\n"
"is_sdes_crypto_changed=%u,\n"
- "is_ice_enabled=%u,\n"
- "is_ice_restart=%u,\n"
- "is_ro_hold_resume_changed=%u,\n"
- "is_ro_provisional_final_matching=%d,\n"
- "is_ro_media_lines_changed=%d,\n"
- "is_ro_network_info_changed=%u,\n"
- "is_ro_loopback_address=%u,\n"
- "is_media_type_changed=%d,\n"
- "is_ro_codecs_changed=%u\n"
- "is_local_encoder_still_ok=%u\n",
- (unsigned)m_lines_count,
- (unsigned)__flags_sum((const tsk_bool_t*)&is_dtls_fingerprint_changed, m_lines_count),
+ "is_ice_enabled=%u,\n"
+ "is_ice_restart=%u,\n"
+ "is_ro_hold_resume_changed=%u,\n"
+ "is_ro_provisional_final_matching=%d,\n"
+ "is_ro_media_lines_changed=%d,\n"
+ "is_ro_network_info_changed=%u,\n"
+ "is_ro_loopback_address=%u,\n"
+ "is_media_type_changed=%d,\n"
+ "is_ro_codecs_changed=%u\n"
+ "is_local_encoder_still_ok=%u\n",
+ (unsigned)m_lines_count,
+ (unsigned)__flags_sum((const tsk_bool_t*)&is_dtls_fingerprint_changed, m_lines_count),
(unsigned)__flags_sum((const tsk_bool_t*)&is_sdes_crypto_changed, m_lines_count),
- (unsigned)__flags_sum((const tsk_bool_t*)&is_ice_enabled, m_lines_count),
- (unsigned)__flags_sum((const tsk_bool_t*)&is_ice_restart, m_lines_count),
- (unsigned)__flags_sum((const tsk_bool_t*)&is_ro_hold_resume_changed, m_lines_count),
- is_ro_provisional_final_matching,
- is_ro_media_lines_changed,
- (unsigned)__flags_sum((const tsk_bool_t*)&is_ro_network_info_changed, m_lines_count),
- (unsigned)__flags_sum((const tsk_bool_t*)&is_ro_loopback_address, m_lines_count),
- is_media_type_changed,
- (unsigned)__flags_sum((const tsk_bool_t*)&is_ro_codecs_changed, m_lines_count),
- (unsigned)__flags_sum((const tsk_bool_t*)&is_local_encoder_still_ok, m_lines_count)
- );
-
- /*
- * It's almost impossible to update the codecs, the connection information etc etc while the sessions are running
- * For example, if the video producer is already started then, you probably cannot update its configuration
- * without stoping it and restarting it again with the right config. Same for RTP Network config (ip addresses, NAT, ports, IP version, ...)
- *
- * "is_loopback_address" is used as a guard to avoid reconf for loopback address used for example by ZTE for fake forking. In all case
- * loopback address won't work on embedded devices such as iOS and Android.
- *
- */
- if (self->started) {
- for (index = 0; index < m_lines_count; ++index) {
- if (/* && (!is_ro_loopback_address[index]) && */ ((is_ro_codecs_changed[index] && !is_local_encoder_still_ok[index]) || is_ro_network_info_changed[index] || is_dtls_fingerprint_changed[index] || is_sdes_crypto_changed[index])) {
- TSK_DEBUG_INFO("Stop media index %d to reconf", (int)index);
- stopped_to_reconf[index] = tsk_true;
- tmedia_session_mgr_set(self,
- TMEDIA_SESSION_SET_INT32(media_types[index], "stop-to-reconf", stopped_to_reconf[index]),
- TMEDIA_SESSION_SET_NULL());
- if ((ret = _tmedia_session_mgr_stop(self, (int)index))){
- TSK_DEBUG_ERROR("Failed to stop session manager");
- goto bail;
- }
- }
- }
- }
-
- /* update remote offer */
- TSK_OBJECT_SAFE_FREE(self->sdp.ro);
- self->sdp.ro = tsk_object_ref((void*)sdp);
-
- /* - if the session is running this means no session update is required unless some important changes
- - this check must be done after the "ro" update
- - "is_ro_hold_resume_changed" do not restart the session but updates the SDP
- */
- if (self->started && !(__flags_sum((const tsk_bool_t*)&is_ro_hold_resume_changed, m_lines_count) || __flags_sum((const tsk_bool_t*)&stopped_to_reconf, m_lines_count) || is_ro_media_lines_changed)) {
- goto end_of_sessions_update;
- }
-
- /* prepare the session manager if not already done (create all sessions with their codecs)
- * if network-initiated: think about tmedia_type_from_sdp() before creating the manager */
- if (_tmedia_session_mgr_load_sessions(self)){
- TSK_DEBUG_ERROR("Failed to prepare the session manager");
- ret = -3;
- goto bail;
- }
- // update media line counts
- index = m_lines_count; // save old "m_lines_count" before loading sessions
- m_lines_count = tsk_list_count_all(self->sessions); // "m_lines_count" after loading sessions
- TSK_DEBUG_INFO("new m_lines_count = %u -> %u", (unsigned)index, (unsigned)m_lines_count);
- if (index != m_lines_count) { // start new sessions
- for (; index < m_lines_count; ++index) { // for(session in new_sessions)
- stopped_to_reconf[index] = self->started; // start new session if mgr started
- if (tmedia_defaults_get_ice_enabled()) {
- is_ice_enabled[index] |= tsdp_message_is_ice_enabled(sdp, index);
- is_ice_restart[index] |= tsdp_message_is_ice_restart(sdp, index);
- }
- }
- }
-
- /* get global connection line (common to all sessions)
- * Each session should override this info if it has a different one in its "m=" line
- * /!\ "remote-ip" is deprecated by "remote-sdp-message" and pending before complete remove
- */
- if (C && C->addr){
- tmedia_session_mgr_set(self,
- TMEDIA_SESSION_SET_STR(self->type, "remote-ip", C->addr),
- TMEDIA_SESSION_SET_NULL());
- }
-
- /* pass complete remote sdp to the sessions to allow them to use session-level attributes
- */
- tmedia_session_mgr_set(self,
- TMEDIA_SESSION_SET_POBJECT(self->type, "remote-sdp-message", self->sdp.ro),
- TMEDIA_SESSION_SET_NULL());
-
- /* foreach "m=" line in the remote offer create/prepare a session (requires the session to be stopped)*/
- index = 0;
- tsk_list_pushback_list(list_tmp_sessions, self->sessions);
- tsk_list_clear_items(self->sessions);
- while ((M = (const tsdp_header_M_t*)tsdp_message_get_headerAt(sdp, tsdp_htype_M, index++))) {
- found = tsk_false;
+ (unsigned)__flags_sum((const tsk_bool_t*)&is_ice_enabled, m_lines_count),
+ (unsigned)__flags_sum((const tsk_bool_t*)&is_ice_restart, m_lines_count),
+ (unsigned)__flags_sum((const tsk_bool_t*)&is_ro_hold_resume_changed, m_lines_count),
+ is_ro_provisional_final_matching,
+ is_ro_media_lines_changed,
+ (unsigned)__flags_sum((const tsk_bool_t*)&is_ro_network_info_changed, m_lines_count),
+ (unsigned)__flags_sum((const tsk_bool_t*)&is_ro_loopback_address, m_lines_count),
+ is_media_type_changed,
+ (unsigned)__flags_sum((const tsk_bool_t*)&is_ro_codecs_changed, m_lines_count),
+ (unsigned)__flags_sum((const tsk_bool_t*)&is_local_encoder_still_ok, m_lines_count)
+ );
+
+ /*
+ * It's almost impossible to update the codecs, the connection information etc etc while the sessions are running
+ * For example, if the video producer is already started then, you probably cannot update its configuration
+ * without stoping it and restarting it again with the right config. Same for RTP Network config (ip addresses, NAT, ports, IP version, ...)
+ *
+ * "is_loopback_address" is used as a guard to avoid reconf for loopback address used for example by ZTE for fake forking. In all case
+ * loopback address won't work on embedded devices such as iOS and Android.
+ *
+ */
+ if (self->started) {
+ for (index = 0; index < m_lines_count; ++index) {
+ if (/* && (!is_ro_loopback_address[index]) && */ ((is_ro_codecs_changed[index] && !is_local_encoder_still_ok[index]) || is_ro_network_info_changed[index] || is_dtls_fingerprint_changed[index] || is_sdes_crypto_changed[index])) {
+ TSK_DEBUG_INFO("Stop media index %d to reconf", (int)index);
+ stopped_to_reconf[index] = tsk_true;
+ tmedia_session_mgr_set(self,
+ TMEDIA_SESSION_SET_INT32(media_types[index], "stop-to-reconf", stopped_to_reconf[index]),
+ TMEDIA_SESSION_SET_NULL());
+ if ((ret = _tmedia_session_mgr_stop(self, (int)index))) {
+ TSK_DEBUG_ERROR("Failed to stop session manager");
+ goto bail;
+ }
+ }
+ }
+ }
+
+ /* update remote offer */
+ TSK_OBJECT_SAFE_FREE(self->sdp.ro);
+ self->sdp.ro = tsk_object_ref((void*)sdp);
+
+ /* - if the session is running this means no session update is required unless some important changes
+ - this check must be done after the "ro" update
+ - "is_ro_hold_resume_changed" do not restart the session but updates the SDP
+ */
+ if (self->started && !(__flags_sum((const tsk_bool_t*)&is_ro_hold_resume_changed, m_lines_count) || __flags_sum((const tsk_bool_t*)&stopped_to_reconf, m_lines_count) || is_ro_media_lines_changed)) {
+ goto end_of_sessions_update;
+ }
+
+ /* prepare the session manager if not already done (create all sessions with their codecs)
+ * if network-initiated: think about tmedia_type_from_sdp() before creating the manager */
+ if (_tmedia_session_mgr_load_sessions(self)) {
+ TSK_DEBUG_ERROR("Failed to prepare the session manager");
+ ret = -3;
+ goto bail;
+ }
+ // update media line counts
+ index = m_lines_count; // save old "m_lines_count" before loading sessions
+ m_lines_count = tsk_list_count_all(self->sessions); // "m_lines_count" after loading sessions
+ TSK_DEBUG_INFO("new m_lines_count = %u -> %u", (unsigned)index, (unsigned)m_lines_count);
+ if (index != m_lines_count) { // start new sessions
+ for (; index < m_lines_count; ++index) { // for(session in new_sessions)
+ stopped_to_reconf[index] = self->started; // start new session if mgr started
+ if (tmedia_defaults_get_ice_enabled()) {
+ is_ice_enabled[index] |= tsdp_message_is_ice_enabled(sdp, index);
+ is_ice_restart[index] |= tsdp_message_is_ice_restart(sdp, index);
+ }
+ }
+ }
+
+ /* get global connection line (common to all sessions)
+ * Each session should override this info if it has a different one in its "m=" line
+ * /!\ "remote-ip" is deprecated by "remote-sdp-message" and pending before complete remove
+ */
+ if (C && C->addr) {
+ tmedia_session_mgr_set(self,
+ TMEDIA_SESSION_SET_STR(self->type, "remote-ip", C->addr),
+ TMEDIA_SESSION_SET_NULL());
+ }
+
+ /* pass complete remote sdp to the sessions to allow them to use session-level attributes
+ */
+ tmedia_session_mgr_set(self,
+ TMEDIA_SESSION_SET_POBJECT(self->type, "remote-sdp-message", self->sdp.ro),
+ TMEDIA_SESSION_SET_NULL());
+
+ /* foreach "m=" line in the remote offer create/prepare a session (requires the session to be stopped)*/
+ index = 0;
+ tsk_list_pushback_list(list_tmp_sessions, self->sessions);
+ tsk_list_clear_items(self->sessions);
+ while ((M = (const tsdp_header_M_t*)tsdp_message_get_headerAt(sdp, tsdp_htype_M, index++))) {
+ found = tsk_false;
#if 1
- // rfc3264 - 8 Modifying the Session
- // if the previous SDP had N "m=" lines, the new SDP MUST have at least N "m=" lines
- // Deleted media streams from a previous SDP MUST NOT be removed in a new SDP
- if (had_lo_sdp) {
- ms = _tmedia_session_mgr_find_session_at_index(list_tmp_sessions, (index - 1 - active_sessions_count));
- }
- else {
- // Initial Offer
- tmedia_type_t M_media_type = tmedia_type_from_sdp_headerM(M);
- ms = tsk_list_find_object_by_pred(list_tmp_sessions, __pred_find_session_by_type, &M_media_type);
- }
+ // rfc3264 - 8 Modifying the Session
+ // if the previous SDP had N "m=" lines, the new SDP MUST have at least N "m=" lines
+ // Deleted media streams from a previous SDP MUST NOT be removed in a new SDP
+ if (had_lo_sdp) {
+ ms = _tmedia_session_mgr_find_session_at_index(list_tmp_sessions, (index - 1 - active_sessions_count));
+ }
+ else {
+ // Initial Offer
+ tmedia_type_t M_media_type = tmedia_type_from_sdp_headerM(M);
+ ms = tsk_list_find_object_by_pred(list_tmp_sessions, __pred_find_session_by_type, &M_media_type);
+ }
#else
- if (ro_type & tmedia_ro_type_answer) {
- // Answer -> match by index
- ms = _tmedia_session_mgr_find_session_at_index(list_tmp_sessions, (index - 1 - active_sessions_count));
- }
- else {
- // Request -> match by type
- tmedia_type_t M_media_type = tmedia_type_from_sdp_headerM(M);
- ms = tsk_list_find_object_by_pred(list_tmp_sessions, __pred_find_session_by_type, &M_media_type);
- }
+ if (ro_type & tmedia_ro_type_answer) {
+ // Answer -> match by index
+ ms = _tmedia_session_mgr_find_session_at_index(list_tmp_sessions, (index - 1 - active_sessions_count));
+ }
+ else {
+ // Request -> match by type
+ tmedia_type_t M_media_type = tmedia_type_from_sdp_headerM(M);
+ ms = tsk_list_find_object_by_pred(list_tmp_sessions, __pred_find_session_by_type, &M_media_type);
+ }
#endif
- if (ms && (tsk_striequals(tmedia_session_get_media(ms), M->media))) {
- /* prepare the media session */
- if (!ms->prepared && M->port && (_tmedia_session_prepare(TMEDIA_SESSION(ms)))){
- TSK_DEBUG_ERROR("Failed to prepare session"); /* should never happen */
- goto bail;
- }
- /* set remote ro at session-level unless media is disabled (port=0) */
- if (M->port == 0 || (ret = _tmedia_session_set_ro(TMEDIA_SESSION(ms), M)) == 0) {
- tmedia_session_t* _ms = tsk_object_ref(TSK_OBJECT(ms));
- found = tsk_true;
- ++active_sessions_count;
- tsk_list_push_back_data(self->sessions, (void**)&_ms); // add at the same index
- tsk_list_remove_item_by_data(list_tmp_sessions, ms); // make sure not to use the session more than once
- }
- else {
- TSK_DEBUG_WARN("_tmedia_session_set_ro() failed");
- ret = 0; // add ghost for this session. Do not goto bail because set_ro() is allowed to fail (e.g. codec mismatch).
- }
- /* set QoS type (only if we are not the offerer) */
- if (/*!self->offerer ==> we suppose that the remote party respected our demand &&*/ qos_type == tmedia_qos_stype_none) {
- tmedia_qos_tline_t* tline = tmedia_qos_tline_from_sdp(M);
- if (tline) {
- qos_type = tline->type;
- TSK_OBJECT_SAFE_FREE(tline);
- }
- }
- }
-
- if (!found /*&& (self->sdp.lo == tsk_null)*/){
- /* Session not supported and we are not the initial offerer ==> add ghost session */
- /*
- An offered stream MAY be rejected in the answer, for any reason. If
- a stream is rejected, the offerer and answerer MUST NOT generate
- media (or RTCP packets) for that stream. To reject an offered
- stream, the port number in the corresponding stream in the answer
- MUST be set to zero. Any media formats listed are ignored. AT LEAST
- ONE MUST BE PRESENT, AS SPECIFIED BY SDP.
- */
- tmedia_session_ghost_t* ghost;
- if ((ghost = (tmedia_session_ghost_t*)tmedia_session_create(tmedia_ghost))){
- tsk_strupdate(&ghost->media, M->media); /* copy media */
- tsk_strupdate(&ghost->proto, M->proto); /* copy proto */
- if (!TSK_LIST_IS_EMPTY(M->FMTs)){
- tsk_strupdate(&ghost->first_format, ((const tsdp_fmt_t*)TSK_LIST_FIRST_DATA(M->FMTs))->value); /* copy format */
- }
- tsk_list_push_back_data(self->sessions, (void**)&ghost);
- }
- else {
- TSK_DEBUG_ERROR("Failed to create ghost session");
- continue;
- }
- }
- }
+ if (ms && (tsk_striequals(tmedia_session_get_media(ms), M->media))) {
+ /* prepare the media session */
+ if (!ms->prepared && M->port && (_tmedia_session_prepare(TMEDIA_SESSION(ms)))) {
+ TSK_DEBUG_ERROR("Failed to prepare session"); /* should never happen */
+ goto bail;
+ }
+ /* set remote ro at session-level unless media is disabled (port=0) */
+ if (M->port == 0 || (ret = _tmedia_session_set_ro(TMEDIA_SESSION(ms), M)) == 0) {
+ tmedia_session_t* _ms = tsk_object_ref(TSK_OBJECT(ms));
+ found = tsk_true;
+ ++active_sessions_count;
+ tsk_list_push_back_data(self->sessions, (void**)&_ms); // add at the same index
+ tsk_list_remove_item_by_data(list_tmp_sessions, ms); // make sure not to use the session more than once
+ }
+ else {
+ TSK_DEBUG_WARN("_tmedia_session_set_ro() failed");
+ ret = 0; // add ghost for this session. Do not goto bail because set_ro() is allowed to fail (e.g. codec mismatch).
+ }
+ /* set QoS type (only if we are not the offerer) */
+ if (/*!self->offerer ==> we suppose that the remote party respected our demand &&*/ qos_type == tmedia_qos_stype_none) {
+ tmedia_qos_tline_t* tline = tmedia_qos_tline_from_sdp(M);
+ if (tline) {
+ qos_type = tline->type;
+ TSK_OBJECT_SAFE_FREE(tline);
+ }
+ }
+ }
+
+ if (!found /*&& (self->sdp.lo == tsk_null)*/) {
+ /* Session not supported and we are not the initial offerer ==> add ghost session */
+ /*
+ An offered stream MAY be rejected in the answer, for any reason. If
+ a stream is rejected, the offerer and answerer MUST NOT generate
+ media (or RTCP packets) for that stream. To reject an offered
+ stream, the port number in the corresponding stream in the answer
+ MUST be set to zero. Any media formats listed are ignored. AT LEAST
+ ONE MUST BE PRESENT, AS SPECIFIED BY SDP.
+ */
+ tmedia_session_ghost_t* ghost;
+ if ((ghost = (tmedia_session_ghost_t*)tmedia_session_create(tmedia_ghost))) {
+ tsk_strupdate(&ghost->media, M->media); /* copy media */
+ tsk_strupdate(&ghost->proto, M->proto); /* copy proto */
+ if (!TSK_LIST_IS_EMPTY(M->FMTs)) {
+ tsk_strupdate(&ghost->first_format, ((const tsdp_fmt_t*)TSK_LIST_FIRST_DATA(M->FMTs))->value); /* copy format */
+ }
+ tsk_list_push_back_data(self->sessions, (void**)&ghost);
+ }
+ else {
+ TSK_DEBUG_ERROR("Failed to create ghost session");
+ continue;
+ }
+ }
+ }
end_of_sessions_update:
- /* update QoS type */
- if (!self->offerer && (qos_type != tmedia_qos_stype_none)){
- self->qos.type = qos_type;
- }
-
- /* signal that ro has changed (will be used to update lo) unless there was no ro_sdp */
- self->ro_changed = (had_ro_sdp && (__flags_sum((const tsk_bool_t*)&is_ro_hold_resume_changed, m_lines_count) || __flags_sum((const tsk_bool_t*)&is_ro_network_info_changed, m_lines_count) || is_ro_media_lines_changed || __flags_sum((const tsk_bool_t*)&is_ro_codecs_changed, m_lines_count) /*|| is_media_type_changed || is_new_mediatype_striped*/));
-
- /* update "provisional" info */
- self->ro_provisional = ((ro_type & tmedia_ro_type_provisional) == tmedia_ro_type_provisional);
-
- if (self->ro_changed) {
- /* update local offer before restarting the session manager otherwise neg_codecs won't match if new codecs
- have been added or removed. No need to load sessions again. */
- (_tmedia_session_mgr_get_lo(self, kSkipSessionLoadTrue, kForceUpdateLOFalse));
- }
- /* manager was started and we stopped it in order to reconfigure it (codecs, network, ....)
- * When ICE is active ("is_ice_active" = yes), the media session will be explicitly restarted when conncheck succeed or fail.
- */
- for (index = 0; index < m_lines_count; ++index) {
- if (stopped_to_reconf[index] && !is_ice_enabled[index]) {
- if ((ret = _tmedia_session_mgr_start(self, (int)index))) {
- TSK_DEBUG_ERROR("Failed to re-start session at index = %d", (int)index);
- goto bail;
- }
- }
- }
-
- // will send [488 Not Acceptable] / [BYE] if no active session
- ret = (self->ro_changed && active_sessions_count <= 0) ? -0xFF : 0;
+ /* update QoS type */
+ if (!self->offerer && (qos_type != tmedia_qos_stype_none)) {
+ self->qos.type = qos_type;
+ }
+
+ /* signal that ro has changed (will be used to update lo) unless there was no ro_sdp */
+ self->ro_changed = (had_ro_sdp && (__flags_sum((const tsk_bool_t*)&is_ro_hold_resume_changed, m_lines_count) || __flags_sum((const tsk_bool_t*)&is_ro_network_info_changed, m_lines_count) || is_ro_media_lines_changed || __flags_sum((const tsk_bool_t*)&is_ro_codecs_changed, m_lines_count) /*|| is_media_type_changed || is_new_mediatype_striped*/));
+
+ /* update "provisional" info */
+ self->ro_provisional = ((ro_type & tmedia_ro_type_provisional) == tmedia_ro_type_provisional);
+
+ if (self->ro_changed) {
+ /* update local offer before restarting the session manager otherwise neg_codecs won't match if new codecs
+ have been added or removed. No need to load sessions again. */
+ (_tmedia_session_mgr_get_lo(self, kSkipSessionLoadTrue, kForceUpdateLOFalse));
+ }
+ /* manager was started and we stopped it in order to reconfigure it (codecs, network, ....)
+ * When ICE is active ("is_ice_active" = yes), the media session will be explicitly restarted when conncheck succeed or fail.
+ */
+ for (index = 0; index < m_lines_count; ++index) {
+ if (stopped_to_reconf[index] && !is_ice_enabled[index]) {
+ if ((ret = _tmedia_session_mgr_start(self, (int)index))) {
+ TSK_DEBUG_ERROR("Failed to re-start session at index = %d", (int)index);
+ goto bail;
+ }
+ }
+ }
+
+ // will send [488 Not Acceptable] / [BYE] if no active session
+ ret = (self->ro_changed && active_sessions_count <= 0) ? -0xFF : 0;
bail:
- TSK_OBJECT_SAFE_FREE(list_tmp_sessions);
+ TSK_OBJECT_SAFE_FREE(list_tmp_sessions);
- tsk_safeobj_unlock(self);
- tsk_list_unlock(self->sessions);
- return ret;
+ tsk_safeobj_unlock(self);
+ tsk_list_unlock(self->sessions);
+ return ret;
}
const tsdp_message_t* tmedia_session_mgr_get_ro(tmedia_session_mgr_t* self)
{
- if (!self){
- TSK_DEBUG_ERROR("Invalid parameter");
- return tsk_null;
- }
- return self->sdp.ro;
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
+ return self->sdp.ro;
}
tsk_bool_t tmedia_session_mgr_is_new_ro(tmedia_session_mgr_t* self, const tsdp_message_t* sdp)
{
- tsk_bool_t is_new = tsk_true;
- const tsdp_header_O_t* O;
+ tsk_bool_t is_new = tsk_true;
+ const tsdp_header_O_t* O;
- if (!self || !sdp){
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
+ if (!self || !sdp) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
- tsk_safeobj_lock(self);
+ tsk_safeobj_lock(self);
- if ((O = (const tsdp_header_O_t*)tsdp_message_get_header(sdp, tsdp_htype_O))) {
- is_new = (self->sdp.ro_ver != (int32_t)O->sess_version);
- }
- else {
- TSK_DEBUG_ERROR("o= line is missing");
- }
+ if ((O = (const tsdp_header_O_t*)tsdp_message_get_header(sdp, tsdp_htype_O))) {
+ is_new = (self->sdp.ro_ver != (int32_t)O->sess_version);
+ }
+ else {
+ TSK_DEBUG_ERROR("o= line is missing");
+ }
- tsk_safeobj_unlock(self);
- return is_new;
+ tsk_safeobj_unlock(self);
+ return is_new;
}
/**@ingroup tmedia_session_group
@@ -1581,23 +1649,23 @@ tsk_bool_t tmedia_session_mgr_is_new_ro(tmedia_session_mgr_t* self, const tsdp_m
*/
int tmedia_session_mgr_hold(tmedia_session_mgr_t* self, tmedia_type_t type)
{
- const tsk_list_item_t* item;
+ const tsk_list_item_t* item;
- if (!self){
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
- tsk_list_foreach(item, self->sessions){
- tmedia_session_t* session = TMEDIA_SESSION(item->data);
- if (((session->type & type) == session->type) && session->M.lo){
- if (tsdp_header_M_hold(session->M.lo, tsk_true) == 0){
- self->state_changed = tsk_true;
- session->lo_held = tsk_true;
- }
- }
- }
- return 0;
+ tsk_list_foreach(item, self->sessions) {
+ tmedia_session_t* session = TMEDIA_SESSION(item->data);
+ if (((session->type & type) == session->type) && session->M.lo) {
+ if (tsdp_header_M_hold(session->M.lo, tsk_true) == 0) {
+ self->state_changed = tsk_true;
+ session->lo_held = tsk_true;
+ }
+ }
+ }
+ return 0;
}
/**@ingroup tmedia_session_group
@@ -1608,33 +1676,33 @@ int tmedia_session_mgr_hold(tmedia_session_mgr_t* self, tmedia_type_t type)
*/
tsk_bool_t tmedia_session_mgr_is_held(tmedia_session_mgr_t* self, tmedia_type_t type, tsk_bool_t local)
{
- const tsk_list_item_t* item;
- tsk_bool_t have_these_sessions = tsk_false;
-
- if (!self){
- TSK_DEBUG_ERROR("Invalid parameter");
- return tsk_false;
- }
-
- tsk_list_foreach(item, self->sessions){
- tmedia_session_t* session = TMEDIA_SESSION(item->data);
- if ((session->type & type) == session->type){
- if (local && session->M.lo){
- have_these_sessions = tsk_true;
- if (!tsdp_header_M_is_held(session->M.lo, tsk_true)){
- return tsk_false;
- }
- }
- else if (!local && session->M.ro){
- have_these_sessions = tsk_true;
- if (!tsdp_header_M_is_held(session->M.ro, tsk_false)){
- return tsk_false;
- }
- }
- }
- }
- /* none is held */
- return have_these_sessions ? tsk_true : tsk_false;
+ const tsk_list_item_t* item;
+ tsk_bool_t have_these_sessions = tsk_false;
+
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_false;
+ }
+
+ tsk_list_foreach(item, self->sessions) {
+ tmedia_session_t* session = TMEDIA_SESSION(item->data);
+ if ((session->type & type) == session->type) {
+ if (local && session->M.lo) {
+ have_these_sessions = tsk_true;
+ if (!tsdp_header_M_is_held(session->M.lo, tsk_true)) {
+ return tsk_false;
+ }
+ }
+ else if (!local && session->M.ro) {
+ have_these_sessions = tsk_true;
+ if (!tsdp_header_M_is_held(session->M.ro, tsk_false)) {
+ return tsk_false;
+ }
+ }
+ }
+ }
+ /* none is held */
+ return have_these_sessions ? tsk_true : tsk_false;
}
/**@ingroup tmedia_session_group
@@ -1647,28 +1715,28 @@ tsk_bool_t tmedia_session_mgr_is_held(tmedia_session_mgr_t* self, tmedia_type_t
*/
int tmedia_session_mgr_resume(tmedia_session_mgr_t* self, tmedia_type_t type, tsk_bool_t local)
{
- const tsk_list_item_t* item;
- int ret = 0;
- if (!self){
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
-
- tsk_list_foreach(item, self->sessions){
- tmedia_session_t* session = TMEDIA_SESSION(item->data);
- if (((session->type & type) == session->type) && session->M.lo){
- if ((ret = tsdp_header_M_resume(session->M.lo, local)) == 0){
- self->state_changed = tsk_true;
- if (local){
- session->lo_held = tsk_false;
- }
- else{
- session->ro_held = tsk_false;
- }
- }
- }
- }
- return ret;
+ const tsk_list_item_t* item;
+ int ret = 0;
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ tsk_list_foreach(item, self->sessions) {
+ tmedia_session_t* session = TMEDIA_SESSION(item->data);
+ if (((session->type & type) == session->type) && session->M.lo) {
+ if ((ret = tsdp_header_M_resume(session->M.lo, local)) == 0) {
+ self->state_changed = tsk_true;
+ if (local) {
+ session->lo_held = tsk_false;
+ }
+ else {
+ session->ro_held = tsk_false;
+ }
+ }
+ }
+ }
+ return ret;
}
/**@ingroup tmedia_session_group
@@ -1680,47 +1748,47 @@ int tmedia_session_mgr_resume(tmedia_session_mgr_t* self, tmedia_type_t type, ts
*/
int tmedia_session_mgr_add_media(tmedia_session_mgr_t* self, tmedia_type_t type)
{
- tsk_size_t i = 0;
- tmedia_session_t* session;
- const tmedia_session_plugin_def_t* plugin;
-
- if (!self){
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
-
- /* for each registered plugin match with the supplied type */
- while ((i < TMED_SESSION_MAX_PLUGINS) && (plugin = __tmedia_session_plugins[i++])){
- if ((plugin->type & type) == plugin->type){
- /* check whether we already support this media */
- if ((session = (tmedia_session_t*)tsk_list_find_object_by_pred(self->sessions, __pred_find_session_by_type, &plugin->type)) && session->plugin){
- if (session->prepared){
- TSK_DEBUG_WARN("[%s] already active", plugin->media);
- }
- else{
- /* exist but unprepared(port=0) */
- _tmedia_session_prepare(session);
- if (self->started && session->plugin->start){
- session->plugin->start(session);
- }
- self->state_changed = tsk_true;
- }
- }
- else{
- /* session not supported */
- self->state_changed = tsk_true;
- if ((session = tmedia_session_create(plugin->type))){
- if (self->started && session->plugin->start){
- session->plugin->start(session);
- }
- tsk_list_push_back_data(self->sessions, (void**)(&session));
- self->state_changed = tsk_true;
- }
- }
- }
- }
-
- return self->state_changed ? 0 : -2;
+ tsk_size_t i = 0;
+ tmedia_session_t* session;
+ const tmedia_session_plugin_def_t* plugin;
+
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ /* for each registered plugin match with the supplied type */
+ while ((i < TMED_SESSION_MAX_PLUGINS) && (plugin = __tmedia_session_plugins[i++])) {
+ if ((plugin->type & type) == plugin->type) {
+ /* check whether we already support this media */
+ if ((session = (tmedia_session_t*)tsk_list_find_object_by_pred(self->sessions, __pred_find_session_by_type, &plugin->type)) && session->plugin) {
+ if (session->prepared) {
+ TSK_DEBUG_WARN("[%s] already active", plugin->media);
+ }
+ else {
+ /* exist but unprepared(port=0) */
+ _tmedia_session_prepare(session);
+ if (self->started && session->plugin->start) {
+ session->plugin->start(session);
+ }
+ self->state_changed = tsk_true;
+ }
+ }
+ else {
+ /* session not supported */
+ self->state_changed = tsk_true;
+ if ((session = tmedia_session_create(plugin->type))) {
+ if (self->started && session->plugin->start) {
+ session->plugin->start(session);
+ }
+ tsk_list_push_back_data(self->sessions, (void**)(&session));
+ self->state_changed = tsk_true;
+ }
+ }
+ }
+ }
+
+ return self->state_changed ? 0 : -2;
}
/**@ingroup tmedia_session_group
@@ -1731,22 +1799,22 @@ int tmedia_session_mgr_add_media(tmedia_session_mgr_t* self, tmedia_type_t type)
*/
int tmedia_session_mgr_remove_media(tmedia_session_mgr_t* self, tmedia_type_t type)
{
- const tsk_list_item_t* item;
+ const tsk_list_item_t* item;
- if (!self){
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
- tsk_list_foreach(item, self->sessions){
- tmedia_session_t* session = TMEDIA_SESSION(item->data);
- if (((session->type & type) == session->type) && session->plugin->stop){
- if (!session->plugin->stop(session)){
- self->state_changed = tsk_true;
- }
- }
- }
- return 0;
+ tsk_list_foreach(item, self->sessions) {
+ tmedia_session_t* session = TMEDIA_SESSION(item->data);
+ if (((session->type & type) == session->type) && session->plugin->stop) {
+ if (!session->plugin->stop(session)) {
+ self->state_changed = tsk_true;
+ }
+ }
+ }
+ return 0;
}
/**@ingroup tmedia_session_group
@@ -1758,14 +1826,14 @@ int tmedia_session_mgr_remove_media(tmedia_session_mgr_t* self, tmedia_type_t ty
*/
int tmedia_session_mgr_set_qos(tmedia_session_mgr_t* self, tmedia_qos_stype_t qos_type, tmedia_qos_strength_t qos_strength)
{
- if (!self){
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
- self->qos.type = qos_type;
- self->qos.strength = qos_strength;
- return 0;
+ self->qos.type = qos_type;
+ self->qos.strength = qos_strength;
+ return 0;
}
/**@ingroup tmedia_session_group
@@ -1775,20 +1843,20 @@ int tmedia_session_mgr_set_qos(tmedia_session_mgr_t* self, tmedia_qos_stype_t qo
*/
tsk_bool_t tmedia_session_mgr_canresume(tmedia_session_mgr_t* self)
{
- const tsk_list_item_t* item;
+ const tsk_list_item_t* item;
- if (!self){
- TSK_DEBUG_ERROR("Invalid parameter");
- return tsk_true;
- }
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_true;
+ }
- tsk_list_foreach(item, self->sessions){
- tmedia_session_t* session = TMEDIA_SESSION(item->data);
- if (session && session->qos && !tmedia_qos_tline_canresume(session->qos)){
- return tsk_false;
- }
- }
- return tsk_true;
+ tsk_list_foreach(item, self->sessions) {
+ tmedia_session_t* session = TMEDIA_SESSION(item->data);
+ if (session && session->qos && !tmedia_qos_tline_canresume(session->qos)) {
+ return tsk_false;
+ }
+ }
+ return tsk_true;
}
@@ -1797,673 +1865,673 @@ tsk_bool_t tmedia_session_mgr_canresume(tmedia_session_mgr_t* self)
*/
tsk_bool_t tmedia_session_mgr_has_active_session(tmedia_session_mgr_t* self)
{
- const tsk_list_item_t* item;
+ const tsk_list_item_t* item;
- if (!self){
- TSK_DEBUG_ERROR("Invalid parameter");
- return tsk_false;
- }
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_false;
+ }
- tsk_list_foreach(item, self->sessions){
- tmedia_session_t* session = TMEDIA_SESSION(item->data);
- if (session && session->M.lo && session->M.lo->port){
- return tsk_true;
- }
- }
- return tsk_false;
+ tsk_list_foreach(item, self->sessions) {
+ tmedia_session_t* session = TMEDIA_SESSION(item->data);
+ if (session && session->M.lo && session->M.lo->port) {
+ return tsk_true;
+ }
+ }
+ return tsk_false;
}
int tmedia_session_mgr_send_dtmf(tmedia_session_mgr_t* self, uint8_t event)
{
- tmedia_session_audio_t* session;
- static const tmedia_type_t audio_type = tmedia_audio;
- int ret = -3;
+ tmedia_session_audio_t* session;
+ static const tmedia_type_t audio_type = tmedia_audio;
+ int ret = -3;
- if (!self){
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
- session = (tmedia_session_audio_t*)tsk_list_find_object_by_pred(self->sessions, __pred_find_session_by_type, &audio_type);
- if (session){
- session = tsk_object_ref(session);
- ret = tmedia_session_audio_send_dtmf(TMEDIA_SESSION_AUDIO(session), event);
- TSK_OBJECT_SAFE_FREE(session);
- }
- else{
- TSK_DEBUG_ERROR("No audio session associated to this manager");
- }
+ session = (tmedia_session_audio_t*)tsk_list_find_object_by_pred(self->sessions, __pred_find_session_by_type, &audio_type);
+ if (session) {
+ session = tsk_object_ref(session);
+ ret = tmedia_session_audio_send_dtmf(TMEDIA_SESSION_AUDIO(session), event);
+ TSK_OBJECT_SAFE_FREE(session);
+ }
+ else {
+ TSK_DEBUG_ERROR("No audio session associated to this manager");
+ }
- return ret;
+ return ret;
}
int tmedia_session_mgr_set_t140_ondata_cbfn(tmedia_session_mgr_t* self, const void* context, tmedia_session_t140_ondata_cb_f func)
{
- tmedia_session_t* session;
- int ret = -1;
- if ((session = tmedia_session_mgr_find(self, tmedia_t140))){
- ret = tmedia_session_t140_set_ondata_cbfn(session, context, func);
- TSK_OBJECT_SAFE_FREE(session);
- }
- return ret;
+ tmedia_session_t* session;
+ int ret = -1;
+ if ((session = tmedia_session_mgr_find(self, tmedia_t140))) {
+ ret = tmedia_session_t140_set_ondata_cbfn(session, context, func);
+ TSK_OBJECT_SAFE_FREE(session);
+ }
+ return ret;
}
int tmedia_session_mgr_send_t140_data(tmedia_session_mgr_t* self, enum tmedia_t140_data_type_e data_type, const void* data_ptr, unsigned data_size)
{
- tmedia_session_t* session;
- int ret = -1;
- if ((session = tmedia_session_mgr_find(self, tmedia_t140))){
- ret = tmedia_session_t140_send_data(session, data_type, data_ptr, data_size);
- TSK_OBJECT_SAFE_FREE(session);
- }
- return ret;
+ tmedia_session_t* session;
+ int ret = -1;
+ if ((session = tmedia_session_mgr_find(self, tmedia_t140))) {
+ ret = tmedia_session_t140_send_data(session, data_type, data_ptr, data_size);
+ TSK_OBJECT_SAFE_FREE(session);
+ }
+ return ret;
}
int tmedia_session_mgr_set_onrtcp_cbfn(tmedia_session_mgr_t* self, tmedia_type_t media_type, const void* context, tmedia_session_rtcp_onevent_cb_f fun)
{
- tmedia_session_t* session;
- tsk_list_item_t *item;
+ tmedia_session_t* session;
+ tsk_list_item_t *item;
- if (!self){
- TSK_DEBUG_ERROR("Invlid parameter");
- return -1;
- }
+ if (!self) {
+ TSK_DEBUG_ERROR("Invlid parameter");
+ return -1;
+ }
- tsk_list_lock(self->sessions);
- tsk_list_foreach(item, self->sessions){
- if (!(session = item->data) || !(session->type & media_type)){
- continue;
- }
- tmedia_session_set_onrtcp_cbfn(session, context, fun);
- }
- tsk_list_unlock(self->sessions);
+ tsk_list_lock(self->sessions);
+ tsk_list_foreach(item, self->sessions) {
+ if (!(session = item->data) || !(session->type & media_type)) {
+ continue;
+ }
+ tmedia_session_set_onrtcp_cbfn(session, context, fun);
+ }
+ tsk_list_unlock(self->sessions);
- return 0;
+ return 0;
}
int tmedia_session_mgr_send_rtcp_event(tmedia_session_mgr_t* self, tmedia_type_t media_type, tmedia_rtcp_event_type_t event_type, uint32_t ssrc_media)
{
- tmedia_session_t* session;
- tsk_list_item_t *item;
+ tmedia_session_t* session;
+ tsk_list_item_t *item;
- if (!self){
- TSK_DEBUG_ERROR("Invlid parameter");
- return -1;
- }
+ if (!self) {
+ TSK_DEBUG_ERROR("Invlid parameter");
+ return -1;
+ }
- tsk_list_lock(self->sessions);
- tsk_list_foreach(item, self->sessions){
- if (!(session = item->data) || !(session->type & media_type)){
- continue;
- }
- tmedia_session_send_rtcp_event(session, event_type, ssrc_media);
- }
- tsk_list_unlock(self->sessions);
+ tsk_list_lock(self->sessions);
+ tsk_list_foreach(item, self->sessions) {
+ if (!(session = item->data) || !(session->type & media_type)) {
+ continue;
+ }
+ tmedia_session_send_rtcp_event(session, event_type, ssrc_media);
+ }
+ tsk_list_unlock(self->sessions);
- return 0;
+ return 0;
}
int tmedia_session_mgr_recv_rtcp_event(tmedia_session_mgr_t* self, tmedia_type_t media_type, tmedia_rtcp_event_type_t event_type, uint32_t ssrc_media)
{
- static const uint64_t __fake_session_id = 0;
- return _tmedia_session_mgr_recv_rtcp_event(self, media_type, event_type, ssrc_media, __fake_session_id);
+ static const uint64_t __fake_session_id = 0;
+ return _tmedia_session_mgr_recv_rtcp_event(self, media_type, event_type, ssrc_media, __fake_session_id);
}
int tmedia_session_mgr_recv_rtcp_event_2(tmedia_session_mgr_t* self, tmedia_rtcp_event_type_t event_type, uint64_t session_id)
{
- static const uint32_t __fake_ssrc_media = 0;
- static const tmedia_type_t __fake_media_type = tmedia_none;
- return _tmedia_session_mgr_recv_rtcp_event(self, __fake_media_type, event_type, __fake_ssrc_media, session_id);
+ static const uint32_t __fake_ssrc_media = 0;
+ static const tmedia_type_t __fake_media_type = tmedia_none;
+ return _tmedia_session_mgr_recv_rtcp_event(self, __fake_media_type, event_type, __fake_ssrc_media, session_id);
}
int tmedia_session_mgr_send_file(tmedia_session_mgr_t* self, const char* path, ...)
{
- tmedia_session_msrp_t* session;
- tmedia_type_t msrp_type = tmedia_msrp;
- int ret = -3;
+ tmedia_session_msrp_t* session;
+ tmedia_type_t msrp_type = tmedia_msrp;
+ int ret = -3;
- if (!self || !path){
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
+ if (!self || !path) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
- session = (tmedia_session_msrp_t*)tsk_list_find_object_by_pred(self->sessions, __pred_find_session_by_type, &msrp_type);
- if (session && session->send_file){
- va_list ap;
- va_start(ap, path);
- session = tsk_object_ref(session);
- ret = session->send_file(TMEDIA_SESSION_MSRP(session), path, &ap);
- TSK_OBJECT_SAFE_FREE(session);
- va_end(ap);
- }
- else{
- TSK_DEBUG_ERROR("No MSRP session associated to this manager or session does not support file transfer");
- }
+ session = (tmedia_session_msrp_t*)tsk_list_find_object_by_pred(self->sessions, __pred_find_session_by_type, &msrp_type);
+ if (session && session->send_file) {
+ va_list ap;
+ va_start(ap, path);
+ session = tsk_object_ref(session);
+ ret = session->send_file(TMEDIA_SESSION_MSRP(session), path, &ap);
+ TSK_OBJECT_SAFE_FREE(session);
+ va_end(ap);
+ }
+ else {
+ TSK_DEBUG_ERROR("No MSRP session associated to this manager or session does not support file transfer");
+ }
- return ret;
+ return ret;
}
int tmedia_session_mgr_send_message(tmedia_session_mgr_t* self, const void* data, tsk_size_t size, const tmedia_params_L_t *params)
{
- tmedia_session_msrp_t* session;
- tmedia_type_t msrp_type = tmedia_msrp;
- int ret = -3;
+ tmedia_session_msrp_t* session;
+ tmedia_type_t msrp_type = tmedia_msrp;
+ int ret = -3;
- if (!self || !size || !data){
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
+ if (!self || !size || !data) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
- session = (tmedia_session_msrp_t*)tsk_list_find_object_by_pred(self->sessions, __pred_find_session_by_type, &msrp_type);
- if (session && session->send_message){
- session = tsk_object_ref(session);
- ret = session->send_message(TMEDIA_SESSION_MSRP(session), data, size, params);
- TSK_OBJECT_SAFE_FREE(session);
- }
- else{
- TSK_DEBUG_ERROR("No MSRP session associated to this manager or session does not support file transfer");
- }
+ session = (tmedia_session_msrp_t*)tsk_list_find_object_by_pred(self->sessions, __pred_find_session_by_type, &msrp_type);
+ if (session && session->send_message) {
+ session = tsk_object_ref(session);
+ ret = session->send_message(TMEDIA_SESSION_MSRP(session), data, size, params);
+ TSK_OBJECT_SAFE_FREE(session);
+ }
+ else {
+ TSK_DEBUG_ERROR("No MSRP session associated to this manager or session does not support file transfer");
+ }
- return ret;
+ return ret;
}
int tmedia_session_mgr_set_msrp_cb(tmedia_session_mgr_t* self, const void* callback_data, tmedia_session_msrp_cb_f func)
{
- tmedia_session_msrp_t* session;
- tmedia_type_t msrp_type = tmedia_msrp;
+ tmedia_session_msrp_t* session;
+ tmedia_type_t msrp_type = tmedia_msrp;
- if (!self){
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
- if ((session = (tmedia_session_msrp_t*)tsk_list_find_object_by_pred(self->sessions, __pred_find_session_by_type, &msrp_type))){
- session->callback.data = callback_data;
- session->callback.func = func;
- return 0;
- }
- else{
- TSK_DEBUG_ERROR("No MSRP session associated to this manager or session does not support file transfer");
- return -2;
- }
+ if ((session = (tmedia_session_msrp_t*)tsk_list_find_object_by_pred(self->sessions, __pred_find_session_by_type, &msrp_type))) {
+ session->callback.data = callback_data;
+ session->callback.func = func;
+ return 0;
+ }
+ else {
+ TSK_DEBUG_ERROR("No MSRP session associated to this manager or session does not support file transfer");
+ return -2;
+ }
}
int tmedia_session_mgr_set_onerror_cbfn(tmedia_session_mgr_t* self, const void* usrdata, tmedia_session_onerror_cb_f fun)
{
- tmedia_session_t* session;
- tsk_list_item_t *item;
+ tmedia_session_t* session;
+ tsk_list_item_t *item;
- if (!self){
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
// save for sessions created later
- self->onerror_cb.fun = fun;
- self->onerror_cb.usrdata = usrdata;
+ self->onerror_cb.fun = fun;
+ self->onerror_cb.usrdata = usrdata;
- tsk_list_lock(self->sessions);
- tsk_list_foreach(item, self->sessions){
- if (!(session = item->data)){
- continue;
- }
- tmedia_session_set_onerror_cbfn(session, usrdata, fun);
- }
- tsk_list_unlock(self->sessions);
+ tsk_list_lock(self->sessions);
+ tsk_list_foreach(item, self->sessions) {
+ if (!(session = item->data)) {
+ continue;
+ }
+ tmedia_session_set_onerror_cbfn(session, usrdata, fun);
+ }
+ tsk_list_unlock(self->sessions);
- return 0;
+ return 0;
}
int tmedia_session_mgr_set_rfc5168_cbfn(tmedia_session_mgr_t* self, const void* usrdata, tmedia_session_rfc5168_cb_f fun)
{
- tmedia_session_t* session;
- tsk_list_item_t *item;
+ tmedia_session_t* session;
+ tsk_list_item_t *item;
- if (!self){
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
// save for functions created later
- self->rfc5168_cb.fun = fun;
- self->rfc5168_cb.usrdata = usrdata;
+ self->rfc5168_cb.fun = fun;
+ self->rfc5168_cb.usrdata = usrdata;
- tsk_list_lock(self->sessions);
- tsk_list_foreach(item, self->sessions){
- if (!(session = item->data)){
- continue;
- }
- tmedia_session_set_rfc5168_cbfn(session, usrdata, fun);
- }
- tsk_list_unlock(self->sessions);
+ tsk_list_lock(self->sessions);
+ tsk_list_foreach(item, self->sessions) {
+ if (!(session = item->data)) {
+ continue;
+ }
+ tmedia_session_set_rfc5168_cbfn(session, usrdata, fun);
+ }
+ tsk_list_unlock(self->sessions);
- return 0;
+ return 0;
}
int tmedia_session_mgr_set_bfcp_cbfn(tmedia_session_mgr_t* self, const void* usrdata, tmedia_session_bfcp_cb_f fun)
{
- tmedia_session_t* session;
- tsk_list_item_t *item;
+ tmedia_session_t* session;
+ tsk_list_item_t *item;
- if (!self) {
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
- tsk_list_lock(self->sessions);
- tsk_list_foreach(item, self->sessions) {
- if (!(session = item->data)) {
- continue;
- }
- tmedia_session_set_bfcp_cbfn(session, usrdata, fun);
- }
- tsk_list_unlock(self->sessions);
+ tsk_list_lock(self->sessions);
+ tsk_list_foreach(item, self->sessions) {
+ if (!(session = item->data)) {
+ continue;
+ }
+ tmedia_session_set_bfcp_cbfn(session, usrdata, fun);
+ }
+ tsk_list_unlock(self->sessions);
- return 0;
+ return 0;
}
int tmedia_session_mgr_lo_apply_changes(tmedia_session_mgr_t* self)
{
- if (!self) {
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
- _tmedia_session_mgr_get_lo(self, kSkipSessionLoadTrue, kForceUpdateLOTrue);
- return 0;
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ _tmedia_session_mgr_get_lo(self, kSkipSessionLoadTrue, kForceUpdateLOTrue);
+ return 0;
}
static int _tmedia_session_mgr_recv_rtcp_event(tmedia_session_mgr_t* self, tmedia_type_t media_type, tmedia_rtcp_event_type_t event_type, uint32_t ssrc_media, uint64_t session_id)
{
- tmedia_session_t* session;
- tsk_list_item_t *item;
+ tmedia_session_t* session;
+ tsk_list_item_t *item;
- if (!self){
- TSK_DEBUG_ERROR("Invlid parameter");
- return -1;
- }
+ if (!self) {
+ TSK_DEBUG_ERROR("Invlid parameter");
+ return -1;
+ }
- tsk_list_lock(self->sessions);
- tsk_list_foreach(item, self->sessions) {
- if (!(session = item->data) || !((session->type & media_type) || (session->id == session_id))) {
- continue;
- }
- tmedia_session_recv_rtcp_event(session, event_type, ssrc_media);
- }
- tsk_list_unlock(self->sessions);
+ tsk_list_lock(self->sessions);
+ tsk_list_foreach(item, self->sessions) {
+ if (!(session = item->data) || !((session->type & media_type) || (session->id == session_id))) {
+ continue;
+ }
+ tmedia_session_recv_rtcp_event(session, event_type, ssrc_media);
+ }
+ tsk_list_unlock(self->sessions);
- return 0;
+ return 0;
}
/** internal function used to load sessions */
static int _tmedia_session_mgr_load_sessions(tmedia_session_mgr_t* self)
{
- tsk_size_t i = 0;
- tmedia_session_t* session;
- const tmedia_session_plugin_def_t* plugin;
+ tsk_size_t i = 0;
+ tmedia_session_t* session;
+ const tmedia_session_plugin_def_t* plugin;
- tsk_list_lock(self->sessions);
+ tsk_list_lock(self->sessions);
#define has_media(media_type) (tsk_list_find_object_by_pred(self->sessions, __pred_find_session_by_type, &(media_type)))
- if (TSK_LIST_IS_EMPTY(self->sessions) || self->mediaType_changed) {
- //static tmedia_type_t __ghost_media_type = tmedia_ghost;
- //static tmedia_type_t __none_media_type = tmedia_none;
- // Remove ghost sessions. Up to the
- //while (tsk_list_remove_item_by_pred(self->sessions, __pred_find_session_by_type, &__ghost_media_type)) ;
- //while (tsk_list_remove_item_by_pred(self->sessions, __pred_find_session_by_type, &__none_media_type)) ;
- /* for each registered plugin create a session instance */
- while ((i < TMED_SESSION_MAX_PLUGINS) && (plugin = __tmedia_session_plugins[i++])) {
- if ((plugin->type & self->type) == plugin->type) { /* media_type *IS* enabled */
- if (has_media(plugin->type)) {
- // we already have a matching media session -> enable it if not already done
- _tmedia_session_mgr_enable_session_with_type(self, plugin->type);
- }
- else {
- // we don't have a matching media session yet
- if ((session = tmedia_session_create(plugin->type))) {
- /* do not call "tmedia_session_mgr_set()" here to avoid applying parms before the creation of all session */
-
- /* set other default values */
-
- /* push session */
- tsk_list_push_back_data(self->sessions, (void**)(&session));
- }
- }
- }
- else { /* media_type *IS NOT* enabled */
- if (has_media(plugin->type)) {
- // do not remove to make sure media indexes match -> see rfc 3264 section 8
- // tsk_list_remove_item_by_pred(self->sessions, __pred_find_session_by_type, &(plugin->type));
- _tmedia_session_mgr_disable_session_with_type(self, plugin->type);
- }
- }
- }
- /* set default values and apply params*/
- tmedia_session_mgr_set(self,
- TMEDIA_SESSION_SET_POBJECT(tmedia_audio, "ice-ctx", self->ice.ctx_audio),
- TMEDIA_SESSION_SET_POBJECT(tmedia_video, "ice-ctx", self->ice.ctx_video),
- TMEDIA_SESSION_SET_POBJECT(tmedia_bfcp_video, "ice-ctx", self->ice.ctx_bfcpvid),
-
- TMEDIA_SESSION_SET_STR(self->type, "local-ip", self->addr),
- TMEDIA_SESSION_SET_STR(self->type, "local-ipver", self->ipv6 ? "ipv6" : "ipv4"),
- TMEDIA_SESSION_SET_INT32(self->type, "bandwidth-level", self->bl),
- TMEDIA_SESSION_SET_NULL());
+ if (TSK_LIST_IS_EMPTY(self->sessions) || self->mediaType_changed) {
+ //static tmedia_type_t __ghost_media_type = tmedia_ghost;
+ //static tmedia_type_t __none_media_type = tmedia_none;
+ // Remove ghost sessions. Up to the
+ //while (tsk_list_remove_item_by_pred(self->sessions, __pred_find_session_by_type, &__ghost_media_type)) ;
+ //while (tsk_list_remove_item_by_pred(self->sessions, __pred_find_session_by_type, &__none_media_type)) ;
+ /* for each registered plugin create a session instance */
+ while ((i < TMED_SESSION_MAX_PLUGINS) && (plugin = __tmedia_session_plugins[i++])) {
+ if ((plugin->type & self->type) == plugin->type) { /* media_type *IS* enabled */
+ if (has_media(plugin->type)) {
+ // we already have a matching media session -> enable it if not already done
+ _tmedia_session_mgr_enable_session_with_type(self, plugin->type);
+ }
+ else {
+ // we don't have a matching media session yet
+ if ((session = tmedia_session_create(plugin->type))) {
+ /* do not call "tmedia_session_mgr_set()" here to avoid applying parms before the creation of all session */
+
+ /* set other default values */
+
+ /* push session */
+ tsk_list_push_back_data(self->sessions, (void**)(&session));
+ }
+ }
+ }
+ else { /* media_type *IS NOT* enabled */
+ if (has_media(plugin->type)) {
+ // do not remove to make sure media indexes match -> see rfc 3264 section 8
+ // tsk_list_remove_item_by_pred(self->sessions, __pred_find_session_by_type, &(plugin->type));
+ _tmedia_session_mgr_disable_session_with_type(self, plugin->type);
+ }
+ }
+ }
+ /* set default values and apply params*/
+ tmedia_session_mgr_set(self,
+ TMEDIA_SESSION_SET_POBJECT(tmedia_audio, "ice-ctx", self->ice.ctx_audio),
+ TMEDIA_SESSION_SET_POBJECT(tmedia_video, "ice-ctx", self->ice.ctx_video),
+ TMEDIA_SESSION_SET_POBJECT(tmedia_bfcp_video, "ice-ctx", self->ice.ctx_bfcpvid),
+
+ TMEDIA_SESSION_SET_STR(self->type, "local-ip", self->addr),
+ TMEDIA_SESSION_SET_STR(self->type, "local-ipver", self->ipv6 ? "ipv6" : "ipv4"),
+ TMEDIA_SESSION_SET_INT32(self->type, "bandwidth-level", self->bl),
+ TMEDIA_SESSION_SET_NULL());
// set callback functions
tmedia_session_mgr_set_onerror_cbfn(self, self->onerror_cb.usrdata, self->onerror_cb.fun);
tmedia_session_mgr_set_rfc5168_cbfn(self, self->rfc5168_cb.usrdata, self->rfc5168_cb.fun);
- }
+ }
#undef has_media
- tsk_list_unlock(self->sessions);
- return 0;
+ tsk_list_unlock(self->sessions);
+ return 0;
}
//!\ not thread-safe
static const tmedia_session_t* _tmedia_session_mgr_find_session_at_index(const tmedia_sessions_L_t* list, tsk_size_t index)
{
- const tsk_list_item_t *item;
- tsk_size_t u = 0;
- tsk_list_foreach(item, list) {
- if (u++ == index) {
- return (const tmedia_session_t*)item->data;
- }
- }
- return tsk_null;
+ const tsk_list_item_t *item;
+ tsk_size_t u = 0;
+ tsk_list_foreach(item, list) {
+ if (u++ == index) {
+ return (const tmedia_session_t*)item->data;
+ }
+ }
+ return tsk_null;
}
/* internal function */
static int _tmedia_session_mgr_disable_or_enable_session_with_type(tmedia_session_mgr_t* self, tmedia_type_t media_type, tsk_bool_t enable)
{
- tsk_list_item_t *item;
- tmedia_session_t *session;
- tsk_list_lock(self->sessions);
-
- tsk_list_foreach(item, self->sessions) {
- if ((session = (tmedia_session_t*)item->data) && session->plugin && session->plugin->type == media_type) {
- if (enable) {
- if (session->M.lo && !session->M.lo->port) {
- TSK_OBJECT_SAFE_FREE(session->M.ro);
- TSK_OBJECT_SAFE_FREE(session->M.lo);
- session->prepared = tsk_false;
- }
- }
- else {
- if (session->plugin->stop) {
- session->plugin->stop(session);
- }
- if (session->M.lo) {
- session->M.lo->port = 0;
- }
- session->prepared = tsk_false;
- }
- }
- }
-
- tsk_list_unlock(self->sessions);
- return 0;
+ tsk_list_item_t *item;
+ tmedia_session_t *session;
+ tsk_list_lock(self->sessions);
+
+ tsk_list_foreach(item, self->sessions) {
+ if ((session = (tmedia_session_t*)item->data) && session->plugin && session->plugin->type == media_type) {
+ if (enable) {
+ if (session->M.lo && !session->M.lo->port) {
+ TSK_OBJECT_SAFE_FREE(session->M.ro);
+ TSK_OBJECT_SAFE_FREE(session->M.lo);
+ session->prepared = tsk_false;
+ }
+ }
+ else {
+ if (session->plugin->stop) {
+ session->plugin->stop(session);
+ }
+ if (session->M.lo) {
+ session->M.lo->port = 0;
+ }
+ session->prepared = tsk_false;
+ }
+ }
+ }
+
+ tsk_list_unlock(self->sessions);
+ return 0;
}
/* internal function */
static int _tmedia_session_mgr_clear_sessions(tmedia_session_mgr_t* self)
{
- if (self && self->sessions){
- tsk_list_clear_items(self->sessions);
- }
- return 0;
+ if (self && self->sessions) {
+ tsk_list_clear_items(self->sessions);
+ }
+ return 0;
}
/* internal function */
// force_update_lo: means use same sdp version number but update fields
static const tsdp_message_t* _tmedia_session_mgr_get_lo(tmedia_session_mgr_t* self, tsk_bool_t skip_session_load, tsk_bool_t force_update_lo)
{
- const tsk_list_item_t* item;
- const tmedia_session_t* ms;
- const tsdp_header_M_t* m;
- const tsdp_message_t* ret = tsk_null;
- uint32_t new_ver_num;
- tsk_bool_t inc_ver = tsk_false;
-
- if (!self){
- TSK_DEBUG_ERROR("Invalid parameter");
- return tsk_null;
- }
-
- tsk_safeobj_lock(self);
-
- /* prepare the session manager if not already done (create all sessions) */
- if (TSK_LIST_IS_EMPTY(self->sessions)){
- if (_tmedia_session_mgr_load_sessions(self)){
- TSK_DEBUG_ERROR("Failed to prepare the session manager");
- goto bail;
- }
- }
-
- /* creates local sdp if not already done or update it's value (because of set_ro())*/
- if ((self->ro_changed || self->state_changed || self->mediaType_changed) && self->sdp.lo) {
- // delete current lo
- TSK_OBJECT_SAFE_FREE(self->sdp.lo);
- if (self->mediaType_changed && !skip_session_load) {
- // reload session with new medias and keep the old one
- _tmedia_session_mgr_load_sessions(self);
- }
- self->ro_changed = tsk_false;
- self->ro_provisional = tsk_false;
- self->state_changed = tsk_false;
- self->mediaType_changed = tsk_false;
- }
- if (force_update_lo && self->sdp.lo) {
- const tsdp_header_O_t* O;
-
- if ((O = (const tsdp_header_O_t*)tsdp_message_get_header(self->sdp.lo, tsdp_htype_O))) {
- tsk_list_item_t *item;
- tmedia_session_t *session;
-
- new_ver_num = O->sess_version;
- tsk_list_lock(self->sessions);
- tsk_list_foreach(item, self->sessions) {
- if ((session = (tmedia_session_t*)item->data)) {
- TSK_OBJECT_SAFE_FREE(session->M.lo);
- }
- }
- tsk_list_unlock(self->sessions);
- TSK_OBJECT_SAFE_FREE(self->sdp.lo);
- }
- else {
- new_ver_num = (self->sdp.lo_ver + 1);
- inc_ver = tsk_true;
- }
- }
- else {
- new_ver_num = (self->sdp.lo_ver + 1);
- inc_ver = tsk_true;
- }
-
- if (self->sdp.lo) {
- ret = self->sdp.lo;
- goto bail;
- }
- else {
- if ((self->sdp.lo = tsdp_message_create_empty(self->public_addr ? self->public_addr : self->addr, self->ipv6, new_ver_num))) {
- /* Set connection "c=" */
- tsdp_message_add_headers(self->sdp.lo,
- TSDP_HEADER_C_VA_ARGS("IN", self->ipv6 ? "IP6" : "IP4", self->public_addr ? self->public_addr : self->addr),
- tsk_null);
- if (inc_ver) {
- ++self->sdp.lo_ver;
- }
- }
- else {
- TSK_DEBUG_ERROR("Failed to create empty SDP message");
- goto bail;
- }
- }
-
- /* pass complete local sdp to the sessions to allow them to use session-level attributes */
- tmedia_session_mgr_set(self,
- TMEDIA_SESSION_SET_POBJECT(self->type, "local-sdp-message", self->sdp.lo),
- TMEDIA_SESSION_SET_NULL());
-
- /* gets each "m=" line from the sessions and add them to the local sdp */
- tsk_list_foreach(item, self->sessions){
- if (!(ms = item->data) || !ms->plugin){
- TSK_DEBUG_ERROR("Invalid session");
- continue;
- }
- if ((self->type & ms->plugin->type) || ms->plugin->type == tmedia_ghost) {
- /* prepare the media session */
- if (!ms->prepared && (_tmedia_session_prepare(TMEDIA_SESSION(ms)))){
- TSK_DEBUG_ERROR("Failed to prepare session"); /* should never happen */
- continue;
- }
-
- /* Add QoS lines to our local media */
- if ((self->qos.type != tmedia_qos_stype_none) && !TMEDIA_SESSION(ms)->qos){
- TMEDIA_SESSION(ms)->qos = tmedia_qos_tline_create(self->qos.type, self->qos.strength);
- }
-
- /* add "m=" line from the session to the local sdp */
- if ((m = tmedia_session_get_lo(TMEDIA_SESSION(ms)))) {
- tsdp_message_add_header(self->sdp.lo, TSDP_HEADER(m));
- }
- else {
- TSK_DEBUG_ERROR("Failed to get m= line for [%s] media", ms->plugin->media);
- }
- }
- else if (ms->M.lo) {
- // media not enabled -> add sdp with port zero
- tsdp_message_add_header(self->sdp.lo, TSDP_HEADER(ms->M.lo));
- }
- }
-
- self->type = self->sdp.lo ? tmedia_type_from_sdp(self->sdp.lo) : tmedia_none;
- ret = self->sdp.lo;
+ const tsk_list_item_t* item;
+ const tmedia_session_t* ms;
+ const tsdp_header_M_t* m;
+ const tsdp_message_t* ret = tsk_null;
+ uint32_t new_ver_num;
+ tsk_bool_t inc_ver = tsk_false;
+
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
+
+ tsk_safeobj_lock(self);
+
+ /* prepare the session manager if not already done (create all sessions) */
+ if (TSK_LIST_IS_EMPTY(self->sessions)) {
+ if (_tmedia_session_mgr_load_sessions(self)) {
+ TSK_DEBUG_ERROR("Failed to prepare the session manager");
+ goto bail;
+ }
+ }
+
+ /* creates local sdp if not already done or update it's value (because of set_ro())*/
+ if ((self->ro_changed || self->state_changed || self->mediaType_changed) && self->sdp.lo) {
+ // delete current lo
+ TSK_OBJECT_SAFE_FREE(self->sdp.lo);
+ if (self->mediaType_changed && !skip_session_load) {
+ // reload session with new medias and keep the old one
+ _tmedia_session_mgr_load_sessions(self);
+ }
+ self->ro_changed = tsk_false;
+ self->ro_provisional = tsk_false;
+ self->state_changed = tsk_false;
+ self->mediaType_changed = tsk_false;
+ }
+ if (force_update_lo && self->sdp.lo) {
+ const tsdp_header_O_t* O;
+
+ if ((O = (const tsdp_header_O_t*)tsdp_message_get_header(self->sdp.lo, tsdp_htype_O))) {
+ tsk_list_item_t *item;
+ tmedia_session_t *session;
+
+ new_ver_num = O->sess_version;
+ tsk_list_lock(self->sessions);
+ tsk_list_foreach(item, self->sessions) {
+ if ((session = (tmedia_session_t*)item->data)) {
+ TSK_OBJECT_SAFE_FREE(session->M.lo);
+ }
+ }
+ tsk_list_unlock(self->sessions);
+ TSK_OBJECT_SAFE_FREE(self->sdp.lo);
+ }
+ else {
+ new_ver_num = (self->sdp.lo_ver + 1);
+ inc_ver = tsk_true;
+ }
+ }
+ else {
+ new_ver_num = (self->sdp.lo_ver + 1);
+ inc_ver = tsk_true;
+ }
+
+ if (self->sdp.lo) {
+ ret = self->sdp.lo;
+ goto bail;
+ }
+ else {
+ if ((self->sdp.lo = tsdp_message_create_empty(self->public_addr ? self->public_addr : self->addr, self->ipv6, new_ver_num))) {
+ /* Set connection "c=" */
+ tsdp_message_add_headers(self->sdp.lo,
+ TSDP_HEADER_C_VA_ARGS("IN", self->ipv6 ? "IP6" : "IP4", self->public_addr ? self->public_addr : self->addr),
+ tsk_null);
+ if (inc_ver) {
+ ++self->sdp.lo_ver;
+ }
+ }
+ else {
+ TSK_DEBUG_ERROR("Failed to create empty SDP message");
+ goto bail;
+ }
+ }
+
+ /* pass complete local sdp to the sessions to allow them to use session-level attributes */
+ tmedia_session_mgr_set(self,
+ TMEDIA_SESSION_SET_POBJECT(self->type, "local-sdp-message", self->sdp.lo),
+ TMEDIA_SESSION_SET_NULL());
+
+ /* gets each "m=" line from the sessions and add them to the local sdp */
+ tsk_list_foreach(item, self->sessions) {
+ if (!(ms = item->data) || !ms->plugin) {
+ TSK_DEBUG_ERROR("Invalid session");
+ continue;
+ }
+ if ((self->type & ms->plugin->type) || ms->plugin->type == tmedia_ghost) {
+ /* prepare the media session */
+ if (!ms->prepared && (_tmedia_session_prepare(TMEDIA_SESSION(ms)))) {
+ TSK_DEBUG_ERROR("Failed to prepare session"); /* should never happen */
+ continue;
+ }
+
+ /* Add QoS lines to our local media */
+ if ((self->qos.type != tmedia_qos_stype_none) && !TMEDIA_SESSION(ms)->qos) {
+ TMEDIA_SESSION(ms)->qos = tmedia_qos_tline_create(self->qos.type, self->qos.strength);
+ }
+
+ /* add "m=" line from the session to the local sdp */
+ if ((m = tmedia_session_get_lo(TMEDIA_SESSION(ms)))) {
+ tsdp_message_add_header(self->sdp.lo, TSDP_HEADER(m));
+ }
+ else {
+ TSK_DEBUG_ERROR("Failed to get m= line for [%s] media", ms->plugin->media);
+ }
+ }
+ else if (ms->M.lo) {
+ // media not enabled -> add sdp with port zero
+ tsdp_message_add_header(self->sdp.lo, TSDP_HEADER(ms->M.lo));
+ }
+ }
+
+ self->type = self->sdp.lo ? tmedia_type_from_sdp(self->sdp.lo) : tmedia_none;
+ ret = self->sdp.lo;
bail:
- tsk_safeobj_unlock(self);
+ tsk_safeobj_unlock(self);
- return ret;
+ return ret;
}
static int _tmedia_session_mgr_start(tmedia_session_mgr_t* self, int session_index)
{
- int ret = 0, index = 0;
- tsk_list_item_t* item;
- tmedia_session_t* session;
-
- if (!self) {
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
-
- tsk_safeobj_lock(self);
-
- tsk_list_foreach(item, self->sessions) {
- if (session_index == kSessionIndexAll || index++ == session_index) {
- if (!(session = item->data) || !session->plugin || !session->plugin->start) {
- TSK_DEBUG_ERROR("Invalid session");
- ret = -2;
- goto bail;
- }
- if (!session->M.lo || !session->M.lo->port) {
- continue;
- }
- if ((ret = session->plugin->start(session))) {
- TSK_DEBUG_ERROR("Failed to start %s session", session->plugin->media);
- continue;
- }
- }
- }
- if (session_index == kSessionIndexAll) {
- self->started = tsk_true;
- }
+ int ret = 0, index = 0;
+ tsk_list_item_t* item;
+ tmedia_session_t* session;
+
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ tsk_safeobj_lock(self);
+
+ tsk_list_foreach(item, self->sessions) {
+ if (session_index == kSessionIndexAll || index++ == session_index) {
+ if (!(session = item->data) || !session->plugin || !session->plugin->start) {
+ TSK_DEBUG_ERROR("Invalid session");
+ ret = -2;
+ goto bail;
+ }
+ if (!session->M.lo || !session->M.lo->port) {
+ continue;
+ }
+ if ((ret = session->plugin->start(session))) {
+ TSK_DEBUG_ERROR("Failed to start %s session", session->plugin->media);
+ continue;
+ }
+ }
+ }
+ if (session_index == kSessionIndexAll) {
+ self->started = tsk_true;
+ }
bail:
- tsk_safeobj_unlock(self);
- return ret;
+ tsk_safeobj_unlock(self);
+ return ret;
}
static int _tmedia_session_mgr_stop(tmedia_session_mgr_t* self, int session_index)
{
- int ret = 0, index = 0;
- tsk_list_item_t* item;
- tmedia_session_t* session;
-
- TSK_DEBUG_INFO("tmedia_session_mgr_stop()");
-
- if (!self) {
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
- tsk_safeobj_lock(self);
-
- tsk_list_foreach(item, self->sessions) {
- if (session_index == kSessionIndexAll || index++ == session_index) {
- if (!(session = item->data) || !session->plugin || !session->plugin->stop) {
- TSK_DEBUG_ERROR("Invalid session");
- ret = -2;
- goto bail;
- }
- if ((ret = session->plugin->stop(session))) {
- TSK_DEBUG_ERROR("Failed to stop session");
- continue;
- }
- session->prepared = tsk_false;
- }
- }
- if (session_index == kSessionIndexAll) {
- self->started = tsk_false;
- }
+ int ret = 0, index = 0;
+ tsk_list_item_t* item;
+ tmedia_session_t* session;
+
+ TSK_DEBUG_INFO("tmedia_session_mgr_stop()");
+
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+ tsk_safeobj_lock(self);
+
+ tsk_list_foreach(item, self->sessions) {
+ if (session_index == kSessionIndexAll || index++ == session_index) {
+ if (!(session = item->data) || !session->plugin || !session->plugin->stop) {
+ TSK_DEBUG_ERROR("Invalid session");
+ ret = -2;
+ goto bail;
+ }
+ if ((ret = session->plugin->stop(session))) {
+ TSK_DEBUG_ERROR("Failed to stop session");
+ continue;
+ }
+ session->prepared = tsk_false;
+ }
+ }
+ if (session_index == kSessionIndexAll) {
+ self->started = tsk_false;
+ }
bail:
- tsk_safeobj_unlock(self);
- return ret;
+ tsk_safeobj_unlock(self);
+ return ret;
}
/* internal function */
static int _tmedia_session_mgr_apply_params(tmedia_session_mgr_t* self)
{
- tsk_list_item_t *it1, *it2;
- tmedia_param_t* param;
- tmedia_session_t* session;
+ tsk_list_item_t *it1, *it2;
+ tmedia_param_t* param;
+ tmedia_session_t* session;
- if (!self){
- TSK_DEBUG_ERROR("Invalid parameter");
- return -1;
- }
+ if (!self) {
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
- /* If no parameters ==> do nothing (not error) */
- if (TSK_LIST_IS_EMPTY(self->params)){
- return 0;
- }
+ /* If no parameters ==> do nothing (not error) */
+ if (TSK_LIST_IS_EMPTY(self->params)) {
+ return 0;
+ }
- tsk_list_lock(self->params);
+ tsk_list_lock(self->params);
- tsk_list_foreach(it1, self->params){
- if (!(param = it1->data)){
- continue;
- }
+ tsk_list_foreach(it1, self->params) {
+ if (!(param = it1->data)) {
+ continue;
+ }
- /* For us */
- if (param->plugin_type == tmedia_ppt_manager){
- continue;
- }
+ /* For us */
+ if (param->plugin_type == tmedia_ppt_manager) {
+ continue;
+ }
- /* For the session (or consumer or producer or codec) */
- tsk_list_foreach(it2, self->sessions){
- if (!(session = it2->data) || !session->plugin){
- continue;
- }
- if (session->plugin->set && (session->type & param->media_type) == session->type){
- session->plugin->set(session, param);
- }
- }
- }
+ /* For the session (or consumer or producer or codec) */
+ tsk_list_foreach(it2, self->sessions) {
+ if (!(session = it2->data) || !session->plugin) {
+ continue;
+ }
+ if (session->plugin->set && (session->type & param->media_type) == session->type) {
+ session->plugin->set(session, param);
+ }
+ }
+ }
- /* Clean up params */
- tsk_list_clear_items(self->params);
+ /* Clean up params */
+ tsk_list_clear_items(self->params);
- tsk_list_unlock(self->params);
+ tsk_list_unlock(self->params);
- return 0;
+ return 0;
}
//=================================================================================================
@@ -2471,54 +2539,53 @@ static int _tmedia_session_mgr_apply_params(tmedia_session_mgr_t* self)
//
static tsk_object_t* tmedia_session_mgr_ctor(tsk_object_t * self, va_list * app)
{
- tmedia_session_mgr_t *mgr = self;
- if (mgr){
- mgr->sessions = tsk_list_create();
+ tmedia_session_mgr_t *mgr = self;
+ if (mgr) {
+ mgr->sessions = tsk_list_create();
- mgr->sdp.lo_ver = TSDP_HEADER_O_SESS_VERSION_DEFAULT;
- mgr->sdp.ro_ver = -1;
+ mgr->sdp.lo_ver = TSDP_HEADER_O_SESS_VERSION_DEFAULT;
+ mgr->sdp.ro_ver = -1;
- mgr->qos.type = tmedia_qos_stype_none;
- mgr->qos.strength = tmedia_qos_strength_optional;
- mgr->bl = tmedia_defaults_get_bl();
+ mgr->qos.type = tmedia_qos_stype_none;
+ mgr->qos.strength = tmedia_qos_strength_optional;
+ mgr->bl = tmedia_defaults_get_bl();
- tsk_safeobj_init(mgr);
- }
- return self;
+ tsk_safeobj_init(mgr);
+ }
+ return self;
}
static tsk_object_t* tmedia_session_mgr_dtor(tsk_object_t * self)
{
- tmedia_session_mgr_t *mgr = self;
- if (mgr){
- TSK_OBJECT_SAFE_FREE(mgr->sessions);
+ tmedia_session_mgr_t *mgr = self;
+ if (mgr) {
+ TSK_OBJECT_SAFE_FREE(mgr->sessions);
- TSK_OBJECT_SAFE_FREE(mgr->sdp.lo);
- TSK_OBJECT_SAFE_FREE(mgr->sdp.ro);
+ TSK_OBJECT_SAFE_FREE(mgr->sdp.lo);
+ TSK_OBJECT_SAFE_FREE(mgr->sdp.ro);
- TSK_OBJECT_SAFE_FREE(mgr->params);
+ TSK_OBJECT_SAFE_FREE(mgr->params);
- TSK_OBJECT_SAFE_FREE(mgr->natt_ctx);
- TSK_FREE(mgr->public_addr);
+ TSK_OBJECT_SAFE_FREE(mgr->natt_ctx);
+ TSK_FREE(mgr->public_addr);
- TSK_OBJECT_SAFE_FREE(mgr->ice.ctx_audio);
- TSK_OBJECT_SAFE_FREE(mgr->ice.ctx_video);
- TSK_OBJECT_SAFE_FREE(mgr->ice.ctx_bfcpvid);
+ TSK_OBJECT_SAFE_FREE(mgr->ice.ctx_audio);
+ TSK_OBJECT_SAFE_FREE(mgr->ice.ctx_video);
+ TSK_OBJECT_SAFE_FREE(mgr->ice.ctx_bfcpvid);
- TSK_FREE(mgr->addr);
+ TSK_FREE(mgr->addr);
- tsk_safeobj_deinit(mgr);
- }
+ tsk_safeobj_deinit(mgr);
+ }
- return self;
+ return self;
}
-static const tsk_object_def_t tmedia_session_mgr_def_s =
-{
- sizeof(tmedia_session_mgr_t),
- tmedia_session_mgr_ctor,
- tmedia_session_mgr_dtor,
- tsk_null,
+static const tsk_object_def_t tmedia_session_mgr_def_s = {
+ sizeof(tmedia_session_mgr_t),
+ tmedia_session_mgr_ctor,
+ tmedia_session_mgr_dtor,
+ tsk_null,
};
const tsk_object_def_t *tmedia_session_mgr_def_t = &tmedia_session_mgr_def_s;
OpenPOWER on IntegriCloud