/* * Copyright (C) 2012 Doubango Telecom <http://www.doubango.org> * License: BSD * This file is part of Open Source sipML5 solution <http://www.sipml5.org> */ tsdp_header_M.prototype = Object.create(tsdp_header.prototype); %%{ machine tsdp_machine_parser_header_M; # Includes include tsdp_machine_utils "./tsdp_machine_utils.jrl"; action tag{ i_tag_start = p; } action parse_media{ hdr_M.s_media = tsk_ragel_parser_get_string(s_str, p, i_tag_start); } action parse_port{ hdr_M.i_port= tsk_ragel_parser_get_int(s_str, p, i_tag_start); } action parse_nports{ hdr_M.i_nports= tsk_ragel_parser_get_int(s_str, p, i_tag_start); } action parse_proto{ hdr_M.s_proto = tsk_ragel_parser_get_string(s_str, p, i_tag_start); } action parse_fmt{ tsk_ragel_parser_add_string(s_str, p, i_tag_start, hdr_M.as_fmt); } media = token>tag %parse_media; port = DIGIT+>tag %parse_port; nports = DIGIT+>tag %parse_port; proto = (token ("/" token)*)>tag %parse_proto; fmt = token>tag %parse_fmt; #// media SP port ["/" integer] SP proto 1*(SP fmt) M = 'm' SP* "=" SP*<: media SP port ("/" nports)? SP proto (SP fmt)* (SP{1})?; # The last SP is for buggy browsers (e.g. Nightly 20.0a1 => "m=application 51713 SCTP/DTLS 5000 \r\n") # Entry point main := M :>CRLF?; }%% %%write data; function tsdp_header_M(s_media, i_port, s_proto){ tsdp_header.call(this, tsdp_header_type_e.M); this.s_media = s_media; this.i_port = i_port; this.i_nports = 0; // number of ports this.s_proto = s_proto; this.as_fmt = new Array(); this.o_hdr_I = null; this.o_hdr_C = null; this.ao_hdr_B = new Array(); this.o_hdr_K = null; this.ao_hdr_A = new Array(); this.ao_hdr_Dummy = new Array(); } tsdp_header_M.prototype.toString = function(s_endline){ if(!s_endline){ s_endline = "\r\n"; } /* IMPORTANT: Keep the order. m= (media name and transport address) i=* (media title) c=* (connection information -- optional if included at session level) b=* (zero or more bandwidth information lines) k=* (encryption key) a=* (zero or more media attribute lines) */ var s_str = tsk_string_format("{0} {1}{2}{3} {4}", this.s_media, this.i_port, this.i_nports ? "/" : "", this.i_nports ? this.i_nports : "", this.s_proto); // FMTs for(var i = 0; i < this.as_fmt.length; ++i){ s_str += " " + this.as_fmt[i]; } var b_single_line = !this.o_hdr_I && !this.o_hdr_C && this.ao_hdr_B.length==0 && !this.o_hdr_K && this.ao_hdr_A.length.length==0; if(b_single_line){ return s_str; } // close the "m=" line s_str += s_endline; // i=* (media title) if(this.o_hdr_I){ s_str += this.o_hdr_I.tostring_full(false, s_endline); } // c=* (connection information -- optional if included at session level) if(this.o_hdr_C){ s_str += this.o_hdr_C.tostring_full(false, s_endline); } // b=* (zero or more bandwidth information lines) for(var i = 0; i < this.ao_hdr_B.length; ++i){ s_str += this.ao_hdr_B[i].tostring_full(false, s_endline); } // k=* (encryption key) if(this.o_hdr_K){ s_str += this.o_hdr_K.tostring_full(false, s_endline); } // a=* (zero or more media attribute lines) for(var i = 0; i < this.ao_hdr_A.length; ++i){ s_str += this.ao_hdr_A[i].tostring_full(false, s_endline); } // dummies for(var i = 0; i < this.ao_hdr_Dummy.length; ++i){ s_str += this.ao_hdr_Dummy[i].tostring_full(false, s_endline); } return s_str.substring(0, s_str.length - s_endline.length); } // for A headers, use "tsdp_header_A_removeAll_by_field()" tsdp_header_M.prototype.remove_header = function(e_type){ switch(e_type){ case tsdp_header_type_e.I: { this.o_hdr_I = null; break; } case tsdp_header_type_e.C: { this.o_hdr_C = null; break; } case tsdp_header_type_e.B: { this.ao_hdr_B.splice(0, this.ao_hdr_B.length); break; } case tsdp_header_type_e.K: { this.o_hdr_K = null; break; } } return 0; } tsdp_header_M.prototype.add_header = function(o_header){ if(!o_header){ tsk_utils_log_error("Invalid argument"); return -1; } switch(o_header.e_type){ case tsdp_header_type_e.I: { this.o_hdr_I = o_header; break; } case tsdp_header_type_e.C: { this.o_hdr_C = o_header; break; } case tsdp_header_type_e.B: { this.ao_hdr_B.push(o_header); break; } case tsdp_header_type_e.K: { this.o_hdr_K = o_header; break; } case tsdp_header_type_e.A: { this.ao_hdr_A.push(o_header); break; } } return 0; } tsdp_header_M.prototype.add_fmt = function(s_fmt){ if(s_fmt){ this.as_fmt.push(s_fmt); } } // add_headers(...) tsdp_header_M.prototype.add_headers = function(){ for(var i = 0; i < arguments.length; ++i){ if(arguments[i]){ this.add_header(arguments[i]); } } } tsdp_header_M.prototype.find_a_at = function(s_field, i_index) { if(!s_field || i_index < 0){ tsk_utils_log_error("Invalid argument"); return null; } var i_pos = 0; for(var i = 0; i < this.ao_hdr_A.length; ++i){ if(this.ao_hdr_A[i].s_field == s_field){ if(i_pos++ >= i_index){ return this.ao_hdr_A[i]; } } } return null; } tsdp_header_M.prototype.find_a = function(s_field) { return this.find_a_at(s_field, 0); } tsdp_header_M.prototype.get_rtpmap = function(s_fmt){ var i_fmt_len = s_fmt ? s_fmt.length : 0; if(i_fmt_len <= 0 || i_fmt_len > 3/*'0-255' or '*'*/){ tsk_utils_log_error("Invalid argument"); return null; } var s_rtpmap = null; /* e.g. AMR-WB/16000 */ var i_A_len, i_index = 0; var i_indexof; var o_hdr_A; /* find "a=rtpmap" */ while((o_hdr_A = this.find_a_at(i_index++))){ /* A->value would be: "98 AMR-WB/16000" */ if((i_A_len = o_hdr_A.s_value ? o_hdr_A.s_value.length : 0) < (i_fmt_len + 1/*space*/)){ continue; } if((i_indexof = tsk_string_index_of(o_hdr_A.s_value, i_A_len, s_fmt)) == 0 && (o_hdr_A.s_value[i_fmt_len] == ' ')){ s_rtpmap = o_hdr_A.s_value.substring(i_fmt_len+1, A_len); break; } } return s_rtpmap; } tsdp_header_M.prototype.get_fmtp = function(s_fmt){ var i_fmt_len = s_fmt ? s_fmt.length : 0; if(i_fmt_len <= 0 || i_fmt_len > 3/*'0-255' or '*'*/){ tsk_utils_log_error("Invalid argument"); return null; } var s_fmtp= null; /* e.g. octet-align=1 */ var i_A_len, i_index = 0; var i_indexof; var o_hdr_A; /* find "a=rtpmap" */ while((o_hdr_A = this.find_a_at(i_index++))){ /* A->value would be: "98 octet-align=1" */ if((i_A_len = o_hdr_A.s_value ? o_hdr_A.s_value.length : 0) < (i_fmt_len + 1/*space*/)){ continue; } if((i_indexof = tsk_string_index_of(o_hdr_A.s_value, i_A_len, s_fmt)) == 0 && (o_hdr_A.s_value[i_fmt_len] == ' ')){ s_fmtp = o_hdr_A.s_value.substring(i_fmt_len+1, A_len); break; } } return s_fmtp; } /* as per 3GPP TS 34.610 */ tsdp_header_M.prototype.hold = function(b_local){ var o_hdr_A; if((o_hdr_A = this.find_a(b_local ? "recvonly" : "sendonly"))){ // an "inactive" SDP attribute if the stream was previously set to "recvonly" media stream o_hdr_A.s_field = b_local ? "inactive" : "recvonly"; } else if((o_hdr_A = this.find_a("sendrecv"))){ // a "sendonly" SDP attribute if the stream was previously set to "sendrecv" media stream o_hdr_A.s_field = b_local ? "sendonly" : "recvonly"; } else{ // default value is sendrecv. hold on default --> sendonly if(!(o_hdr_A = this.find_a(b_local ? "sendonly" : "recvonly")) && !(o_hdr_A = this.find_a("inactive"))){ var o_hdr_newA; if((o_hdr_newA = new tsdp_header_A(b_local ? "sendonly" : "recvonly", null))){ this.add_header(o_hdr_newA); } } } return 0; } /* as per 3GPP TS 34.610 */ tsdp_header_M.prototype.set_holdresume_att = function(b_lo_held, b_ro_held){ var o_hdr_A; var hold_resume_atts = [["sendrecv", "recvonly"],["sendonly", "inactive"]]; if((o_hdr_A = this.find_a("sendrecv")) || (o_hdr_A = this.find_a("sendonly")) || (o_hdr_A = this.find_a("recvonly")) || (o_hdr_A = this.find_a("inactive"))){ o_hdr_A.s_field = hold_resume_atts[b_lo_held ? 1 : 0][b_ro_held ? 1 : 0]; } else{ var o_hdr_newA; if((o_hdr_newA = new tsdp_header_A(hold_resume_atts[b_lo_held ? 1 : 0][b_ro_held ? 1 : 0], null))){ this.add_headers(o_hdr_newA); } } return 0; } tsdp_header_M.prototype.is_held = function(b_local){ /* both cases */ if(this.find_a("inactive")){ return true; } if(b_local){ return this.find_a("recvonly") ? true : false; } else{ return this.find_a("sendonly") ? true : false; } } /* as per 3GPP TS 34.610 */ tsdp_header_M.prototype.resume = function(b_local){ var o_hdr_A; if((o_hdr_A = this.find_a("inactive"))){ // a "recvonly" SDP attribute if the stream was previously an inactive media stream o_hdr_A.s_field = b_local ? "recvonly" : "sendonly"; } else if((o_hdr_A = this.find_a(b_local ? "sendonly" : "recvonly"))){ // a "sendrecv" SDP attribute if the stream was previously a sendonly media stream, or the attribute may be omitted, since sendrecv is the default o_hdr_A.s_field = sendrecv; } return 0; } tsdp_header_M.prototype.Parse = function(s_str){ var cs = 0; var p = 0; var pe = s_str.length; var eof = pe; var data = tsk_buff_str2ib(s_str); var i_tag_start; var hdr_M = new tsdp_header_M(null, 0, null); %%write init; %%write exec; if( cs < %%{ write first_final; }%% ){ tsk_utils_log_error("Failed to parse \"m=\" header: " + s_str); return null; } return hdr_M; }