1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2001-2016. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20 21%% 22%%---------------------------------------------------------------------- 23%% Purpose: RFC 4566 24%%---------------------------------------------------------------------- 25 26-module(megaco_sdp). 27 28%%---------------------------------------------------------------------- 29%% Include files 30%%---------------------------------------------------------------------- 31 32-include_lib("megaco/include/megaco.hrl"). 33-include_lib("megaco/src/app/megaco_internal.hrl"). 34-include_lib("megaco/include/megaco_message_v1.hrl"). 35-include_lib("megaco/include/megaco_sdp.hrl"). 36 37 38%%---------------------------------------------------------------------- 39%% External exports 40%%---------------------------------------------------------------------- 41 42%% Avoid warning for local function error/1 clashing with autoimported BIF. 43-compile({no_auto_import,[error/1]}). 44-export([ 45 decode/1, encode/1, 46 get_sdp_record_from_PropertyGroup/2 47 ]). 48 49 50%%---------------------------------------------------------------------- 51%% Internal exports 52%%---------------------------------------------------------------------- 53 54 55%%---------------------------------------------------------------------- 56%% Macros 57%%---------------------------------------------------------------------- 58 59 60%%---------------------------------------------------------------------- 61%% Records 62%%---------------------------------------------------------------------- 63 64 65%%====================================================================== 66%% External functions 67%%====================================================================== 68 69%% --------------------------------------------------------------------- 70%% decode(PP) -> {ok, SDP} | {error, Reason} 71%% 72%% This function performs the following conversion: 73%% property_parm() -> sdp() 74%% property_group() -> sdp_property_group() 75%% property_groups() -> sdp_property_groups() 76%% 77%% --------------------------------------------------------------------- 78 79decode(SDP) -> 80 case (catch do_decode(SDP)) of 81 {ok, _} = OK -> 82 OK; 83 {error, _} = ERR -> 84 ERR; 85 {'EXIT', Reason} -> 86 {error, {exit, Reason}}; 87 CRAP -> 88 {error, {crap, CRAP}} 89 end. 90 91do_decode(PP) when is_record(PP, 'PropertyParm') -> 92 decode_PropertyParm(PP); 93do_decode([PP|_] = PG) when is_record(PP, 'PropertyParm') -> 94 decode_PropertyGroup(PG); 95do_decode([H|_] = PGs) when is_list(H) -> 96 decode_PropertyGroups(PGs); 97do_decode(asn1_NOVALUE = V) -> 98 {ok, V}; 99do_decode(Bad) -> 100 {error, {bad_sdp, Bad}}. 101 102 103%% --------------------------------------------------------------------- 104%% encode(SDPs) -> {ok, PP} | {error, Reason} 105%% 106%% This function performs the following conversion: 107%% sdp() -> property_parm() 108%% sdp_property_group() -> property_group() 109%% sdp_property_groups() -> property_groups() 110%% 111%% --------------------------------------------------------------------- 112 113encode(SDP) -> 114 case (catch do_encode(SDP)) of 115 {ok, _} = OK -> 116 OK; 117 {error, _} = ERR -> 118 ERR; 119 {'EXIT', Reason} -> 120 {error, {exit, Reason}}; 121 CRAP -> 122 {error, {crap, CRAP}} 123 end. 124 125do_encode(SDP) when is_tuple(SDP) -> 126 {ok, encode_PropertyParm(SDP)}; 127do_encode([SDP|_] = PG) when is_tuple(SDP) -> 128 encode_PropertyGroup(PG); 129do_encode([H|_] = PGs) when is_list(H) -> 130 encode_PropertyGroups(PGs); 131do_encode(asn1_NOVALUE = V) -> 132 {ok, V}. 133 134 135%%----------------------------------------------------------------- 136%% Generate sdp records from PropertyParm records 137%%----------------------------------------------------------------- 138 139decode_PropertyGroups(PGs) -> 140 decode_PropertyGroups(PGs, []). 141 142decode_PropertyGroups([], DecodedPGs) -> 143 {ok, lists:reverse(DecodedPGs)}; 144 145decode_PropertyGroups([PG | PGs], DecodedPGs) -> 146 {ok, DecodedPG} = decode_PropertyGroup(PG), 147 decode_PropertyGroups(PGs, [DecodedPG | DecodedPGs]). 148 149 150decode_PropertyGroup(PG) -> 151 {ok, decode_PropertyGroup(PG, [])}. 152 153decode_PropertyGroup([], Acc) -> 154 lists:reverse(Acc); 155 156decode_PropertyGroup([PP | PG], Acc) -> 157 case (catch decode_PropertyParm(PP)) of 158 {ok, PP2} -> 159 decode_PropertyGroup(PG, [PP2 | Acc]); 160 {error, Reason} -> 161 decode_PropertyGroup(PG, [{PP, Reason} | Acc]); 162 Error -> 163 decode_PropertyGroup(PG, [{PP, Error} | Acc]) 164 end. 165 166 167%% ===== Protocol Version ===== 168%% 169decode_PropertyParm(#'PropertyParm'{name = "v", 170 value = [V], 171 extraInfo = asn1_NOVALUE}) -> 172 decode_pp_protocol_version(V); 173 174 175%% ===== Origin ===== 176%% 177decode_PropertyParm(#'PropertyParm'{name = "o", 178 value = [V], 179 extraInfo = asn1_NOVALUE}) -> 180 decode_pp_origin(V); 181 182 183%% ===== Session Name ===== 184%% 185decode_PropertyParm(#'PropertyParm'{name = "s", 186 value = [V], 187 extraInfo = asn1_NOVALUE}) -> 188 decode_pp_session_name(V); 189 190 191%% ===== Session and Media Information ===== 192%% 193decode_PropertyParm(#'PropertyParm'{name = "i", 194 value = [V], 195 extraInfo = asn1_NOVALUE}) -> 196 decode_pp_session_media_id(V); 197 198 199%% ===== URI ===== 200%% 201decode_PropertyParm(#'PropertyParm'{name = "u", 202 value = [V], 203 extraInfo = asn1_NOVALUE}) -> 204 decode_pp_uri(V); 205 206 207%% ===== Email Address and Phone Number ===== 208%% 209decode_PropertyParm(#'PropertyParm'{name = "e", 210 value = [V], 211 extraInfo = asn1_NOVALUE}) -> 212 decode_pp_email(V); 213 214decode_PropertyParm(#'PropertyParm'{name = "p", 215 value = [V], 216 extraInfo = asn1_NOVALUE}) -> 217 decode_pp_phone(V); 218 219 220%% ===== Connection Data ===== 221%% 222decode_PropertyParm(#'PropertyParm'{name = "c", 223 value = [V], 224 extraInfo = asn1_NOVALUE}) -> 225 decode_pp_connection_data(V); 226 227 228%% ===== Bandwidth ===== 229%% 230decode_PropertyParm(#'PropertyParm'{name = "b", 231 value = [V], 232 extraInfo = asn1_NOVALUE}) -> 233 decode_pp_bandwidth(V); 234 235 236%% ===== Times, Repeat Times and Time Zones ===== 237%% 238decode_PropertyParm(#'PropertyParm'{name = "t", 239 value = [V], 240 extraInfo = asn1_NOVALUE }) -> 241 decode_pp_times(V); 242decode_PropertyParm(#'PropertyParm'{name = "r", 243 value = [V], 244 extraInfo = asn1_NOVALUE}) -> 245 decode_pp_rtimes(V); 246decode_PropertyParm(#'PropertyParm'{name = "z", 247 value = [V], 248 extraInfo = asn1_NOVALUE}) -> 249 decode_pp_tzones(V); 250 251 252%% ===== Encryption Keys ===== 253%% 254decode_PropertyParm(#'PropertyParm'{name = "k", 255 value = [V], 256 extraInfo = asn1_NOVALUE}) -> 257 decode_pp_encryption_keys(V); 258 259 260%% ===== Attributes ===== 261%% 262decode_PropertyParm(#'PropertyParm'{name = "a", 263 value = [V], 264 extraInfo = asn1_NOVALUE}) -> 265 decode_pp_attribute(V); 266 267 268%% ===== Media Announcements ===== 269%% 270decode_PropertyParm(#'PropertyParm'{name = "m", 271 value = [V], 272 extraInfo = asn1_NOVALUE}) -> 273 decode_pp_media_announcement(V); 274 275 276decode_PropertyParm(_PP) -> 277 ?d("decode_PropertyParm -> entry with" 278 "~n _PP: ~p", [_PP]), 279 {error, undefined_PropertyParm}. 280 281 282%%----------------------------------------------------------------- 283%% Generate PropertyParm records from sdp records 284%%----------------------------------------------------------------- 285 286encode_PropertyGroups(PGs) -> 287 encode_PropertyGroups(PGs, []). 288 289 290encode_PropertyGroups([], Acc) -> 291 {ok, lists:reverse(Acc)}; 292encode_PropertyGroups([PG | PGs], Acc) -> 293 {ok, EncodedPG} = encode_PropertyGroup(PG), 294 encode_PropertyGroups(PGs, [EncodedPG | Acc]). 295 296 297encode_PropertyGroup(PG) -> 298 encode_PropertyGroup(PG, []). 299 300encode_PropertyGroup([], Acc) -> 301 {ok, lists:reverse(Acc)}; 302encode_PropertyGroup([PP | PG], Acc) -> 303 EncodedPP = encode_PropertyParm(PP), 304 encode_PropertyGroup(PG, [EncodedPP | Acc]). 305 306 307%% ===== Protocol Version ===== 308%% 309encode_PropertyParm(#megaco_sdp_v{version = Version}) -> 310 encode_pp_protocol_version(Version); 311 312 313%% ===== Origin ===== 314%% 315encode_PropertyParm(#megaco_sdp_o{user_name = User, 316 session_id = SessionId, 317 version = Version, 318 network_type = Network, 319 address_type = AddrType, 320 address = Addr}) -> 321 encode_pp_origin(User, SessionId, Version, Network, AddrType, Addr); 322 323 324%% ===== Session Name ===== 325%% 326encode_PropertyParm(#megaco_sdp_s{name = Name}) -> 327 encode_pp_session_name(Name); 328 329 330%% ===== Session and Media Information ===== 331%% 332encode_PropertyParm(#megaco_sdp_i{session_descriptor = SD}) -> 333 encode_pp_session_media_id(SD); 334 335 336%% ===== URI ===== 337%% 338encode_PropertyParm(#megaco_sdp_u{uri = URI}) -> 339 encode_pp_uri(URI); 340 341 342%% ===== Email Address and Phone Number ===== 343%% 344encode_PropertyParm(#megaco_sdp_e{email = Email}) -> 345 encode_pp_email(Email); 346 347encode_PropertyParm(#megaco_sdp_p{phone_number = Num}) -> 348 encode_pp_phone(Num); 349 350 351%% ===== Connection Data ===== 352%% 353encode_PropertyParm(#megaco_sdp_c{network_type = NetType, 354 address_type = AddressType, 355 connection_addr = ConnectionAddr}) -> 356 encode_pp_connection_data(NetType, AddressType, ConnectionAddr); 357 358 359%% ===== Bandwidth ===== 360%% 361encode_PropertyParm(#megaco_sdp_b{bwtype = BwType, 362 bandwidth = Bandwidth}) -> 363 encode_pp_bandwidth(BwType, Bandwidth); 364 365 366%% ===== Times, Repeat Times and Time Zones ===== 367%% 368encode_PropertyParm(#megaco_sdp_t{start = Start, stop = Stop}) -> 369 encode_pp_times(Start, Stop); 370 371encode_PropertyParm(#megaco_sdp_r{repeat_interval = Repeat, 372 active_duration = Duration, 373 list_of_offsets = ListOfOffsets}) -> 374 encode_pp_rtimes(Repeat, Duration, ListOfOffsets); 375 376encode_PropertyParm(#megaco_sdp_z{list_of_adjustments = LOA}) -> 377 encode_pp_tzones(LOA); 378 379 380%% ===== Encryption Keys ===== 381%% 382encode_PropertyParm(#megaco_sdp_k{method = Method, 383 encryption_key = EncryptionKey}) -> 384 encode_pp_encryption_keys(Method, EncryptionKey); 385 386 387%% ===== Attributes ===== 388%% 389encode_PropertyParm(#megaco_sdp_a_cat{category = Category}) -> 390 encode_pp_attribute_cat(Category); 391 392encode_PropertyParm(#megaco_sdp_a_keywds{keywords = Keywords}) -> 393 encode_pp_attribute_keywds(Keywords); 394 395encode_PropertyParm(#megaco_sdp_a_tool{name_and_version = NameAndVersion}) -> 396 encode_pp_attribute_tool(NameAndVersion); 397 398encode_PropertyParm(#megaco_sdp_a_ptime{packet_time = PacketTime}) -> 399 encode_pp_attribute_ptime(PacketTime); 400 401encode_PropertyParm( 402 #megaco_sdp_a_maxptime{maximum_packet_time = MaxPacketTime}) -> 403 encode_pp_attribute_maxptime(MaxPacketTime); 404 405encode_PropertyParm(#megaco_sdp_a_rtpmap{payload_type = Payload, 406 encoding_name = EncName, 407 clock_rate = ClockRate, 408 encoding_parms = EncPar}) -> 409 encode_pp_attribute_rtpmap(Payload, EncName, ClockRate, EncPar); 410 411encode_PropertyParm(#megaco_sdp_a_orient{orientation = Orientation}) -> 412 encode_pp_attribute_orient(Orientation); 413 414encode_PropertyParm(#megaco_sdp_a_type{conf_type = CType}) -> 415 encode_pp_attribute_type(CType); 416 417encode_PropertyParm(#megaco_sdp_a_charset{char_set = CharSet}) -> 418 encode_pp_attribute_charset(CharSet); 419 420encode_PropertyParm(#megaco_sdp_a_sdplang{tag = Tag}) -> 421 encode_pp_attribute_sdplang(Tag); 422 423encode_PropertyParm(#megaco_sdp_a_lang{tag = Tag}) -> 424 encode_pp_attribute_lang(Tag); 425 426encode_PropertyParm(#megaco_sdp_a_framerate{frame_rate = FrameRate}) -> 427 encode_pp_attribute_framerate(FrameRate); 428 429encode_PropertyParm(#megaco_sdp_a_quality{quality = Quality}) -> 430 encode_pp_attribute_quality(Quality); 431 432encode_PropertyParm(#megaco_sdp_a_fmtp{format = Fmt, param = Params}) -> 433 encode_pp_attribute_fmtp(Fmt, Params); 434 435encode_PropertyParm(#megaco_sdp_a{attribute = Attr, value = Value}) -> 436 encode_pp_attribute(Attr, Value); 437 438 439%% ===== Media Announcements ===== 440%% 441encode_PropertyParm(#megaco_sdp_m{media = Media, 442 port = Port, 443 num_ports = NOP, 444 transport = Transport, 445 fmt_list = FMT}) -> 446 encode_pp_media_announcement(Media, Port, NOP, Transport, FMT); 447 448 449%% This is a "manually" encoded PropertyParm, leave it as is. 450%% 451encode_PropertyParm(PP) when is_record(PP, 'PropertyParm') -> 452 PP; 453 454 455%% Bad data 456encode_PropertyParm(SDP) -> 457 error({unknown_sdp, SDP}). 458 459 460%%----------------------------------------------------------------- 461%% Func: get_sdp_record_from_PropertGroup/2 462%% Description: Get all sdp records of a certain type from a 463%% property group 464%%----------------------------------------------------------------- 465 466get_sdp_record_from_PropertyGroup(Type, PG) 467 when is_atom(Type) and is_list(PG) -> 468 F = fun(R) -> not is_pg_record(Type, R) end, 469 lists:filter(F, PG). 470 471is_pg_record(v, R) when is_record(R, megaco_sdp_v) -> true; 472is_pg_record(c, R) when is_record(R, megaco_sdp_c) -> true; 473is_pg_record(m, R) when is_record(R, megaco_sdp_m) -> true; 474is_pg_record(o, R) when is_record(R, megaco_sdp_o) -> true; 475is_pg_record(a, R) when is_record(R, megaco_sdp_a) -> true; 476is_pg_record(a, R) when is_record(R, megaco_sdp_a_ptime) -> true; 477is_pg_record(a, R) when is_record(R, megaco_sdp_a_rtpmap) -> true; 478is_pg_record(b, R) when is_record(R, megaco_sdp_b) -> true; 479is_pg_record(t, R) when is_record(R, megaco_sdp_t) -> true; 480is_pg_record(r, R) when is_record(R, megaco_sdp_r) -> true; 481is_pg_record(z, R) when is_record(R, megaco_sdp_z) -> true; 482is_pg_record(k, R) when is_record(R, megaco_sdp_k) -> true; 483is_pg_record(s, R) when is_record(R, megaco_sdp_s) -> true; 484is_pg_record(i, R) when is_record(R, megaco_sdp_i) -> true; 485is_pg_record(u, R) when is_record(R, megaco_sdp_u) -> true; 486is_pg_record(e, R) when is_record(R, megaco_sdp_e) -> true; 487is_pg_record(p, R) when is_record(R, megaco_sdp_p) -> true; 488is_pg_record(_, _) -> false. 489 490 491%%====================================================================== 492%% Internal functions 493%%====================================================================== 494 495%% ===== Protocol Version ===== 496%% 497decode_pp_protocol_version(Value) when is_list(Value) -> 498 ?d("decode_pp_protocol_version -> entry with" 499 "~n Value: ~p", [Value]), 500 Version = s2i(Value, invalid_protocol_version), 501 ?d("decode_pp_protocol_version -> entry with" 502 "~n Version: ~w", [Version]), 503 decode_pp_protocol_version(Version); 504decode_pp_protocol_version(Version) when is_integer(Version) -> 505 ?d("decode_pp_protocol_version -> entry with" 506 "~n Version: ~w", [Version]), 507 {ok, #megaco_sdp_v{version = Version}}. 508 509encode_pp_protocol_version(Version) when is_integer(Version) -> 510 ?d("encode_pp_protocol_version -> entry with" 511 "~n Version: ~w", [Version]), 512 #'PropertyParm'{name = "v", 513 value = [integer_to_list(Version)]}; 514encode_pp_protocol_version(Version) -> 515 error({invalid_protocol_version, Version}). 516 517 518%% ===== Origin ===== 519%% 520decode_pp_origin(Value) -> 521 ?d("decode_pp_origin -> entry with" 522 "~n Value: ~p", [Value]), 523 case string:tokens(Value, " \t") of 524 [User, SessId, SessVersion, NetType, AddrType, UnicastAddress] -> 525 ?d("decode_pp_origin -> entry with" 526 "~n User: ~p" 527 "~n SessionId: ~p" 528 "~n Version: ~p" 529 "~n NetType: ~p" 530 "~n AddrType: ~p" 531 "~n UnicastAddress: ~p", 532 [User, SessId, SessVersion, NetType, AddrType, UnicastAddress]), 533 F = fun(X, R) -> 534 case (catch list_to_integer(X)) of 535 I when is_integer(I) -> 536 I; 537 _ -> 538 error({invalid_origin, {R, X}}) 539 end 540 end, 541 SID = F(SessId, sess_id), 542 V = F(SessVersion, sess_version), 543 SDP = #megaco_sdp_o{user_name = User, 544 session_id = SID, 545 version = V, 546 network_type = decode_network_type(NetType), 547 address_type = decode_address_type(AddrType), 548 address = UnicastAddress}, 549 {ok, SDP}; 550 Err -> 551 ?d("decode_pp_origin -> " 552 "~n Err: ~p", [Err]), 553 invalid_pp(origin, Value, Err) 554 end. 555 556encode_pp_origin(User0, SessionId0, SessVersion0, 557 NetType0, AddrType0, UnicastAddr0) -> 558 ?d("do_encode_pp_origin -> entry with" 559 "~n User0: ~p" 560 "~n SessionId0: ~p" 561 "~n SessVersion0: ~p" 562 "~n NetType0: ~p" 563 "~n AddrType0: ~p" 564 "~n UnicastAddr0: ~p", 565 [User0, SessionId0, SessVersion0, NetType0, AddrType0, UnicastAddr0]), 566 User = encode_origin_user(User0), 567 SessionId = encode_origin_session_id(SessionId0), 568 SessVersion = encode_origin_sess_version(SessVersion0), 569 NetType = encode_origin_network_type(NetType0), 570 AddrType = encode_origin_address_type(AddrType0), 571 UnicastAddr = encode_origin_unicast_address(UnicastAddr0), 572 #'PropertyParm'{name = "o", 573 value = [ 574 User ++ " " ++ 575 SessionId ++ " " ++ 576 SessVersion ++ " " ++ 577 NetType ++ " " ++ 578 AddrType ++ " " ++ 579 UnicastAddr 580 ]}. 581 582encode_origin_user(User) when is_list(User) -> 583 User; 584encode_origin_user(BadUser) -> 585 error({invalid_origin_user, BadUser}). 586 587encode_origin_session_id(SID) when is_integer(SID) -> 588 integer_to_list(SID); 589encode_origin_session_id(BadSID) -> 590 error({invalid_origin_session_id, BadSID}). 591 592encode_origin_sess_version(SessVersion) when is_integer(SessVersion) -> 593 integer_to_list(SessVersion); 594encode_origin_sess_version(BadSessVersion) -> 595 error({invalid_origin_sess_version, BadSessVersion}). 596 597encode_origin_network_type(NT) -> 598 case (catch encode_network_type(NT)) of 599 {error, _} -> 600 error({invalid_origin_network_type, NT}); 601 Val -> 602 Val 603 end. 604 605encode_origin_address_type(AT) -> 606 case (catch encode_address_type(AT)) of 607 {error, _} -> 608 error({invalid_origin_address_type, AT}); 609 Val -> 610 Val 611 end. 612 613encode_origin_unicast_address(UnicastAddr) when is_list(UnicastAddr) -> 614 UnicastAddr; 615encode_origin_unicast_address(BadUnicastAddr) -> 616 error({invalid_origin_unicast_address, BadUnicastAddr}). 617 618 619%% ===== Session Name ===== 620%% 621decode_pp_session_name(Value) -> 622 ?d("decode_pp_session_name -> entry with" 623 "~n Value: ~p", [Value]), 624 {ok, #megaco_sdp_s{name = Value}}. 625 626encode_pp_session_name(Name) when is_list(Name) -> 627 ?d("encode_pp_session_name -> entry with" 628 "~n Name: '~s'", [Name]), 629 #'PropertyParm'{name = "s", 630 value = [Name]}; 631encode_pp_session_name(BadName) -> 632 error({invalid_session_name, BadName}). 633 634 635%% ===== Session and Media Information ===== 636%% 637decode_pp_session_media_id(Value) -> 638 ?d("decode_pp_session_media_id -> entry with" 639 "~n Value: ~p", [Value]), 640 {ok, #megaco_sdp_i{session_descriptor = Value}}. 641 642encode_pp_session_media_id(SD) when is_list(SD) -> 643 ?d("encode_pp_session_media_id -> entry with" 644 "~n SD: '~s'", [SD]), 645 #'PropertyParm'{name = "i", 646 value = [SD]}; 647encode_pp_session_media_id(BadSD) -> 648 error({invalid_session_media_id, BadSD}). 649 650 651%% ===== URI ===== 652%% 653decode_pp_uri(Value) -> 654 ?d("decode_pp_uri -> entry with" 655 "~n Value: ~p", [Value]), 656 {ok, #megaco_sdp_u{uri = Value}}. 657 658encode_pp_uri(URI) when is_list(URI) -> 659 ?d("encode_pp_uri -> entry with" 660 "~n URI: ~p", [URI]), 661 #'PropertyParm'{name = "u", 662 value = [URI]}; 663encode_pp_uri(BadUri) -> 664 error({invalid_uri, BadUri}). 665 666 667%% ===== Email Address and Phone Number ===== 668%% 669decode_pp_email(Value) -> 670 ?d("decode_pp_email -> entry with" 671 "~n Value: ~p", [Value]), 672 {ok, #megaco_sdp_e{email = Value}}. 673 674encode_pp_email(Email) when is_list(Email) -> 675 ?d("encode_pp_email -> entry with" 676 "~n Email: ~p", [Email]), 677 #'PropertyParm'{name = "e", 678 value = [Email]}; 679encode_pp_email(BadEmail) -> 680 error({invalid_email, BadEmail}). 681 682decode_pp_phone(Value) -> 683 ?d("decode_pp_phone -> entry with" 684 "~n Value: ~p", [Value]), 685 {ok, #megaco_sdp_p{phone_number = Value}}. 686 687encode_pp_phone(Phone) when is_list(Phone) -> 688 ?d("encode_pp_phone -> entry with" 689 "~n Phone: ~p", [Phone]), 690 #'PropertyParm'{name = "p", 691 value = [Phone]}; 692encode_pp_phone(BadPhone) -> 693 error({invalid_phone, BadPhone}). 694 695 696%% ===== Connection Data ===== 697%% 698decode_pp_connection_data(Value) -> 699 ?d("decode_pp_connection_data -> entry with" 700 "~n Value: ~p", [Value]), 701 case string:tokens(Value, " \t") of 702 [NetType, AddrType, ConnectionAddr] -> 703 ?d("decode_pp_connection_data -> " 704 "~n NetType: ~p" 705 "~n AddrType: ~p" 706 "~n ConnectionAddr: ~p", [NetType, AddrType, ConnectionAddr]), 707 NT = decode_network_type(NetType), 708 AT = decode_address_type(AddrType), 709 case AT of 710 ip4 -> 711 ?d("decode_pp_connection_data -> ip4", []), 712 ConnAddr = 713 case string:tokens(ConnectionAddr, "\/") of 714 [Base, TtlStr, NumOfAddrs] -> 715 ?d("decode_pp_connection_data -> " 716 "~n Base: ~p" 717 "~n TtlStr: ~p" 718 "~n NumOfAddrs:~p", 719 [Base, TtlStr, NumOfAddrs]), 720 TTL = s2i(TtlStr, 721 invalid_connection_data_ttl), 722 ?d("decode_pp_connection_data -> TTL: ~p", 723 [TTL]), 724 NOA = 725 s2i(NumOfAddrs, 726 invalid_connection_data_conn_addr_num_of), 727 ?d("decode_pp_connection_data -> NOA: ~p", 728 [NOA]), 729 #megaco_sdp_c_conn_addr{base = Base, 730 ttl = TTL, 731 num_of = NOA}; 732 [Base, TtlStr] -> 733 ?d("decode_pp_connection_data -> " 734 "~n Base: ~p" 735 "~n TtlStr: ~p", 736 [Base, TtlStr]), 737 TTL = 738 s2i(TtlStr, 739 invalid_connection_data_conn_addr_ttl), 740 ?d("decode_pp_connection_data -> TTL: ~p", 741 [TTL]), 742 #megaco_sdp_c_conn_addr{base = Base, 743 ttl = TTL}; 744 [Base] -> 745 Base 746 end, 747 ?d("decode_pp_connection_data -> " 748 "~n ConnAddr: ~p", [ConnAddr]), 749 SDP = #megaco_sdp_c{network_type = NT, 750 address_type = AT, 751 connection_addr = ConnAddr}, 752 {ok, SDP}; 753 ip6 -> 754 ?d("decode_pp_connection_data -> ip6", []), 755 SDP = #megaco_sdp_c{network_type = NT, 756 address_type = AT, 757 connection_addr = ConnectionAddr}, 758 {ok, SDP}; 759 _ -> 760 SDP = #megaco_sdp_c{network_type = NT, 761 address_type = AT, 762 connection_addr = ConnectionAddr}, 763 {ok, SDP} 764 end; 765 Err -> 766 invalid_pp(connection_data, Value, Err) 767 end. 768 769encode_pp_connection_data(NetType0, AddrType0, ConnAddr0) -> 770 ?d("encode_pp_connection_data -> entry with" 771 "~n NetType0: ~p" 772 "~n AddrType0: ~p" 773 "~n ConnAddr0: ~p", [NetType0, AddrType0, ConnAddr0]), 774 NetType = encode_conn_data_network_type(NetType0), 775 AddrType = encode_conn_data_address_type(AddrType0), 776 ConnAddr = encode_conn_data_conn_addr(AddrType0, ConnAddr0), 777 Val = NetType ++ " " ++ AddrType ++ " " ++ ConnAddr, 778 #'PropertyParm'{name = "c", 779 value = [Val]}. 780 781encode_conn_data_network_type(NT) -> 782 case (catch encode_network_type(NT)) of 783 {error, _} -> 784 error({invalid_connection_data_network_type, NT}); 785 Val -> 786 Val 787 end. 788 789encode_conn_data_address_type(AT) -> 790 case (catch encode_address_type(AT)) of 791 {error, _} -> 792 error({invalid_connection_data_address_type, AT}); 793 Val -> 794 Val 795 end. 796 797encode_conn_data_conn_addr(_, CA) when is_list(CA) -> 798 CA; 799encode_conn_data_conn_addr(ip4, CA) 800 when is_record(CA, megaco_sdp_c_conn_addr) -> 801 encode_conn_data_conn_addr(CA); 802encode_conn_data_conn_addr(AT, CA) 803 when is_list(AT) and is_record(CA, megaco_sdp_c_conn_addr) -> 804 case tolower(AT) of 805 "ip4" -> 806 encode_conn_data_conn_addr(CA); 807 _ -> 808 error({invalid_connection_data_conn_addr, {AT, CA}}) 809 end; 810encode_conn_data_conn_addr(_, BadCA) -> 811 error({invalid_connection_data_conn_addr, BadCA}). 812 813encode_conn_data_conn_addr(#megaco_sdp_c_conn_addr{base = Base0, 814 ttl = TTL0, 815 num_of = undefined}) -> 816 Base = encode_conn_data_conn_addr_base(Base0), 817 TTL = encode_conn_data_conn_addr_ttl(TTL0), 818 Base ++ "/" ++ TTL; 819encode_conn_data_conn_addr(#megaco_sdp_c_conn_addr{base = Base0, 820 ttl = TTL0, 821 num_of = NumOf0}) -> 822 Base = encode_conn_data_conn_addr_base(Base0), 823 TTL = encode_conn_data_conn_addr_ttl(TTL0), 824 NumOf = encode_conn_data_conn_addr_num_of(NumOf0), 825 Base ++ "/" ++ TTL ++ "/" ++ NumOf. 826 827encode_conn_data_conn_addr_base(Base) when is_list(Base) -> 828 Base; 829encode_conn_data_conn_addr_base(BadBase) -> 830 error({invalid_connection_data_conn_addr_base, BadBase}). 831 832encode_conn_data_conn_addr_ttl(TTL) when is_integer(TTL) -> 833 integer_to_list(TTL); 834encode_conn_data_conn_addr_ttl(BadTTL) -> 835 error({invalid_connection_data_conn_addr_ttl, BadTTL}). 836 837encode_conn_data_conn_addr_num_of(NumOf) when is_integer(NumOf) -> 838 integer_to_list(NumOf); 839encode_conn_data_conn_addr_num_of(BadNumOf) -> 840 error({invalid_connection_data_conn_addr_num_of, BadNumOf}). 841 842 843%% ===== Bandwidth ===== 844%% 845decode_pp_bandwidth(Value) -> 846 ?d("decode_pp_bandwidth -> entry with" 847 "~n Value: ~p", [Value]), 848 case string:tokens(Value, ":") of 849 [BwTypeStr, BandwidthStr] -> 850 ?d("decode_pp_bandwidth -> " 851 "~n BwTypeStr: ~p" 852 "~n BandwidthStr: ~p", [BwTypeStr, BandwidthStr]), 853 BwType = decode_bandwidth_bwt(BwTypeStr), 854 ?d("decode_pp_bandwidth -> " 855 "~n BwType: ~w", [BwType]), 856 Bandwidth = decode_bandwidth_bw(BandwidthStr), 857 ?d("decode_pp_bandwidth -> " 858 "~n Bandwidth: ~w", [Bandwidth]), 859 SDP = #megaco_sdp_b{bwtype = BwType, 860 bandwidth = Bandwidth}, 861 {ok, SDP}; 862 Err -> 863 invalid_pp(bandwidth_info, Value, Err) 864 end. 865 866encode_pp_bandwidth(BwType0, Bandwidth0) -> 867 ?d("encode_pp_bandwidth -> entry with" 868 "~n BwType0: ~p" 869 "~n Bandwidth0: ~p", [BwType0, Bandwidth0]), 870 BwType = encode_bandwidth_bwt(BwType0), 871 Bandwidth = encode_bandwidth_bw(Bandwidth0), 872 Val = BwType ++ ":" ++ Bandwidth, 873 #'PropertyParm'{name = "b", 874 value = [Val]}. 875 876decode_bandwidth_bwt("CT") -> 877 ct; 878decode_bandwidth_bwt("AS") -> 879 as; 880decode_bandwidth_bwt(BwType) when is_list(BwType) -> 881 BwType. 882 883encode_bandwidth_bwt(ct) -> 884 "CT"; 885encode_bandwidth_bwt(as) -> 886 "AS"; 887encode_bandwidth_bwt(BwType) when is_list(BwType) -> 888 BwType; 889encode_bandwidth_bwt(BadBwType) -> 890 error({invalid_bandwidth_bwtype, BadBwType}). 891 892decode_bandwidth_bw(Bandwidth) -> 893 s2i(Bandwidth, invalid_bandwidth_bandwidth). 894 895encode_bandwidth_bw(Bandwidth) when is_integer(Bandwidth) -> 896 integer_to_list(Bandwidth); 897encode_bandwidth_bw(BadBandwidth) -> 898 error({invalid_bandwidth_bandwidth, BadBandwidth}). 899 900 901%% ===== Times ===== 902%% 903decode_pp_times(Value) -> 904 ?d("decode_pp_times -> entry with" 905 "~n Value: ~p", [Value]), 906 case string:tokens(Value, " \t") of 907 [StartStr, StopStr] -> 908 ?d("decode_pp_times -> " 909 "~n StartStr: ~p" 910 "~n StopStr: ~p", [StartStr, StopStr]), 911 Start = decode_times_start(StartStr), 912 ?d("decode_pp_times -> entry with" 913 "~n Stop: ~w", [Start]), 914 Stop = decode_times_stop(StopStr), 915 ?d("decode_pp_times -> entry with" 916 "~n Stop: ~w", [Stop]), 917 SDP = #megaco_sdp_t{start = Start, 918 stop = Stop}, 919 {ok, SDP}; 920 Err -> 921 invalid_pp(times, Value, Err) 922 end. 923 924encode_pp_times(Start0, Stop0) -> 925 ?d("encode_pp_times -> entry with" 926 "~n Start0: ~p" 927 "~n Stop0: ~p", [Start0, Stop0]), 928 Start = encode_times_start(Start0), 929 Stop = encode_times_stop(Stop0), 930 Val = Start ++ " " ++ Stop, 931 #'PropertyParm'{name = "t", 932 value = [Val]}. 933 934decode_times_start(Time) -> 935 s2i(Time, invalid_times_start). 936 937encode_times_start(Time) when is_integer(Time) -> 938 integer_to_list(Time); 939encode_times_start(BadTime) -> 940 error({invalid_times_start, BadTime}). 941 942decode_times_stop(Time) -> 943 s2i(Time, invalid_times_stop). 944 945encode_times_stop(Time) when is_integer(Time) -> 946 integer_to_list(Time); 947encode_times_stop(BadTime) -> 948 error({invalid_times_stop, BadTime}). 949 950 951%% ===== Repeat Times ===== 952%% 953decode_pp_rtimes(Value) -> 954 ?d("decode_pp_rtimes -> entry with" 955 "~n Value: ~p", [Value]), 956 case string:tokens(Value, " \t") of 957 [Repeat, Duration | ListOfOffsets] -> 958 ?d("decode_pp_rtimes -> " 959 "~n Repeat: ~p" 960 "~n Duration: ~p" 961 "~n ListOfOffsets: ~p", [Repeat, Duration, ListOfOffsets]), 962 SDP = #megaco_sdp_r{repeat_interval = Repeat, 963 active_duration = Duration, 964 list_of_offsets = ListOfOffsets}, 965 {ok, SDP}; 966 Err -> 967 invalid_pp(repeat_times, Value, Err) 968 end. 969 970encode_pp_rtimes(Repeat0, Duration0, ListOfOffsets0) -> 971 ?d("encode_pp_rtimes -> entry with" 972 "~n Repeat0: ~p" 973 "~n Duration0: ~p" 974 "~n ListOfOffsets0: ~p", [Repeat0, Duration0, ListOfOffsets0]), 975 Repeat = encode_rtimes_repeat(Repeat0), 976 Duration = encode_rtimes_duration(Duration0), 977 ListOfOffsets = encode_rtimes_list_of_offsets(ListOfOffsets0), 978 Val = Repeat ++ " " ++ Duration ++ ListOfOffsets, 979 #'PropertyParm'{name = "r", 980 value = [Val]}. 981 982encode_rtimes_repeat(Repeat) when is_list(Repeat) -> 983 Repeat; 984encode_rtimes_repeat(BadRepeat) -> 985 error({invalid_rtimes_repeat, BadRepeat}). 986 987encode_rtimes_duration(Duration) when is_list(Duration) -> 988 Duration; 989encode_rtimes_duration(BadDuration) -> 990 error({invalid_rtimes_duration, BadDuration}). 991 992encode_rtimes_list_of_offsets(LOO) when is_list(LOO) -> 993 F = fun(Off, Acc) when is_list(Off) -> 994 Acc ++ " " ++ Off; 995 (BadOff, Acc) -> 996 error({invalid_rtimes_list_of_offsets, {BadOff, Acc}}) 997 end, 998 lists:foldl(F, [], LOO); 999encode_rtimes_list_of_offsets(BadLoo) -> 1000 error({invalid_rtimes_list_of_offsets, BadLoo}). 1001 1002 1003%% ===== Time Zones ===== 1004%% 1005decode_pp_tzones(Value) when is_list(Value) and (length(Value) > 0) -> 1006 ?d("decode_pp_ztimes -> entry with" 1007 "~n Value: ~p", [Value]), 1008 LOA = decode_tzones_list_of_adjustments(string:tokens(Value, " \t"), []), 1009 {ok, #megaco_sdp_z{list_of_adjustments = LOA}}; 1010decode_pp_tzones(BadValue) -> 1011 error({invalid_tzones_list_of_adjustments, BadValue}). 1012 1013encode_pp_tzones(LOA) -> 1014 ?d("encode_pp_ztimes -> entry with" 1015 "~n LOA: ~p", [LOA]), 1016 Val = encode_tzones_list_of_adjustments(LOA), 1017 #'PropertyParm'{name = "z", 1018 value = [Val]}. 1019 1020decode_tzones_list_of_adjustments([], Acc) -> 1021 lists:reverse(Acc); 1022decode_tzones_list_of_adjustments([Adj], Acc) -> 1023 error({invalid_tzones_list_of_adjustments, Adj, lists:reverse(Acc)}); 1024decode_tzones_list_of_adjustments([Time, Offset | LOA], Acc) -> 1025 Adj = #megaco_sdp_z_adjustement{time = Time, offset = Offset}, 1026 decode_tzones_list_of_adjustments(LOA, [Adj | Acc]). 1027 1028encode_tzones_list_of_adjustments([H|_] = LOA) 1029 when is_record(H, megaco_sdp_z_adjustement) -> 1030 F = fun(#megaco_sdp_z_adjustement{time = T, offset = O}, Acc) -> 1031 Acc ++ " " ++ T ++ " " ++ O; 1032 (BadAdjustment, Acc) -> 1033 error({invalid_tzones_list_of_adjustments, 1034 {BadAdjustment, Acc}}) 1035 end, 1036 lists:foldl(F, [], LOA); 1037encode_tzones_list_of_adjustments(LOA) -> 1038 error({invalid_tzones_list_of_adjustments, LOA}). 1039 1040 1041%% ===== Encryption Keys ===== 1042%% 1043decode_pp_encryption_keys(Value) -> 1044 ?d("decode_pp_encryption_keys -> entry with" 1045 "~n Value: ~p", [Value]), 1046 {M, E} = 1047 case string:tokens(Value, ":") of 1048 [Method, EncryptionKey] -> 1049 ?d("decode_pp_encryption_keys -> " 1050 "~n Method: ~p" 1051 "~n EncryptionKey: ~p", [Method, EncryptionKey]), 1052 {Method, EncryptionKey}; 1053 [Method] -> 1054 ?d("decode_pp_encryption_keys -> " 1055 "~n Method: ~p", [Method]), 1056 {Method, undefined}; 1057 Err -> 1058 invalid_pp(encryption_key, Value, Err) 1059 end, 1060 M2 = 1061 case tolower(M) of 1062 "clear" -> 1063 clear; 1064 "base64" -> 1065 base64; 1066 "uri" -> 1067 uri; 1068 "prompt" -> 1069 prompt; 1070 _ -> 1071 M 1072 end, 1073 ?d("decode_pp_encryption_keys -> " 1074 "~n M2: ~p", [M2]), 1075 SDP = #megaco_sdp_k{method = M2, 1076 encryption_key = E}, 1077 {ok, SDP}. 1078 1079encode_pp_encryption_keys(prompt = _Method, undefined) -> 1080 ?d("encode_pp_encryption_keys(prompt) -> entry", []), 1081 #'PropertyParm'{name = "k", 1082 value = ["prompt"]}; 1083encode_pp_encryption_keys(clear = _Method, EncryptionKey) 1084 when is_list(EncryptionKey) -> 1085 ?d("encode_pp_encryption_keys(clear) -> entry with" 1086 "~n EncryptionKey: ~p", [EncryptionKey]), 1087 #'PropertyParm'{name = "k", 1088 value = ["clear:" ++ EncryptionKey]}; 1089encode_pp_encryption_keys(base64 = _Method, EncryptionKey) 1090 when is_list(EncryptionKey) -> 1091 ?d("encode_pp_encryption_keys(base64) -> entry with" 1092 "~n EncryptionKey: ~p", [EncryptionKey]), 1093 #'PropertyParm'{name = "k", 1094 value = ["base64:" ++ EncryptionKey]}; 1095encode_pp_encryption_keys(uri = _Method, EncryptionKey) 1096 when is_list(EncryptionKey) -> 1097 ?d("encode_pp_encryption_keys(uri) -> entry with" 1098 "~n EncryptionKey: ~p", [EncryptionKey]), 1099 #'PropertyParm'{name = "k", 1100 value = ["uri:" ++ EncryptionKey]}; 1101encode_pp_encryption_keys(Method, EncryptionKey) 1102 when is_list(Method) and is_list(EncryptionKey) -> 1103 ?d("encode_pp_encryption_keys -> entry with" 1104 "~n Method: ~p" 1105 "~n EncryptionKey: ~p", [Method, EncryptionKey]), 1106 #'PropertyParm'{name = "k", 1107 value = [Method ++ ":" ++ EncryptionKey]}; 1108encode_pp_encryption_keys(BadMethod, BadEK) -> 1109 error({invalid_encryption_keys, {BadMethod, BadEK}}). 1110 1111 1112%% ===== Attributes ===== 1113%% 1114decode_pp_attribute(Value) -> 1115 ?d("decode_pp_attribute -> entry with" 1116 "~n Value: ~p", [Value]), 1117 First = string:chr(Value, $:), 1118 if 1119 (First > 0) and (First < length(Value)) -> 1120 ?d("decode_pp_attribute -> value attribute", []), 1121 Attr = string:substr(Value, 1, First -1), 1122 AttrValue = string:substr(Value, First + 1), 1123 ?d("decode_pp_attribute -> " 1124 "~n Attr: ~p" 1125 "~n AttrValue: ~p", [Attr, AttrValue]), 1126 decode_pp_attribute_value(Attr, AttrValue); 1127 1128 First > 0 -> 1129 ?d("decode_pp_attribute -> value attribute (empty)", []), 1130 Attr = string:substr(Value, 1, First -1), 1131 ?d("decode_pp_attribute -> " 1132 "~n Attr: ~p", [Attr]), 1133 decode_pp_attribute_value(Attr, []); 1134 1135 true -> 1136 ?d("decode_pp_attribute -> binary attribute", []), 1137 {ok, #megaco_sdp_a{attribute = Value}} 1138 1139 end. 1140 1141decode_pp_attribute_value("cat", AttrValue) -> 1142 ?d("decode_pp_attribute -> cat", []), 1143 SDP = #megaco_sdp_a_cat{category = AttrValue}, 1144 {ok, SDP}; 1145 1146decode_pp_attribute_value("keywds", AttrValue) -> 1147 ?d("decode_pp_attribute -> keywds", []), 1148 SDP = #megaco_sdp_a_keywds{keywords = AttrValue}, 1149 {ok, SDP}; 1150 1151decode_pp_attribute_value("tool", AttrValue) -> 1152 ?d("decode_pp_attribute -> tool", []), 1153 SDP = #megaco_sdp_a_tool{name_and_version = AttrValue}, 1154 {ok, SDP}; 1155 1156decode_pp_attribute_value("ptime", AttrValue) -> 1157 ?d("decode_pp_attribute -> ptime", []), 1158 PacketTimeStr = string:strip(AttrValue, both, $ ), 1159 PacketTime = 1160 s2i(PacketTimeStr, invalid_ptime_packet_time), 1161 ?d("decode_pp_attribute -> PacketTime: ~w", [PacketTime]), 1162 SDP = #megaco_sdp_a_ptime{packet_time = PacketTime}, 1163 {ok, SDP}; 1164 1165decode_pp_attribute_value("maxptime", AttrValue) -> 1166 ?d("decode_pp_attribute -> maxptime", []), 1167 MaxPacketTimeStr = string:strip(AttrValue, both, $ ), 1168 MaxPacketTime = 1169 s2i(MaxPacketTimeStr, invalid_maxptime_maximum_packet_time), 1170 ?d("decode_pp_attribute -> MaxPacketTime: ~w", [MaxPacketTime]), 1171 SDP = #megaco_sdp_a_maxptime{maximum_packet_time = MaxPacketTime}, 1172 {ok, SDP}; 1173 1174decode_pp_attribute_value("rtpmap", AttrValue) -> 1175 ?d("decode_pp_attribute -> rtpmap", []), 1176 case string:tokens(AttrValue, "\/ \t") of 1177 [PayloadStr, EncName, ClockRateStr | EncPar] -> 1178 ?d("decode_pp_attribute -> " 1179 "~n PayloadStr: ~p" 1180 "~n EncName: ~p" 1181 "~n ClockRateStr: ~p" 1182 "~n EncPar: ~p", 1183 [PayloadStr, EncName, ClockRateStr, EncPar]), 1184 Payload = 1185 s2i(PayloadStr, invalid_rtpmap_payload), 1186 ?d("decode_pp_attribute -> Payload: ~w", 1187 [Payload]), 1188 ClockRate = 1189 s2i(ClockRateStr, invalid_rtpmap_payload), 1190 ?d("decode_pp_attribute -> ClockRate: ~w", 1191 [ClockRate]), 1192 SDP = 1193 #megaco_sdp_a_rtpmap{payload_type = Payload, 1194 encoding_name = EncName, 1195 clock_rate = ClockRate, 1196 encoding_parms = EncPar}, 1197 {ok, SDP}; 1198 _ -> 1199 error({invalid_rtpmap, AttrValue}) 1200 end; 1201 1202decode_pp_attribute_value("orient", AttrValue) -> 1203 ?d("decode_pp_attribute -> orient", []), 1204 Orientation = decode_attribute_orientation(AttrValue), 1205 SDP = #megaco_sdp_a_orient{orientation = Orientation}, 1206 {ok, SDP}; 1207 1208decode_pp_attribute_value("type", AttrValue) -> 1209 ?d("decode_pp_attribute -> type", []), 1210 SDP = #megaco_sdp_a_type{conf_type = AttrValue}, 1211 {ok, SDP}; 1212 1213decode_pp_attribute_value("charset", AttrValue) -> 1214 ?d("decode_pp_attribute -> charset", []), 1215 SDP = #megaco_sdp_a_charset{char_set = AttrValue}, 1216 {ok, SDP}; 1217 1218decode_pp_attribute_value("sdplang", AttrValue) -> 1219 ?d("decode_pp_attribute -> sdplang", []), 1220 SDP = #megaco_sdp_a_sdplang{tag = AttrValue}, 1221 {ok, SDP}; 1222 1223decode_pp_attribute_value("lang", AttrValue) -> 1224 ?d("decode_pp_attribute -> lang", []), 1225 SDP = #megaco_sdp_a_lang{tag = AttrValue}, 1226 {ok, SDP}; 1227 1228decode_pp_attribute_value("framerate", AttrValue) -> 1229 ?d("decode_pp_attribute -> framerate", []), 1230 SDP = #megaco_sdp_a_framerate{frame_rate = AttrValue}, 1231 {ok, SDP}; 1232 1233decode_pp_attribute_value("quality", AttrValue) -> 1234 ?d("decode_pp_attribute -> quality", []), 1235 QualityStr = AttrValue, 1236 Quality = s2i(QualityStr, invalid_quality_quality), 1237 ?d("decode_pp_attribute -> Quality: ~w", [Quality]), 1238 SDP = #megaco_sdp_a_quality{quality = Quality}, 1239 {ok, SDP}; 1240 1241decode_pp_attribute_value("fmtp", AttrValue) -> 1242 ?d("decode_pp_attribute -> fmtp", []), 1243 FMTP = AttrValue, 1244 First = string:chr(FMTP, $ ), 1245 if 1246 (First > 0) and (First < length(FMTP)) -> 1247 ?d("decode_pp_attribute_value -> valid fmtp with params", []), 1248 Format = string:substr(FMTP, 1, First - 1), 1249 Params = string:substr(FMTP, First + 1), 1250 ?d("decode_pp_attribute_value -> " 1251 "~n Format: ~p" 1252 "~n Params: ~p", [Format, Params]), 1253 SDP = #megaco_sdp_a_fmtp{format = Format, 1254 param = Params}, 1255 {ok, SDP}; 1256 1257 First > 0 -> 1258 ?d("decode_pp_attribute -> valid fmtp", []), 1259 Format = string:substr(FMTP, 1, First - 1), 1260 ?d("decode_pp_attribute -> " 1261 "~n Format: ~p", [Format]), 1262 {ok, #megaco_sdp_a_fmtp{format = Format, param = []}}; 1263 1264 true -> 1265 ?d("decode_pp_attribute_value -> no params", []), 1266 {ok, #megaco_sdp_a_fmtp{format = FMTP, param = []}} 1267 1268 end; 1269 1270decode_pp_attribute_value(Attr, AttrValue) -> 1271 ?d("decode_pp_attribute -> unknown value attribute", []), 1272 {ok, #megaco_sdp_a{attribute = Attr, value = AttrValue}}. 1273 1274decode_attribute_orientation("portrait") -> 1275 portrait; 1276decode_attribute_orientation("landscape") -> 1277 landscape; 1278decode_attribute_orientation("seascape") -> 1279 seascape; 1280decode_attribute_orientation(BadOrientation) -> 1281 error({invalid_orient_orientation, BadOrientation}). 1282 1283encode_attribute_orientation(portrait) -> 1284 "portrait"; 1285encode_attribute_orientation(landscape) -> 1286 "landscape"; 1287encode_attribute_orientation(seascape) -> 1288 "seascape"; 1289encode_attribute_orientation(BadOrientation) -> 1290 error({invalid_orient_orientation, BadOrientation}). 1291 1292 1293encode_pp_attribute_cat(Cat) when is_list(Cat) -> 1294 ?d("encode_pp_attribute_cat -> entry with" 1295 "~n Cat: ~p", [Cat]), 1296 #'PropertyParm'{name = "a", 1297 value = ["cat:" ++ Cat]}; 1298encode_pp_attribute_cat(BadCat) -> 1299 error({invalid_cat_category, BadCat}). 1300 1301 1302encode_pp_attribute_keywds(Keywords) when is_list(Keywords) -> 1303 ?d("encode_pp_attribute_keywds -> entry with" 1304 "~n Keywords: ~p", [Keywords]), 1305 #'PropertyParm'{name = "a", 1306 value = ["keywds:" ++ Keywords]}; 1307encode_pp_attribute_keywds(BadKeywords) -> 1308 error({invalid_keywds_keywords, BadKeywords}). 1309 1310 1311encode_pp_attribute_tool(NameAndVersion) when is_list(NameAndVersion) -> 1312 ?d("encode_pp_attribute_tool -> entry with" 1313 "~n NameAndVersion: ~p", [NameAndVersion]), 1314 #'PropertyParm'{name = "a", 1315 value = ["tool:" ++ NameAndVersion]}; 1316encode_pp_attribute_tool(BadNameAndVersion) -> 1317 error({invalid_tool_name_and_version, BadNameAndVersion}). 1318 1319 1320encode_pp_attribute_ptime(PacketTime) when is_integer(PacketTime) -> 1321 ?d("encode_pp_attribute_ptime -> entry with" 1322 "~n PacketTime: ~w", [PacketTime]), 1323 #'PropertyParm'{name = "a", 1324 value = ["ptime:" ++ integer_to_list(PacketTime)]}; 1325encode_pp_attribute_ptime(BadPT) -> 1326 error({invalid_ptime_packet_time, BadPT}). 1327 1328 1329encode_pp_attribute_maxptime(MaxPacketTime) when is_integer(MaxPacketTime) -> 1330 ?d("encode_pp_attribute_maxptime -> entry with" 1331 "~n MaxPacketTime: ~w", [MaxPacketTime]), 1332 #'PropertyParm'{name = "a", 1333 value = ["maxptime:" ++ integer_to_list(MaxPacketTime)]}; 1334encode_pp_attribute_maxptime(BadMPT) -> 1335 error({invalid_maxptime_maximum_packet_time, BadMPT}). 1336 1337 1338encode_pp_attribute_rtpmap(Payload0, EncName0, ClockRate0, EncPar0) -> 1339 ?d("encode_pp_attribute_rtpmap -> entry with" 1340 "~n Payload0: ~p" 1341 "~n EncName0: ~p" 1342 "~n ClockRate0: ~p" 1343 "~n EncPar0: ~p", [Payload0, EncName0, ClockRate0, EncPar0]), 1344 Payload = encode_rtpmap_payload(Payload0), 1345 EncName = encode_rtpmap_encoding_name(EncName0), 1346 ClockRate = encode_rtpmap_clockrate(ClockRate0), 1347 EncPar = encode_rtpmap_encoding_parms(EncPar0), 1348 Val = "rtpmap:" ++ Payload ++ " " ++ 1349 EncName ++ "/" ++ ClockRate ++ EncPar, 1350 #'PropertyParm'{name = "a", 1351 value = [Val]}. 1352 1353encode_rtpmap_payload(Payload) when is_integer(Payload) -> 1354 integer_to_list(Payload); 1355encode_rtpmap_payload(BadPayload) -> 1356 error({invalid_rtpmap_payload, BadPayload}). 1357 1358encode_rtpmap_encoding_name(EncName) when is_list(EncName) -> 1359 EncName; 1360encode_rtpmap_encoding_name(BadEncName) -> 1361 error({invalid_rtpmap_encoding_name, BadEncName}). 1362 1363encode_rtpmap_clockrate(ClockRate) when is_integer(ClockRate) -> 1364 integer_to_list(ClockRate); 1365encode_rtpmap_clockrate(BadClockRate) -> 1366 error({invalid_rtpmap_clockrate, BadClockRate}). 1367 1368encode_rtpmap_encoding_parms(EncPar) when is_list(EncPar) -> 1369 F = fun(EP, Acc) when is_list(EP) -> 1370 Acc ++ "/" ++ EP; 1371 (BadEP, Acc) -> 1372 error({invalid_rtpmap_encoding_parms, {BadEP, Acc}}) 1373 end, 1374 lists:foldl(F, [], EncPar); 1375encode_rtpmap_encoding_parms(BadEncPar) -> 1376 error({invalid_rtpmap_encoding_parms, BadEncPar}). 1377 1378 1379encode_pp_attribute_orient(Orientation0) -> 1380 ?d("encode_pp_attribute_orient -> entry with" 1381 "~n Orientation0: ~w", [Orientation0]), 1382 Orientation = encode_attribute_orientation(Orientation0), 1383 #'PropertyParm'{name = "a", 1384 value = ["orient:" ++ Orientation]}. 1385 1386 1387encode_pp_attribute_type(CType) when is_list(CType) -> 1388 ?d("encode_pp_attribute_type -> entry with" 1389 "~n CType: ~p", [CType]), 1390 #'PropertyParm'{name = "a", 1391 value = ["type:" ++ CType]}; 1392encode_pp_attribute_type(BadCType) -> 1393 error({invalid_type_conf_type, BadCType}). 1394 1395 1396encode_pp_attribute_charset(CharSet) when is_list(CharSet) -> 1397 ?d("encode_pp_attribute_charset -> entry with" 1398 "~n CharSet: ~p", [CharSet]), 1399 #'PropertyParm'{name = "a", 1400 value = ["charset:" ++ CharSet]}; 1401encode_pp_attribute_charset(BadCharSet) -> 1402 error({invalid_charset_char_set, BadCharSet}). 1403 1404 1405encode_pp_attribute_sdplang(SdpLang) when is_list(SdpLang) -> 1406 ?d("encode_pp_attribute_sdplang -> entry with" 1407 "~n SdpLang: ~p", [SdpLang]), 1408 #'PropertyParm'{name = "a", 1409 value = ["sdplang:" ++ SdpLang]}; 1410encode_pp_attribute_sdplang(BadSdpLang) -> 1411 error({invalid_sdplang_tag, BadSdpLang}). 1412 1413 1414encode_pp_attribute_lang(Lang) when is_list(Lang) -> 1415 ?d("encode_pp_attribute_lang -> entry with" 1416 "~n Lang: ~p", [Lang]), 1417 #'PropertyParm'{name = "a", 1418 value = ["lang:" ++ Lang]}; 1419encode_pp_attribute_lang(BadLang) -> 1420 error({invalid_lang_tag, BadLang}). 1421 1422 1423encode_pp_attribute_framerate(FrameRate) when is_list(FrameRate) -> 1424 ?d("encode_pp_attribute_framerate -> entry with" 1425 "~n FrameRate: ~p", [FrameRate]), 1426 #'PropertyParm'{name = "a", 1427 value = ["framerate:" ++ FrameRate]}; 1428encode_pp_attribute_framerate(BadFrameRate) -> 1429 error({invalid_framerate_frame_rate, BadFrameRate}). 1430 1431 1432encode_pp_attribute_quality(Quality) when is_integer(Quality) -> 1433 ?d("encode_pp_attribute_quality -> entry with" 1434 "~n Quality: ~w", [Quality]), 1435 #'PropertyParm'{name = "a", 1436 value = ["quality:" ++ integer_to_list(Quality)]}; 1437encode_pp_attribute_quality(BadQ) -> 1438 error({invalid_quality_quality, BadQ}). 1439 1440 1441encode_pp_attribute_fmtp(Fmt0, Params0) -> 1442 ?d("encode_pp_attribute_rtpmap -> entry with" 1443 "~n Fmt0: ~p" 1444 "~n Params0: ~p", [Fmt0, Params0]), 1445 Fmt = encode_fmtp_format(Fmt0), 1446 Params = encode_fmtp_param(Params0), 1447 Val = "fmtp:" ++ Fmt ++ " " ++ Params, 1448 #'PropertyParm'{name = "a", 1449 value = [Val]}. 1450 1451encode_fmtp_format(Fmt) when is_list(Fmt) -> 1452 Fmt; 1453encode_fmtp_format(BadFmt) -> 1454 error({invalid_fmtp_format, BadFmt}). 1455 1456encode_fmtp_param(Param) when is_list(Param) -> 1457 Param; 1458encode_fmtp_param(BadParam) -> 1459 error({invalid_fmtp_param, BadParam}). 1460 1461 1462encode_pp_attribute(Attr, undefined) when is_list(Attr) -> 1463 ?d("encode_pp_attribute_rtpmap -> entry with" 1464 "~n Attr: ~p", [Attr]), 1465 #'PropertyParm'{name = "a", 1466 value = [Attr]}; 1467encode_pp_attribute(Attr, Value) when is_list(Attr) and is_list(Value) -> 1468 ?d("encode_pp_attribute_rtpmap -> entry with" 1469 "~n Attr: ~p" 1470 "~n Value: ~p", [Attr, Value]), 1471 #'PropertyParm'{name = "a", 1472 value = [Attr ++ ":" ++ Value]}; 1473encode_pp_attribute(BadAttr, BadAttrValue) -> 1474 error({invalid_attribute, {BadAttr, BadAttrValue}}). 1475 1476 1477%% ===== Media Announcements ===== 1478%% 1479decode_pp_media_announcement(Value) -> 1480 case string:tokens(Value, " \t") of 1481 [Media0, PortInfo, Transport | FMT] -> 1482 Media = 1483 case tolower(Media0) of 1484 "audio" -> audio; 1485 "video" -> video; 1486 "application" -> application; 1487 "data" -> data; 1488 "control" -> control; 1489 _ -> Media0 1490 end, 1491 {Port, NoOfPorts} = 1492 case string:tokens(PortInfo, "/") of 1493 [P1, NP] -> 1494 {s2i(P1, invalid_media_announcement_port), 1495 s2i(NP, invalid_media_announcement_nof_ports)}; 1496 [P2] -> 1497 {s2i(P2, invalid_media_announcement_port), 1498 undefined}; 1499 Err -> 1500 invalid_pp(mnta_port_info, Value, Err) 1501 end, 1502 SDP = #megaco_sdp_m{media = Media, 1503 port = Port, 1504 num_ports = NoOfPorts, 1505 transport = Transport, 1506 fmt_list = FMT}, 1507 {ok, SDP}; 1508 Err -> 1509 invalid_pp(media_name_transp_addr, Value, Err) 1510 end. 1511 1512 1513encode_pp_media_announcement(Media0, Port0, undefined, Transport0, FMT0) -> 1514 ?d("encode_pp_media_announcement -> entry with" 1515 "~n Media0: ~p" 1516 "~n Port0: ~p" 1517 "~n Transport0: ~p" 1518 "~n FMT0: ~p", [Media0, Port0, Transport0, FMT0]), 1519 Media = encode_media_announcement_media(Media0), 1520 Port = encode_media_announcement_port(Port0), 1521 Transport = encode_media_announcement_transport(Transport0), 1522 FMT = encode_media_announcement_fmt_list(FMT0), 1523 do_encode_pp_media_announcement(Media, Port, "", Transport, FMT); 1524encode_pp_media_announcement(Media0, Port0, NumPorts0, Transport0, FMT0) -> 1525 ?d("encode_pp_media_announcement -> entry with" 1526 "~n Media0: ~p" 1527 "~n Port0: ~p" 1528 "~n NumPorts0: ~p" 1529 "~n Transport0: ~p" 1530 "~n FMT0: ~p", [Media0, Port0, NumPorts0, Transport0, FMT0]), 1531 Media = encode_media_announcement_media(Media0), 1532 Port = encode_media_announcement_port(Port0), 1533 NumPorts = encode_media_announcement_num_port(NumPorts0), 1534 Transport = encode_media_announcement_transport(Transport0), 1535 FMT = encode_media_announcement_fmt_list(FMT0), 1536 do_encode_pp_media_announcement(Media, Port, NumPorts, Transport, FMT). 1537 1538do_encode_pp_media_announcement(Media, Port, NumOfPorts, Transport, FMT) -> 1539 Val = Media ++ " " ++ Port ++ NumOfPorts ++ " " ++ Transport ++ FMT, 1540 #'PropertyParm'{name = "m", 1541 value = [Val]}. 1542 1543encode_media_announcement_media(Media) when is_atom(Media) -> 1544 MaMedia = [audio, video, application, data, control], 1545 case lists:member(Media, MaMedia) of 1546 true -> 1547 atom_to_list(Media); 1548 false -> 1549 error({invalid_media_announcement_media, Media}) 1550 end; 1551encode_media_announcement_media(Media) when is_list(Media) -> 1552 Media; 1553encode_media_announcement_media(BadMedia) -> 1554 error({invalid_media_announcement_media, BadMedia}). 1555 1556encode_media_announcement_port(Port) when is_integer(Port) -> 1557 integer_to_list(Port); 1558encode_media_announcement_port(BadPort) -> 1559 error({invalid_media_announcement_port, BadPort}). 1560 1561encode_media_announcement_num_port(NumPort) when is_integer(NumPort) -> 1562 "/" ++ integer_to_list(NumPort); 1563encode_media_announcement_num_port(BadNumPort) -> 1564 error({invalid_media_announcement_num_port, BadNumPort}). 1565 1566encode_media_announcement_transport(Transport) when is_list(Transport) -> 1567 Transport; 1568encode_media_announcement_transport(BadTransport) -> 1569 error({invalid_media_announcement_transport, BadTransport}). 1570 1571encode_media_announcement_fmt_list(FmtList) when is_list(FmtList) -> 1572 F = fun(FMT, Acc) when is_list(FMT) -> 1573 Acc ++ " " ++ FMT; 1574 (BadFMT, Acc) -> 1575 error({invalid_media_announcement_fmt_list, {BadFMT, Acc}}) 1576 end, 1577 lists:foldl(F, [], FmtList); 1578encode_media_announcement_fmt_list(BadFmtList) -> 1579 error({invalid_media_announcement_fmt_list, BadFmtList}). 1580 1581 1582decode_network_type(NT) when is_list(NT) -> 1583 case tolower(NT) of 1584 "in" -> in; 1585 _ -> NT 1586 end. 1587 1588encode_network_type(in) -> "IN"; 1589encode_network_type(NT) when is_list(NT) -> NT; 1590encode_network_type(Bad) -> 1591 {error, {invalid_network_type, Bad}}. 1592 1593 1594decode_address_type(AT) when is_list(AT) -> 1595 case tolower(AT) of 1596 "ip4" -> ip4; 1597 "ip6" -> ip6; 1598 _ -> AT 1599 end. 1600 1601encode_address_type(ip4) -> "IP4"; 1602encode_address_type(ip6) -> "IP6"; 1603encode_address_type(AT) when is_list(AT) -> 1604 case toupper(AT) of 1605 "IP4" -> "IP4"; 1606 "IP6" -> "IP6"; 1607 _ -> AT 1608 end; 1609encode_address_type(Crap) -> 1610 {error, {invalid_address_type, Crap}}. 1611 1612 1613s2i(S, E) -> 1614 case (catch list_to_integer(S)) of 1615 I when is_integer(I) -> 1616 I; 1617 _ -> 1618 error({E, S}) 1619 end. 1620 1621-define(LOWER(Char), 1622 if 1623 Char >= $A, Char =< $Z -> 1624 Char - ($A - $a); 1625 true -> 1626 Char 1627 end). 1628tolower(Chars) -> 1629 [?LOWER(Char) || Char <- Chars]. 1630 1631-define(UPPER(Char), 1632 if 1633 Char >= $a, Char =< $z -> 1634 Char + ($A - $a); 1635 true -> 1636 Char 1637 end). 1638toupper(Chars) -> 1639 [?UPPER(Char) || Char <- Chars]. 1640 1641invalid_pp(What, Value, Error) -> 1642 {error, {invalid_PropertyParm, {What, Value, Error}}}. 1643 1644error(Reason) -> 1645 throw({error, Reason}). 1646 1647