summaryrefslogtreecommitdiffstats
path: root/tinyMEDIA/src/tmedia_qos.c
diff options
context:
space:
mode:
Diffstat (limited to 'tinyMEDIA/src/tmedia_qos.c')
-rw-r--r--tinyMEDIA/src/tmedia_qos.c861
1 files changed, 861 insertions, 0 deletions
diff --git a/tinyMEDIA/src/tmedia_qos.c b/tinyMEDIA/src/tmedia_qos.c
new file mode 100644
index 0000000..e2cac97
--- /dev/null
+++ b/tinyMEDIA/src/tmedia_qos.c
@@ -0,0 +1,861 @@
+/*
+* Copyright (C) 2009-2010 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+
+/**@file tmedia_qos.c
+ * @brief RFC 3312 (Preconditions) implementation.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tinymedia/tmedia_qos.h"
+
+#include "tsk_memory.h"
+#include "tsk_debug.h"
+
+/* ========================= Internal ==================================*/
+
+static const char* tmedia_qos_strength_tostring(tmedia_qos_strength_t strength)
+{
+ switch(strength){
+ case tmedia_qos_strength_none:
+ return "none";
+ case tmedia_qos_strength_mandatory:
+ return "mandatory";
+ case tmedia_qos_strength_optional:
+ return "optional";
+ case tmedia_qos_strength_failure:
+ return "failure";
+ case tmedia_qos_strength_unknown:
+ default:
+ return "unknown";
+ }
+}
+
+static tmedia_qos_strength_t tmedia_qos_strength_fromstring(const char* strength)
+{
+ if(tsk_strequals(strength, "none")){
+ return tmedia_qos_strength_none;
+ }
+ else if(tsk_strequals(strength, "mandatory")){
+ return tmedia_qos_strength_mandatory;
+ }
+ else if(tsk_strequals(strength, "optional")){
+ return tmedia_qos_strength_optional;
+ }
+ else if(tsk_strequals(strength, "failure")){
+ return tmedia_qos_strength_failure;
+ }
+ else{
+ return tmedia_qos_strength_unknown;
+ }
+}
+
+static tmedia_qos_direction_t tmedia_qos_direction_fromstring(const char* direction)
+{
+ if(tsk_strequals(direction, "send")){
+ return tmedia_qos_direction_send;
+ }
+ else if(tsk_strequals(direction, "recv")){
+ return tmedia_qos_direction_recv;
+ }
+ else if(tsk_strequals(direction, "sendrecv")){
+ return tmedia_qos_direction_sendrecv;
+ }
+ else{
+ return tmedia_qos_direction_none;
+ }
+}
+
+/* ========================= Common ==================================*/
+
+tmedia_qos_tline_t* tmedia_qos_tline_create(tmedia_qos_stype_t type, tmedia_qos_strength_t strength)
+{
+ switch(type){
+ case tmedia_qos_stype_e2e:
+ return (tmedia_qos_tline_t*)tmedia_qos_tline_e2e_create(strength);
+ case tmedia_qos_stype_segmented:
+ return (tmedia_qos_tline_t*)tmedia_qos_tline_segmented_create(strength);
+ }
+ return tsk_null;
+}
+
+tmedia_qos_stype_t tmedia_qos_get_type(const tsdp_header_M_t* m)
+{
+ const tsdp_header_A_t* A;
+ char s0[10];
+
+ if(!m){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tmedia_qos_stype_none;
+ }
+
+ if((A = tsdp_header_M_findA(m, "curr"))){
+ if(sscanf(A->value, "qos %s %*s", s0) != EOF){
+ return tsk_strequals(s0, "e2e") ? tmedia_qos_stype_e2e : tmedia_qos_stype_segmented;
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to parse a=%s:%s", A->field, A->value);
+ }
+ }
+
+ return tmedia_qos_stype_none;
+}
+
+tmedia_qos_tline_t* tmedia_qos_tline_from_sdp(const tsdp_header_M_t* m)
+{
+ if(!m){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_null;
+ }
+
+ switch(tmedia_qos_get_type(m)){
+ case tmedia_qos_stype_e2e:
+ return (tmedia_qos_tline_t*)tmedia_qos_tline_e2e_from_sdp(m);
+ case tmedia_qos_stype_segmented:
+ return (tmedia_qos_tline_t*)tmedia_qos_tline_segmented_from_sdp(m);
+ default:
+ return tsk_null;
+ }
+}
+
+int tmedia_qos_tline_to_sdp(const tmedia_qos_tline_t* self, tsdp_header_M_t* m)
+{
+ if(!self || !m){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ switch(self->type){
+ case tmedia_qos_stype_e2e:
+ return tmedia_qos_tline_e2e_to_sdp((tmedia_qos_tline_e2e_t*)self, m);
+ case tmedia_qos_stype_segmented:
+ return tmedia_qos_tline_segmented_to_sdp((tmedia_qos_tline_segmented_t*)self, m);
+ default:
+ TSK_DEBUG_ERROR("Invalid type");
+ return -2;
+ }
+}
+
+int tmedia_qos_tline_set_ro(tmedia_qos_tline_t* self, const tmedia_qos_tline_t* ro)
+{
+ if(!self || !ro){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ switch(self->type){
+ case tmedia_qos_stype_e2e:
+ return tmedia_qos_tline_e2e_set_ro((tmedia_qos_tline_e2e_t*)self, (const tmedia_qos_tline_e2e_t*)ro);
+ case tmedia_qos_stype_segmented:
+ return tmedia_qos_tline_segmented_set_ro((tmedia_qos_tline_segmented_t*)self, (const tmedia_qos_tline_segmented_t*)ro);
+ default:
+ TSK_DEBUG_ERROR("Invalid type");
+ return -2;
+ }
+}
+
+tsk_bool_t tmedia_qos_tline_canresume(const tmedia_qos_tline_t* self)
+{
+ if(!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_true;
+ }
+ switch(self->type){
+ case tmedia_qos_stype_segmented:
+ return tmedia_qos_tline_segmented_canresume((const tmedia_qos_tline_segmented_t*)self);
+ case tmedia_qos_stype_e2e:
+ return tmedia_qos_tline_e2e_canresume((const tmedia_qos_tline_e2e_t*)self);
+ default:
+ return tsk_true;
+ }
+}
+
+/* ========================= E2E ==================================*/
+
+tmedia_qos_tline_e2e_t* tmedia_qos_tline_e2e_create(tmedia_qos_strength_t strength)
+{
+ return tsk_object_new(tmedia_qos_tline_e2e_def_t, strength);
+}
+
+tmedia_qos_tline_e2e_t* tmedia_qos_tline_e2e_from_sdp(const tsdp_header_M_t* m)
+{
+ tmedia_qos_tline_e2e_t* e2e = tsk_null;
+ const tsdp_header_A_t* A;
+ tsk_size_t i;
+
+ char s0[10], s1[10];
+
+ if(!m){
+ TSK_DEBUG_ERROR("invalid parameter");
+ return tsk_null;
+ }
+
+ /* Example
+ a=curr:qos e2e none
+ a=des:qos mandatory e2e sendrecv
+ a=conf:qos e2e recv
+ */
+
+ e2e = tmedia_qos_tline_e2e_create(tmedia_qos_strength_unknown);
+
+ /* curr */
+ for(i = 0; (A = tsdp_header_M_findA_at(m, "curr", i)); i++){
+ if(sscanf(A->value, "qos e2e %10s", s0) != EOF){
+ tmedia_qos_direction_t dir = tmedia_qos_direction_fromstring(s0);
+ switch(dir){
+ case tmedia_qos_direction_send:
+ e2e->send.current = tsk_true;
+ break;
+ case tmedia_qos_direction_recv:
+ e2e->recv.current = tsk_true;
+ break;
+ case tmedia_qos_direction_sendrecv:
+ e2e->send.current = tsk_true;
+ e2e->recv.current = tsk_true;
+ break;
+ case tmedia_qos_direction_none:
+ e2e->send.current = tsk_false;
+ e2e->recv.current = tsk_false;
+ break;
+ default:
+ break;
+ }
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to parse a=%s:%s", A->field, A->value);
+ }
+ }
+
+ /* des */
+ for(i = 0; (A = tsdp_header_M_findA_at(m, "des", i)); i++){
+ if(sscanf(A->value, "qos %10s e2e %10s", s0, s1) != EOF){
+ tmedia_qos_strength_t strength = tmedia_qos_strength_fromstring(s0);
+ tmedia_qos_direction_t dir = tmedia_qos_direction_fromstring(s1);
+ switch(dir){
+ case tmedia_qos_direction_send:
+ e2e->send.strength = strength;
+ break;
+ case tmedia_qos_direction_recv:
+ e2e->recv.strength = strength;
+ break;
+ case tmedia_qos_direction_sendrecv:
+ e2e->send.strength = strength;
+ e2e->recv.strength = strength;
+ break;
+ default:
+ break;
+ }
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to parse a=%s:%s", A->field, A->value);
+ }
+ }
+
+ /* conf */
+ for(i = 0; (A = tsdp_header_M_findA_at(m, "conf", i)); i++){
+ if(sscanf(A->value, "qos e2e %10s", s0) != EOF){
+ tmedia_qos_direction_t dir = tmedia_qos_direction_fromstring(s0);
+ switch(dir){
+ case tmedia_qos_direction_send:
+ e2e->send.confirm = tsk_true;
+ break;
+ case tmedia_qos_direction_recv:
+ e2e->recv.confirm = tsk_true;
+ break;
+ case tmedia_qos_direction_sendrecv:
+ e2e->send.confirm = tsk_true;
+ e2e->recv.confirm = tsk_true;
+ break;
+ default:
+ break;
+ }
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to parse a=%s:%s", A->field, A->value);
+ }
+ }
+
+ return e2e;
+}
+
+int tmedia_qos_tline_e2e_to_sdp(const tmedia_qos_tline_e2e_t* self, tsdp_header_M_t* m)
+{
+ /* RFC 3312 - 5.1.1 SDP encoding
+
+ For the end-to-end status type, the user agent MUST generate one
+ current status line with the tag "e2e" for the media stream. If the
+ strength-tags for both directions are equal (e.g., both "mandatory")
+ in the transaction status table, the user agent MUST add one desired
+ status line with the tag "sendrecv". If both tags are different, the
+ user agent MUST include two desired status lines, one with the tag
+ "send" and the other with the tag "recv".
+ */
+ char* temp = tsk_null;
+
+ if(!self || !m){
+ TSK_DEBUG_ERROR("invalid parameter");
+ return -1;
+ }
+ /* Example
+ a=curr:qos e2e none
+ a=des:qos mandatory e2e sendrecv
+ */
+
+
+ /* curr */
+ tsk_sprintf(&temp, "qos e2e %s", (self->recv.current && self->send.current) ? "sendrecv" : (self->recv.current ? "recv" : (self->send.current ? "send" : "none")));
+ tsdp_header_M_add_headers(m,
+ TSDP_HEADER_A_VA_ARGS("curr", temp),
+ tsk_null);
+ TSK_FREE(temp);
+
+ /* des */
+ if(self->recv.strength == self->send.strength){
+ /* sendrecv */
+ tsk_sprintf(&temp, "qos %s e2e sendrecv", tmedia_qos_strength_tostring(self->recv.strength));
+ tsdp_header_M_add_headers(m,
+ TSDP_HEADER_A_VA_ARGS("des", temp),
+ tsk_null);
+ TSK_FREE(temp);
+ }
+ else{
+ /* send */
+ tsk_sprintf(&temp, "qos %s e2e send", tmedia_qos_strength_tostring(self->send.strength));
+ tsdp_header_M_add_headers(m,
+ TSDP_HEADER_A_VA_ARGS("des", temp),
+ tsk_null);
+ TSK_FREE(temp);
+
+ /* recv */
+ tsk_sprintf(&temp, "qos %s e2e recv", tmedia_qos_strength_tostring(self->recv.strength));
+ tsdp_header_M_add_headers(m,
+ TSDP_HEADER_A_VA_ARGS("des", temp),
+ tsk_null);
+ TSK_FREE(temp);
+ }
+
+ /* conf (should not request confirm on "send" direction)*/
+ if(self->recv.confirm){
+ tsdp_header_M_add_headers(m,
+ TSDP_HEADER_A_VA_ARGS("conf", "qos e2e recv"),
+ tsk_null);
+ }
+ return 0;
+}
+
+int tmedia_qos_tline_e2e_set_ro(tmedia_qos_tline_e2e_t* self, const tmedia_qos_tline_e2e_t* ro)
+{
+ if(!self || !ro){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ /* We were the offerer
+ * Remote asked for confirmation in its "recv" direction?
+ * "recv" direction for remote is our "send" direction
+ * As we don't support RSVP (under the way), confirm immediatly.
+ * "send" direction should not requested for confirmation
+ */
+ if(ro->recv.confirm){
+ self->send.current = tsk_true;
+ goto bail;
+ }
+ if(ro->send.current){
+ self->recv.confirm = tsk_false; /* remote confirmed */
+ self->recv.current = tsk_true; /* because ro confirmed */
+ self->send.current = tsk_true; /* beacuse we don't support RSVP */
+ goto bail;
+ }
+
+ /* We are the answerer
+ * As we don't support RSVP (under the way):
+ * ==> request confirmation for "recv" direction if equal to "none" (not reserved)
+ * =>
+ */
+ if(!self->recv.current){
+ self->recv.confirm = tsk_true;
+ goto bail;
+ }
+
+bail:
+ /* all other cases: success */
+ return 0;
+}
+
+tsk_bool_t tmedia_qos_tline_e2e_canresume(const tmedia_qos_tline_e2e_t* self)
+{
+ if(!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_true;
+ }
+
+ /* Example
+ a=curr:qos e2e none
+ a=des:qos mandatory e2e sendrecv
+
+ Or
+
+ a=curr:qos e2e send
+ a=des:qos mandatory e2e recv
+ a=des:qos optional e2e send
+ */
+
+ /* only "mandatory" strength should force the application to continue nego. */
+ if(self->recv.strength == tmedia_qos_strength_mandatory && !self->recv.current){
+ return tsk_false;
+ }
+ /*else */if(self->send.strength == tmedia_qos_strength_mandatory && !self->send.current){
+ return tsk_false;
+ }
+
+ /* "optinal" and "none" strengths */
+ return tsk_true;
+}
+
+//
+// E2E QoS line object definition
+//
+static tsk_object_t* tmedia_qos_tline_e2e_ctor(tsk_object_t * self, va_list * app)
+{
+ tmedia_qos_tline_e2e_t *e2e = self;
+ if(e2e){
+ e2e->recv.strength = e2e->send.strength = va_arg(*app, tmedia_qos_strength_t);
+ TMEDIA_QOS_TLINE(e2e)->type = tmedia_qos_stype_e2e;
+ }
+ return self;
+}
+
+static tsk_object_t* tmedia_qos_tline_e2e_dtor(tsk_object_t * self)
+{
+ tmedia_qos_tline_e2e_t *e2e = self;
+ if(e2e){
+ }
+
+ return self;
+}
+
+static const tsk_object_def_t tmedia_qos_tline_e2e_def_s =
+{
+ sizeof(tmedia_qos_tline_e2e_t),
+ tmedia_qos_tline_e2e_ctor,
+ tmedia_qos_tline_e2e_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tmedia_qos_tline_e2e_def_t = &tmedia_qos_tline_e2e_def_s;
+
+
+
+
+
+
+
+
+
+
+/* ========================= Segmented ==================================*/
+
+tmedia_qos_tline_segmented_t* tmedia_qos_tline_segmented_create(tmedia_qos_strength_t strength)
+{
+ return tsk_object_new(tmedia_qos_tline_segmented_def_t, strength);
+}
+
+tmedia_qos_tline_segmented_t* tmedia_qos_tline_segmented_from_sdp(const tsdp_header_M_t* m)
+{
+ tmedia_qos_tline_segmented_t* segmented = tsk_null;
+ const tsdp_header_A_t* A;
+ tsk_size_t i;
+
+ char s0[10], s1[10], s2[10];
+
+ if(!m){
+ TSK_DEBUG_ERROR("invalid parameter");
+ return tsk_null;
+ }
+
+ /* Example
+ a=curr:qos local none
+ a=curr:qos remote none
+ a=des:qos optional remote send
+ a=des:qos none remote recv
+ a=des:qos none local sendrecv
+ a=conf:qos local recv
+ */
+ segmented = tmedia_qos_tline_segmented_create(tmedia_qos_strength_unknown);
+
+ /* curr */
+ for(i = 0; (A = tsdp_header_M_findA_at(m, "curr", i)); i++){
+ if(sscanf(A->value, "qos %10s %10s", s0, s1) != EOF){
+ /* For segmented, s0 should be equal to "local" or "remote" */
+ tmedia_qos_direction_t dir = tmedia_qos_direction_fromstring(s1);
+ if(tsk_strequals(s0, "local")){
+ /* local */
+ switch(dir){
+ case tmedia_qos_direction_send:
+ segmented->local_send.current = tsk_true;
+ break;
+ case tmedia_qos_direction_recv:
+ segmented->local_recv.current = tsk_true;
+ break;
+ case tmedia_qos_direction_sendrecv:
+ segmented->local_send.current = tsk_true;
+ segmented->local_recv.current = tsk_true;
+ break;
+ case tmedia_qos_direction_none:
+ segmented->local_send.current = tsk_false;
+ segmented->local_recv.current = tsk_false;
+ break;
+ default:
+ break;
+ }
+ }
+ else{
+ /* remote */
+ switch(dir){
+ case tmedia_qos_direction_send:
+ segmented->remote_send.current = tsk_true;
+ break;
+ case tmedia_qos_direction_recv:
+ segmented->remote_recv.current = tsk_true;
+ break;
+ case tmedia_qos_direction_sendrecv:
+ segmented->remote_send.current = tsk_true;
+ segmented->remote_recv.current = tsk_true;
+ break;
+ case tmedia_qos_direction_none:
+ segmented->remote_send.current = tsk_false;
+ segmented->remote_recv.current = tsk_false;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to parse a=%s:%s", A->field, A->value);
+ }
+ }
+
+ /* des */
+ for(i = 0; (A = tsdp_header_M_findA_at(m, "des", i)); i++){
+ if(sscanf(A->value, "qos %10s %10s %10s", s0, s1, s2) != EOF){
+ /* For segmented, s1 should be equal to "local" or "remote" */
+ tmedia_qos_strength_t strength = tmedia_qos_strength_fromstring(s0);
+ tmedia_qos_direction_t dir = tmedia_qos_direction_fromstring(s2);
+ if(tsk_strequals(s1, "local")){
+ /* local */
+ switch(dir){
+ case tmedia_qos_direction_send:
+ segmented->local_send.strength = strength;
+ break;
+ case tmedia_qos_direction_recv:
+ segmented->local_recv.strength = strength;
+ break;
+ case tmedia_qos_direction_sendrecv:
+ segmented->local_send.strength = strength;
+ segmented->local_recv.strength = strength;
+ break;
+ default:
+ break;
+ }
+ }
+ else{
+ /* remote */
+ switch(dir){
+ case tmedia_qos_direction_send:
+ segmented->remote_send.strength = strength;
+ break;
+ case tmedia_qos_direction_recv:
+ segmented->remote_recv.strength = strength;
+ break;
+ case tmedia_qos_direction_sendrecv:
+ segmented->remote_send.strength = strength;
+ segmented->remote_recv.strength = strength;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to parse a=%s:%s", A->field, A->value);
+ }
+ }
+
+ /* conf */
+ for(i = 0; (A = tsdp_header_M_findA_at(m, "conf", i)); i++){
+ if(sscanf(A->value, "qos %10s %10s", s0, s1) != EOF){
+ /* For segmented, s0 should be equal to "local" or "remote" */
+ tmedia_qos_direction_t dir = tmedia_qos_direction_fromstring(s1);
+ if(tsk_strequals(s0, "local")){
+ /* local */
+ switch(dir){
+ case tmedia_qos_direction_send:
+ segmented->local_send.confirm = tsk_true;
+ break;
+ case tmedia_qos_direction_recv:
+ segmented->local_recv.confirm = tsk_true;
+ break;
+ case tmedia_qos_direction_sendrecv:
+ segmented->local_send.confirm = tsk_true;
+ segmented->local_recv.confirm = tsk_true;
+ break;
+ default:
+ break;
+ }
+ }
+ else{
+ /* remote */
+ switch(dir){
+ case tmedia_qos_direction_send:
+ segmented->remote_send.confirm = tsk_true;
+ break;
+ case tmedia_qos_direction_recv:
+ segmented->remote_recv.confirm = tsk_true;
+ break;
+ case tmedia_qos_direction_sendrecv:
+ segmented->remote_send.confirm = tsk_true;
+ segmented->remote_recv.confirm = tsk_true;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to parse a=%s:%s", A->field, A->value);
+ }
+ }
+
+ return segmented;
+}
+
+int tmedia_qos_tline_segmented_to_sdp(const tmedia_qos_tline_segmented_t* self, tsdp_header_M_t* m)
+{
+ /* RFC 3312 - 5.1.1 SDP encoding
+
+ For the segmented status type, the user agent MUST generate two
+ current status lines: one with the tag "local" and the other with the
+ tag "remote". The user agent MUST add one or two desired status
+ lines per segment (i.e., local and remote). If, for a particular
+ segment (local or remote), the tags for both directions in the
+ transaction status table are equal (e.g., both "mandatory"), the user
+ agent MUST add one desired status line with the tag "sendrecv". If
+ both tags are different, the user agent MUST include two desired
+ status lines, one with the tag "send" and the other with the tag "recv".
+ */
+ char* temp = tsk_null;
+
+ if(!self || !m){
+ TSK_DEBUG_ERROR("invalid parameter");
+ return -1;
+ }
+
+ /* Example
+ a=curr:qos local none
+ a=curr:qos remote none
+ a=des:qos optional remote send
+ a=des:qos none remote recv
+ a=des:qos none local sendrecv
+ */
+
+ /* curr:local */
+ tsk_sprintf(&temp, "qos local %s", (self->local_recv.current && self->local_send.current) ? "sendrecv" : (self->local_recv.current ? "recv" : (self->local_send.current ? "send" : "none")));
+ tsdp_header_M_add_headers(m,
+ TSDP_HEADER_A_VA_ARGS("curr", temp),
+ tsk_null);
+ TSK_FREE(temp);
+
+ /* curr:remote */
+ tsk_sprintf(&temp, "qos remote %s", (self->remote_recv.current && self->remote_send.current) ? "sendrecv" : (self->remote_recv.current ? "recv" : (self->remote_send.current ? "send" : "none")));
+ tsdp_header_M_add_headers(m,
+ TSDP_HEADER_A_VA_ARGS("curr", temp),
+ tsk_null);
+ TSK_FREE(temp);
+
+
+ /* des:local */
+ if(self->local_recv.strength == self->local_send.strength){
+ /* sendrecv */
+ tsk_sprintf(&temp, "qos %s local sendrecv", tmedia_qos_strength_tostring(self->local_send.strength));
+ tsdp_header_M_add_headers(m,
+ TSDP_HEADER_A_VA_ARGS("des", temp),
+ tsk_null);
+ TSK_FREE(temp);
+ }
+ else{
+ /* send */
+ tsk_sprintf(&temp, "qos %s local send", tmedia_qos_strength_tostring(self->local_send.strength));
+ tsdp_header_M_add_headers(m,
+ TSDP_HEADER_A_VA_ARGS("des", temp),
+ tsk_null);
+ TSK_FREE(temp);
+
+ /* recv */
+ tsk_sprintf(&temp, "qos %s local recv", tmedia_qos_strength_tostring(self->local_recv.strength));
+ tsdp_header_M_add_headers(m,
+ TSDP_HEADER_A_VA_ARGS("des", temp),
+ tsk_null);
+ TSK_FREE(temp);
+ }
+
+
+ /* des:remote */
+ if(self->remote_recv.strength == self->remote_send.strength){
+ /* sendrecv */
+ tsk_sprintf(&temp, "qos %s remote sendrecv", tmedia_qos_strength_tostring(self->remote_send.strength));
+ tsdp_header_M_add_headers(m,
+ TSDP_HEADER_A_VA_ARGS("des", temp),
+ tsk_null);
+ TSK_FREE(temp);
+ }
+ else{
+ /* send */
+ tsk_sprintf(&temp, "qos %s remote send", tmedia_qos_strength_tostring(self->remote_send.strength));
+ tsdp_header_M_add_headers(m,
+ TSDP_HEADER_A_VA_ARGS("des", temp),
+ tsk_null);
+ TSK_FREE(temp);
+
+ /* recv */
+ tsk_sprintf(&temp, "qos %s remote recv", tmedia_qos_strength_tostring(self->remote_recv.strength));
+ tsdp_header_M_add_headers(m,
+ TSDP_HEADER_A_VA_ARGS("des", temp),
+ tsk_null);
+ TSK_FREE(temp);
+ }
+
+ /* conf */
+ if(self->remote_recv.confirm || self->remote_send.confirm){
+ tsk_sprintf(&temp, "qos remote %s", (self->remote_recv.confirm && self->remote_send.confirm) ? "sendrecv" : (self->remote_recv.confirm ? "recv" : (self->remote_send.confirm ? "send" : "none")));
+ tsdp_header_M_add_headers(m,
+ TSDP_HEADER_A_VA_ARGS("conf", temp),
+ tsk_null);
+ TSK_FREE(temp);
+ }
+
+ return 0;
+}
+
+int tmedia_qos_tline_segmented_set_ro(tmedia_qos_tline_segmented_t* self, const tmedia_qos_tline_segmented_t* ro)
+{
+ if(!self || !ro){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ //////////////
+ if(!ro->local_recv.current && !ro->remote_recv.confirm){
+ /* request confirmation */
+ self->remote_recv.confirm = tsk_true;
+ }
+ else{
+ self->remote_recv.confirm = tsk_false;
+ self->local_recv.current = tsk_true;
+ }
+ if(!ro->local_send.current && !ro->remote_send.confirm){
+ /* request confirmation */
+ self->remote_send.confirm = tsk_true;
+ }
+ else{
+ self->remote_send.confirm = tsk_false;
+ self->local_send.current = tsk_true;
+ }
+
+ //////////////
+ if(ro->remote_recv.confirm){
+ self->local_recv.current = tsk_true;
+ }
+ if(ro->remote_send.confirm){
+ self->local_send.current = tsk_true;
+ }
+
+ //////////////
+ if(ro->local_recv.current){
+ self->remote_recv.current = tsk_true;
+ }
+ if(ro->local_send.current){
+ self->remote_send.current = tsk_true;
+ }
+
+ return 0;
+}
+
+tsk_bool_t tmedia_qos_tline_segmented_canresume(const tmedia_qos_tline_segmented_t* self)
+{
+ if(!self){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return tsk_true;
+ }
+
+ /* == Strength is mandatory == */
+ if(self->local_recv.strength == tmedia_qos_strength_mandatory && !self->local_recv.current){
+ return tsk_false;
+ }
+
+ if(self->local_send.strength == tmedia_qos_strength_mandatory && !self->local_send.current){
+ return tsk_false;
+ }
+
+ if(self->remote_recv.strength == tmedia_qos_strength_mandatory && !self->remote_recv.current){
+ return tsk_false;
+ }
+
+ if(self->remote_send.strength == tmedia_qos_strength_mandatory && !self->remote_send.current){
+ return tsk_false;
+ }
+
+ /* "optinal" and "none" strengths */
+ return tsk_true;
+}
+
+//
+// Segmented QoS line object definition
+//
+static tsk_object_t* tmedia_qos_tline_segmented_ctor(tsk_object_t * self, va_list * app)
+{
+ tmedia_qos_tline_segmented_t *segmented = self;
+ if(segmented){
+ segmented->local_recv.strength = segmented->local_send.strength
+ = segmented->remote_recv.strength = segmented->remote_send.strength = va_arg(*app, tmedia_qos_strength_t);
+ TMEDIA_QOS_TLINE(segmented)->type = tmedia_qos_stype_segmented;
+ }
+ return self;
+}
+
+static tsk_object_t* tmedia_qos_tline_segmented_dtor(tsk_object_t * self)
+{
+ tmedia_qos_tline_segmented_t *segmented = self;
+ if(segmented){
+ }
+
+ return self;
+}
+
+static const tsk_object_def_t tmedia_qos_tline_segmented_def_s =
+{
+ sizeof(tmedia_qos_tline_segmented_t),
+ tmedia_qos_tline_segmented_ctor,
+ tmedia_qos_tline_segmented_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tmedia_qos_tline_segmented_def_t = &tmedia_qos_tline_segmented_def_s; \ No newline at end of file
OpenPOWER on IntegriCloud