%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2001-2011. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at %% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, software %% distributed under the License is distributed on an "AS IS" BASIS, %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. %% %% %CopyrightEnd% %% %% %%---------------------------------------------------------------------- %% Purpose: RFC 4566 %%---------------------------------------------------------------------- -module(megaco_sdp). %%---------------------------------------------------------------------- %% Include files %%---------------------------------------------------------------------- -include_lib("megaco/include/megaco.hrl"). -include_lib("megaco/src/app/megaco_internal.hrl"). -include_lib("megaco/include/megaco_message_v1.hrl"). -include_lib("megaco/include/megaco_sdp.hrl"). %%---------------------------------------------------------------------- %% External exports %%---------------------------------------------------------------------- %% Avoid warning for local function error/1 clashing with autoimported BIF. -compile({no_auto_import,[error/1]}). -export([ decode/1, encode/1, get_sdp_record_from_PropertyGroup/2 ]). %%---------------------------------------------------------------------- %% Internal exports %%---------------------------------------------------------------------- %%---------------------------------------------------------------------- %% Macros %%---------------------------------------------------------------------- %%---------------------------------------------------------------------- %% Records %%---------------------------------------------------------------------- %%====================================================================== %% External functions %%====================================================================== %% --------------------------------------------------------------------- %% decode(PP) -> {ok, SDP} | {error, Reason} %% %% This function performs the following conversion: %% property_parm() -> sdp() %% property_group() -> sdp_property_group() %% property_groups() -> sdp_property_groups() %% %% --------------------------------------------------------------------- decode(SDP) -> case (catch do_decode(SDP)) of {ok, _} = OK -> OK; {error, _} = ERR -> ERR; {'EXIT', Reason} -> {error, {exit, Reason}}; CRAP -> {error, {crap, CRAP}} end. do_decode(PP) when is_record(PP, 'PropertyParm') -> decode_PropertyParm(PP); do_decode([PP|_] = PG) when is_record(PP, 'PropertyParm') -> decode_PropertyGroup(PG); do_decode([H|_] = PGs) when is_list(H) -> decode_PropertyGroups(PGs); do_decode(asn1_NOVALUE = V) -> {ok, V}; do_decode(Bad) -> {error, {bad_sdp, Bad}}. %% --------------------------------------------------------------------- %% encode(SDPs) -> {ok, PP} | {error, Reason} %% %% This function performs the following conversion: %% sdp() -> property_parm() %% sdp_property_group() -> property_group() %% sdp_property_groups() -> property_groups() %% %% --------------------------------------------------------------------- encode(SDP) -> case (catch do_encode(SDP)) of {ok, _} = OK -> OK; {error, _} = ERR -> ERR; {'EXIT', Reason} -> {error, {exit, Reason}}; CRAP -> {error, {crap, CRAP}} end. do_encode(SDP) when is_tuple(SDP) -> {ok, encode_PropertyParm(SDP)}; do_encode([SDP|_] = PG) when is_tuple(SDP) -> encode_PropertyGroup(PG); do_encode([H|_] = PGs) when is_list(H) -> encode_PropertyGroups(PGs); do_encode(asn1_NOVALUE = V) -> {ok, V}. %%----------------------------------------------------------------- %% Generate sdp records from PropertyParm records %%----------------------------------------------------------------- decode_PropertyGroups(PGs) -> decode_PropertyGroups(PGs, []). decode_PropertyGroups([], DecodedPGs) -> {ok, lists:reverse(DecodedPGs)}; decode_PropertyGroups([PG | PGs], DecodedPGs) -> {ok, DecodedPG} = decode_PropertyGroup(PG), decode_PropertyGroups(PGs, [DecodedPG | DecodedPGs]). decode_PropertyGroup(PG) -> {ok, decode_PropertyGroup(PG, [])}. decode_PropertyGroup([], Acc) -> lists:reverse(Acc); decode_PropertyGroup([PP | PG], Acc) -> case (catch decode_PropertyParm(PP)) of {ok, PP2} -> decode_PropertyGroup(PG, [PP2 | Acc]); {error, Reason} -> decode_PropertyGroup(PG, [{PP, Reason} | Acc]); Error -> decode_PropertyGroup(PG, [{PP, Error} | Acc]) end. %% ===== Protocol Version ===== %% decode_PropertyParm(#'PropertyParm'{name = "v", value = [V], extraInfo = asn1_NOVALUE}) -> decode_pp_protocol_version(V); %% ===== Origin ===== %% decode_PropertyParm(#'PropertyParm'{name = "o", value = [V], extraInfo = asn1_NOVALUE}) -> decode_pp_origin(V); %% ===== Session Name ===== %% decode_PropertyParm(#'PropertyParm'{name = "s", value = [V], extraInfo = asn1_NOVALUE}) -> decode_pp_session_name(V); %% ===== Session and Media Information ===== %% decode_PropertyParm(#'PropertyParm'{name = "i", value = [V], extraInfo = asn1_NOVALUE}) -> decode_pp_session_media_id(V); %% ===== URI ===== %% decode_PropertyParm(#'PropertyParm'{name = "u", value = [V], extraInfo = asn1_NOVALUE}) -> decode_pp_uri(V); %% ===== Email Address and Phone Number ===== %% decode_PropertyParm(#'PropertyParm'{name = "e", value = [V], extraInfo = asn1_NOVALUE}) -> decode_pp_email(V); decode_PropertyParm(#'PropertyParm'{name = "p", value = [V], extraInfo = asn1_NOVALUE}) -> decode_pp_phone(V); %% ===== Connection Data ===== %% decode_PropertyParm(#'PropertyParm'{name = "c", value = [V], extraInfo = asn1_NOVALUE}) -> decode_pp_connection_data(V); %% ===== Bandwidth ===== %% decode_PropertyParm(#'PropertyParm'{name = "b", value = [V], extraInfo = asn1_NOVALUE}) -> decode_pp_bandwidth(V); %% ===== Times, Repeat Times and Time Zones ===== %% decode_PropertyParm(#'PropertyParm'{name = "t", value = [V], extraInfo = asn1_NOVALUE }) -> decode_pp_times(V); decode_PropertyParm(#'PropertyParm'{name = "r", value = [V], extraInfo = asn1_NOVALUE}) -> decode_pp_rtimes(V); decode_PropertyParm(#'PropertyParm'{name = "z", value = [V], extraInfo = asn1_NOVALUE}) -> decode_pp_tzones(V); %% ===== Encryption Keys ===== %% decode_PropertyParm(#'PropertyParm'{name = "k", value = [V], extraInfo = asn1_NOVALUE}) -> decode_pp_encryption_keys(V); %% ===== Attributes ===== %% decode_PropertyParm(#'PropertyParm'{name = "a", value = [V], extraInfo = asn1_NOVALUE}) -> decode_pp_attribute(V); %% ===== Media Announcements ===== %% decode_PropertyParm(#'PropertyParm'{name = "m", value = [V], extraInfo = asn1_NOVALUE}) -> decode_pp_media_announcement(V); decode_PropertyParm(_PP) -> ?d("decode_PropertyParm -> entry with" "~n _PP: ~p", [_PP]), {error, undefined_PropertyParm}. %%----------------------------------------------------------------- %% Generate PropertyParm records from sdp records %%----------------------------------------------------------------- encode_PropertyGroups(PGs) -> encode_PropertyGroups(PGs, []). encode_PropertyGroups([], Acc) -> {ok, lists:reverse(Acc)}; encode_PropertyGroups([PG | PGs], Acc) -> {ok, EncodedPG} = encode_PropertyGroup(PG), encode_PropertyGroups(PGs, [EncodedPG | Acc]). encode_PropertyGroup(PG) -> encode_PropertyGroup(PG, []). encode_PropertyGroup([], Acc) -> {ok, lists:reverse(Acc)}; encode_PropertyGroup([PP | PG], Acc) -> EncodedPP = encode_PropertyParm(PP), encode_PropertyGroup(PG, [EncodedPP | Acc]). %% ===== Protocol Version ===== %% encode_PropertyParm(#megaco_sdp_v{version = Version}) -> encode_pp_protocol_version(Version); %% ===== Origin ===== %% encode_PropertyParm(#megaco_sdp_o{user_name = User, session_id = SessionId, version = Version, network_type = Network, address_type = AddrType, address = Addr}) -> encode_pp_origin(User, SessionId, Version, Network, AddrType, Addr); %% ===== Session Name ===== %% encode_PropertyParm(#megaco_sdp_s{name = Name}) -> encode_pp_session_name(Name); %% ===== Session and Media Information ===== %% encode_PropertyParm(#megaco_sdp_i{session_descriptor = SD}) -> encode_pp_session_media_id(SD); %% ===== URI ===== %% encode_PropertyParm(#megaco_sdp_u{uri = URI}) -> encode_pp_uri(URI); %% ===== Email Address and Phone Number ===== %% encode_PropertyParm(#megaco_sdp_e{email = Email}) -> encode_pp_email(Email); encode_PropertyParm(#megaco_sdp_p{phone_number = Num}) -> encode_pp_phone(Num); %% ===== Connection Data ===== %% encode_PropertyParm(#megaco_sdp_c{network_type = NetType, address_type = AddressType, connection_addr = ConnectionAddr}) -> encode_pp_connection_data(NetType, AddressType, ConnectionAddr); %% ===== Bandwidth ===== %% encode_PropertyParm(#megaco_sdp_b{bwtype = BwType, bandwidth = Bandwidth}) -> encode_pp_bandwidth(BwType, Bandwidth); %% ===== Times, Repeat Times and Time Zones ===== %% encode_PropertyParm(#megaco_sdp_t{start = Start, stop = Stop}) -> encode_pp_times(Start, Stop); encode_PropertyParm(#megaco_sdp_r{repeat_interval = Repeat, active_duration = Duration, list_of_offsets = ListOfOffsets}) -> encode_pp_rtimes(Repeat, Duration, ListOfOffsets); encode_PropertyParm(#megaco_sdp_z{list_of_adjustments = LOA}) -> encode_pp_tzones(LOA); %% ===== Encryption Keys ===== %% encode_PropertyParm(#megaco_sdp_k{method = Method, encryption_key = EncryptionKey}) -> encode_pp_encryption_keys(Method, EncryptionKey); %% ===== Attributes ===== %% encode_PropertyParm(#megaco_sdp_a_cat{category = Category}) -> encode_pp_attribute_cat(Category); encode_PropertyParm(#megaco_sdp_a_keywds{keywords = Keywords}) -> encode_pp_attribute_keywds(Keywords); encode_PropertyParm(#megaco_sdp_a_tool{name_and_version = NameAndVersion}) -> encode_pp_attribute_tool(NameAndVersion); encode_PropertyParm(#megaco_sdp_a_ptime{packet_time = PacketTime}) -> encode_pp_attribute_ptime(PacketTime); encode_PropertyParm( #megaco_sdp_a_maxptime{maximum_packet_time = MaxPacketTime}) -> encode_pp_attribute_maxptime(MaxPacketTime); encode_PropertyParm(#megaco_sdp_a_rtpmap{payload_type = Payload, encoding_name = EncName, clock_rate = ClockRate, encoding_parms = EncPar}) -> encode_pp_attribute_rtpmap(Payload, EncName, ClockRate, EncPar); encode_PropertyParm(#megaco_sdp_a_orient{orientation = Orientation}) -> encode_pp_attribute_orient(Orientation); encode_PropertyParm(#megaco_sdp_a_type{conf_type = CType}) -> encode_pp_attribute_type(CType); encode_PropertyParm(#megaco_sdp_a_charset{char_set = CharSet}) -> encode_pp_attribute_charset(CharSet); encode_PropertyParm(#megaco_sdp_a_sdplang{tag = Tag}) -> encode_pp_attribute_sdplang(Tag); encode_PropertyParm(#megaco_sdp_a_lang{tag = Tag}) -> encode_pp_attribute_lang(Tag); encode_PropertyParm(#megaco_sdp_a_framerate{frame_rate = FrameRate}) -> encode_pp_attribute_framerate(FrameRate); encode_PropertyParm(#megaco_sdp_a_quality{quality = Quality}) -> encode_pp_attribute_quality(Quality); encode_PropertyParm(#megaco_sdp_a_fmtp{format = Fmt, param = Params}) -> encode_pp_attribute_fmtp(Fmt, Params); encode_PropertyParm(#megaco_sdp_a{attribute = Attr, value = Value}) -> encode_pp_attribute(Attr, Value); %% ===== Media Announcements ===== %% encode_PropertyParm(#megaco_sdp_m{media = Media, port = Port, num_ports = NOP, transport = Transport, fmt_list = FMT}) -> encode_pp_media_announcement(Media, Port, NOP, Transport, FMT); %% This is a "manually" encoded PropertyParm, leave it as is. %% encode_PropertyParm(PP) when is_record(PP, 'PropertyParm') -> PP; %% Bad data encode_PropertyParm(SDP) -> error({unknown_sdp, SDP}). %%----------------------------------------------------------------- %% Func: get_sdp_record_from_PropertGroup/2 %% Description: Get all sdp records of a certain type from a %% property group %%----------------------------------------------------------------- get_sdp_record_from_PropertyGroup(Type, PG) when is_atom(Type) and is_list(PG) -> F = fun(R) -> not is_pg_record(Type, R) end, lists:filter(F, PG). is_pg_record(v, R) when is_record(R, megaco_sdp_v) -> true; is_pg_record(c, R) when is_record(R, megaco_sdp_c) -> true; is_pg_record(m, R) when is_record(R, megaco_sdp_m) -> true; is_pg_record(o, R) when is_record(R, megaco_sdp_o) -> true; is_pg_record(a, R) when is_record(R, megaco_sdp_a) -> true; is_pg_record(a, R) when is_record(R, megaco_sdp_a_ptime) -> true; is_pg_record(a, R) when is_record(R, megaco_sdp_a_rtpmap) -> true; is_pg_record(b, R) when is_record(R, megaco_sdp_b) -> true; is_pg_record(t, R) when is_record(R, megaco_sdp_t) -> true; is_pg_record(r, R) when is_record(R, megaco_sdp_r) -> true; is_pg_record(z, R) when is_record(R, megaco_sdp_z) -> true; is_pg_record(k, R) when is_record(R, megaco_sdp_k) -> true; is_pg_record(s, R) when is_record(R, megaco_sdp_s) -> true; is_pg_record(i, R) when is_record(R, megaco_sdp_i) -> true; is_pg_record(u, R) when is_record(R, megaco_sdp_u) -> true; is_pg_record(e, R) when is_record(R, megaco_sdp_e) -> true; is_pg_record(p, R) when is_record(R, megaco_sdp_p) -> true; is_pg_record(_, _) -> false. %%====================================================================== %% Internal functions %%====================================================================== %% ===== Protocol Version ===== %% decode_pp_protocol_version(Value) when is_list(Value) -> ?d("decode_pp_protocol_version -> entry with" "~n Value: ~p", [Value]), Version = s2i(Value, invalid_protocol_version), ?d("decode_pp_protocol_version -> entry with" "~n Version: ~w", [Version]), decode_pp_protocol_version(Version); decode_pp_protocol_version(Version) when is_integer(Version) -> ?d("decode_pp_protocol_version -> entry with" "~n Version: ~w", [Version]), {ok, #megaco_sdp_v{version = Version}}. encode_pp_protocol_version(Version) when is_integer(Version) -> ?d("encode_pp_protocol_version -> entry with" "~n Version: ~w", [Version]), #'PropertyParm'{name = "v", value = [integer_to_list(Version)]}; encode_pp_protocol_version(Version) -> error({invalid_protocol_version, Version}). %% ===== Origin ===== %% decode_pp_origin(Value) -> ?d("decode_pp_origin -> entry with" "~n Value: ~p", [Value]), case string:tokens(Value, " \t") of [User, SessId, SessVersion, NetType, AddrType, UnicastAddress] -> ?d("decode_pp_origin -> entry with" "~n User: ~p" "~n SessionId: ~p" "~n Version: ~p" "~n NetType: ~p" "~n AddrType: ~p" "~n UnicastAddress: ~p", [User, SessId, SessVersion, NetType, AddrType, UnicastAddress]), F = fun(X, R) -> case (catch list_to_integer(X)) of I when is_integer(I) -> I; _ -> error({invalid_origin, {R, X}}) end end, SID = F(SessId, sess_id), V = F(SessVersion, sess_version), SDP = #megaco_sdp_o{user_name = User, session_id = SID, version = V, network_type = decode_network_type(NetType), address_type = decode_address_type(AddrType), address = UnicastAddress}, {ok, SDP}; Err -> ?d("decode_pp_origin -> " "~n Err: ~p", [Err]), invalid_pp(origin, Value, Err) end. encode_pp_origin(User0, SessionId0, SessVersion0, NetType0, AddrType0, UnicastAddr0) -> ?d("do_encode_pp_origin -> entry with" "~n User0: ~p" "~n SessionId0: ~p" "~n SessVersion0: ~p" "~n NetType0: ~p" "~n AddrType0: ~p" "~n UnicastAddr0: ~p", [User0, SessionId0, SessVersion0, NetType0, AddrType0, UnicastAddr0]), User = encode_origin_user(User0), SessionId = encode_origin_session_id(SessionId0), SessVersion = encode_origin_sess_version(SessVersion0), NetType = encode_origin_network_type(NetType0), AddrType = encode_origin_address_type(AddrType0), UnicastAddr = encode_origin_unicast_address(UnicastAddr0), #'PropertyParm'{name = "o", value = [ User ++ " " ++ SessionId ++ " " ++ SessVersion ++ " " ++ NetType ++ " " ++ AddrType ++ " " ++ UnicastAddr ]}. encode_origin_user(User) when is_list(User) -> User; encode_origin_user(BadUser) -> error({invalid_origin_user, BadUser}). encode_origin_session_id(SID) when is_integer(SID) -> integer_to_list(SID); encode_origin_session_id(BadSID) -> error({invalid_origin_session_id, BadSID}). encode_origin_sess_version(SessVersion) when is_integer(SessVersion) -> integer_to_list(SessVersion); encode_origin_sess_version(BadSessVersion) -> error({invalid_origin_sess_version, BadSessVersion}). encode_origin_network_type(NT) -> case (catch encode_network_type(NT)) of {error, _} -> error({invalid_origin_network_type, NT}); Val -> Val end. encode_origin_address_type(AT) -> case (catch encode_address_type(AT)) of {error, _} -> error({invalid_origin_address_type, AT}); Val -> Val end. encode_origin_unicast_address(UnicastAddr) when is_list(UnicastAddr) -> UnicastAddr; encode_origin_unicast_address(BadUnicastAddr) -> error({invalid_origin_unicast_address, BadUnicastAddr}). %% ===== Session Name ===== %% decode_pp_session_name(Value) -> ?d("decode_pp_session_name -> entry with" "~n Value: ~p", [Value]), {ok, #megaco_sdp_s{name = Value}}. encode_pp_session_name(Name) when is_list(Name) -> ?d("encode_pp_session_name -> entry with" "~n Name: '~s'", [Name]), #'PropertyParm'{name = "s", value = [Name]}; encode_pp_session_name(BadName) -> error({invalid_session_name, BadName}). %% ===== Session and Media Information ===== %% decode_pp_session_media_id(Value) -> ?d("decode_pp_session_media_id -> entry with" "~n Value: ~p", [Value]), {ok, #megaco_sdp_i{session_descriptor = Value}}. encode_pp_session_media_id(SD) when is_list(SD) -> ?d("encode_pp_session_media_id -> entry with" "~n SD: '~s'", [SD]), #'PropertyParm'{name = "i", value = [SD]}; encode_pp_session_media_id(BadSD) -> error({invalid_session_media_id, BadSD}). %% ===== URI ===== %% decode_pp_uri(Value) -> ?d("decode_pp_uri -> entry with" "~n Value: ~p", [Value]), {ok, #megaco_sdp_u{uri = Value}}. encode_pp_uri(URI) when is_list(URI) -> ?d("encode_pp_uri -> entry with" "~n URI: ~p", [URI]), #'PropertyParm'{name = "u", value = [URI]}; encode_pp_uri(BadUri) -> error({invalid_uri, BadUri}). %% ===== Email Address and Phone Number ===== %% decode_pp_email(Value) -> ?d("decode_pp_email -> entry with" "~n Value: ~p", [Value]), {ok, #megaco_sdp_e{email = Value}}. encode_pp_email(Email) when is_list(Email) -> ?d("encode_pp_email -> entry with" "~n Email: ~p", [Email]), #'PropertyParm'{name = "e", value = [Email]}; encode_pp_email(BadEmail) -> error({invalid_email, BadEmail}). decode_pp_phone(Value) -> ?d("decode_pp_phone -> entry with" "~n Value: ~p", [Value]), {ok, #megaco_sdp_p{phone_number = Value}}. encode_pp_phone(Phone) when is_list(Phone) -> ?d("encode_pp_phone -> entry with" "~n Phone: ~p", [Phone]), #'PropertyParm'{name = "p", value = [Phone]}; encode_pp_phone(BadPhone) -> error({invalid_phone, BadPhone}). %% ===== Connection Data ===== %% decode_pp_connection_data(Value) -> ?d("decode_pp_connection_data -> entry with" "~n Value: ~p", [Value]), case string:tokens(Value, " \t") of [NetType, AddrType, ConnectionAddr] -> ?d("decode_pp_connection_data -> " "~n NetType: ~p" "~n AddrType: ~p" "~n ConnectionAddr: ~p", [NetType, AddrType, ConnectionAddr]), NT = decode_network_type(NetType), AT = decode_address_type(AddrType), case AT of ip4 -> ?d("decode_pp_connection_data -> ip4", []), ConnAddr = case string:tokens(ConnectionAddr, "\/") of [Base, TtlStr, NumOfAddrs] -> ?d("decode_pp_connection_data -> " "~n Base: ~p" "~n TtlStr: ~p" "~n NumOfAddrs:~p", [Base, TtlStr, NumOfAddrs]), TTL = s2i(TtlStr, invalid_connection_data_ttl), ?d("decode_pp_connection_data -> TTL: ~p", [TTL]), NOA = s2i(NumOfAddrs, invalid_connection_data_conn_addr_num_of), ?d("decode_pp_connection_data -> NOA: ~p", [NOA]), #megaco_sdp_c_conn_addr{base = Base, ttl = TTL, num_of = NOA}; [Base, TtlStr] -> ?d("decode_pp_connection_data -> " "~n Base: ~p" "~n TtlStr: ~p", [Base, TtlStr]), TTL = s2i(TtlStr, invalid_connection_data_conn_addr_ttl), ?d("decode_pp_connection_data -> TTL: ~p", [TTL]), #megaco_sdp_c_conn_addr{base = Base, ttl = TTL}; [Base] -> Base end, ?d("decode_pp_connection_data -> " "~n ConnAddr: ~p", [ConnAddr]), SDP = #megaco_sdp_c{network_type = NT, address_type = AT, connection_addr = ConnAddr}, {ok, SDP}; ip6 -> ?d("decode_pp_connection_data -> ip6", []), SDP = #megaco_sdp_c{network_type = NT, address_type = AT, connection_addr = ConnectionAddr}, {ok, SDP}; _ -> SDP = #megaco_sdp_c{network_type = NT, address_type = AT, connection_addr = ConnectionAddr}, {ok, SDP} end; Err -> invalid_pp(connection_data, Value, Err) end. encode_pp_connection_data(NetType0, AddrType0, ConnAddr0) -> ?d("encode_pp_connection_data -> entry with" "~n NetType0: ~p" "~n AddrType0: ~p" "~n ConnAddr0: ~p", [NetType0, AddrType0, ConnAddr0]), NetType = encode_conn_data_network_type(NetType0), AddrType = encode_conn_data_address_type(AddrType0), ConnAddr = encode_conn_data_conn_addr(AddrType0, ConnAddr0), Val = NetType ++ " " ++ AddrType ++ " " ++ ConnAddr, #'PropertyParm'{name = "c", value = [Val]}. encode_conn_data_network_type(NT) -> case (catch encode_network_type(NT)) of {error, _} -> error({invalid_connection_data_network_type, NT}); Val -> Val end. encode_conn_data_address_type(AT) -> case (catch encode_address_type(AT)) of {error, _} -> error({invalid_connection_data_address_type, AT}); Val -> Val end. encode_conn_data_conn_addr(_, CA) when is_list(CA) -> CA; encode_conn_data_conn_addr(ip4, CA) when is_record(CA, megaco_sdp_c_conn_addr) -> encode_conn_data_conn_addr(CA); encode_conn_data_conn_addr(AT, CA) when is_list(AT) and is_record(CA, megaco_sdp_c_conn_addr) -> case tolower(AT) of "ip4" -> encode_conn_data_conn_addr(CA); _ -> error({invalid_connection_data_conn_addr, {AT, CA}}) end; encode_conn_data_conn_addr(_, BadCA) -> error({invalid_connection_data_conn_addr, BadCA}). encode_conn_data_conn_addr(#megaco_sdp_c_conn_addr{base = Base0, ttl = TTL0, num_of = undefined}) -> Base = encode_conn_data_conn_addr_base(Base0), TTL = encode_conn_data_conn_addr_ttl(TTL0), Base ++ "/" ++ TTL; encode_conn_data_conn_addr(#megaco_sdp_c_conn_addr{base = Base0, ttl = TTL0, num_of = NumOf0}) -> Base = encode_conn_data_conn_addr_base(Base0), TTL = encode_conn_data_conn_addr_ttl(TTL0), NumOf = encode_conn_data_conn_addr_num_of(NumOf0), Base ++ "/" ++ TTL ++ "/" ++ NumOf. encode_conn_data_conn_addr_base(Base) when is_list(Base) -> Base; encode_conn_data_conn_addr_base(BadBase) -> error({invalid_connection_data_conn_addr_base, BadBase}). encode_conn_data_conn_addr_ttl(TTL) when is_integer(TTL) -> integer_to_list(TTL); encode_conn_data_conn_addr_ttl(BadTTL) -> error({invalid_connection_data_conn_addr_ttl, BadTTL}). encode_conn_data_conn_addr_num_of(NumOf) when is_integer(NumOf) -> integer_to_list(NumOf); encode_conn_data_conn_addr_num_of(BadNumOf) -> error({invalid_connection_data_conn_addr_num_of, BadNumOf}). %% ===== Bandwidth ===== %% decode_pp_bandwidth(Value) -> ?d("decode_pp_bandwidth -> entry with" "~n Value: ~p", [Value]), case string:tokens(Value, ":") of [BwTypeStr, BandwidthStr] -> ?d("decode_pp_bandwidth -> " "~n BwTypeStr: ~p" "~n BandwidthStr: ~p", [BwTypeStr, BandwidthStr]), BwType = decode_bandwidth_bwt(BwTypeStr), ?d("decode_pp_bandwidth -> " "~n BwType: ~w", [BwType]), Bandwidth = decode_bandwidth_bw(BandwidthStr), ?d("decode_pp_bandwidth -> " "~n Bandwidth: ~w", [Bandwidth]), SDP = #megaco_sdp_b{bwtype = BwType, bandwidth = Bandwidth}, {ok, SDP}; Err -> invalid_pp(bandwidth_info, Value, Err) end. encode_pp_bandwidth(BwType0, Bandwidth0) -> ?d("encode_pp_bandwidth -> entry with" "~n BwType0: ~p" "~n Bandwidth0: ~p", [BwType0, Bandwidth0]), BwType = encode_bandwidth_bwt(BwType0), Bandwidth = encode_bandwidth_bw(Bandwidth0), Val = BwType ++ ":" ++ Bandwidth, #'PropertyParm'{name = "b", value = [Val]}. decode_bandwidth_bwt("CT") -> ct; decode_bandwidth_bwt("AS") -> as; decode_bandwidth_bwt(BwType) when is_list(BwType) -> BwType. encode_bandwidth_bwt(ct) -> "CT"; encode_bandwidth_bwt(as) -> "AS"; encode_bandwidth_bwt(BwType) when is_list(BwType) -> BwType; encode_bandwidth_bwt(BadBwType) -> error({invalid_bandwidth_bwtype, BadBwType}). decode_bandwidth_bw(Bandwidth) -> s2i(Bandwidth, invalid_bandwidth_bandwidth). encode_bandwidth_bw(Bandwidth) when is_integer(Bandwidth) -> integer_to_list(Bandwidth); encode_bandwidth_bw(BadBandwidth) -> error({invalid_bandwidth_bandwidth, BadBandwidth}). %% ===== Times ===== %% decode_pp_times(Value) -> ?d("decode_pp_times -> entry with" "~n Value: ~p", [Value]), case string:tokens(Value, " \t") of [StartStr, StopStr] -> ?d("decode_pp_times -> " "~n StartStr: ~p" "~n StopStr: ~p", [StartStr, StopStr]), Start = decode_times_start(StartStr), ?d("decode_pp_times -> entry with" "~n Stop: ~w", [Start]), Stop = decode_times_stop(StopStr), ?d("decode_pp_times -> entry with" "~n Stop: ~w", [Stop]), SDP = #megaco_sdp_t{start = Start, stop = Stop}, {ok, SDP}; Err -> invalid_pp(times, Value, Err) end. encode_pp_times(Start0, Stop0) -> ?d("encode_pp_times -> entry with" "~n Start0: ~p" "~n Stop0: ~p", [Start0, Stop0]), Start = encode_times_start(Start0), Stop = encode_times_stop(Stop0), Val = Start ++ " " ++ Stop, #'PropertyParm'{name = "t", value = [Val]}. decode_times_start(Time) -> s2i(Time, invalid_times_start). encode_times_start(Time) when is_integer(Time) -> integer_to_list(Time); encode_times_start(BadTime) -> error({invalid_times_start, BadTime}). decode_times_stop(Time) -> s2i(Time, invalid_times_stop). encode_times_stop(Time) when is_integer(Time) -> integer_to_list(Time); encode_times_stop(BadTime) -> error({invalid_times_stop, BadTime}). %% ===== Repeat Times ===== %% decode_pp_rtimes(Value) -> ?d("decode_pp_rtimes -> entry with" "~n Value: ~p", [Value]), case string:tokens(Value, " \t") of [Repeat, Duration | ListOfOffsets] -> ?d("decode_pp_rtimes -> " "~n Repeat: ~p" "~n Duration: ~p" "~n ListOfOffsets: ~p", [Repeat, Duration, ListOfOffsets]), SDP = #megaco_sdp_r{repeat_interval = Repeat, active_duration = Duration, list_of_offsets = ListOfOffsets}, {ok, SDP}; Err -> invalid_pp(repeat_times, Value, Err) end. encode_pp_rtimes(Repeat0, Duration0, ListOfOffsets0) -> ?d("encode_pp_rtimes -> entry with" "~n Repeat0: ~p" "~n Duration0: ~p" "~n ListOfOffsets0: ~p", [Repeat0, Duration0, ListOfOffsets0]), Repeat = encode_rtimes_repeat(Repeat0), Duration = encode_rtimes_duration(Duration0), ListOfOffsets = encode_rtimes_list_of_offsets(ListOfOffsets0), Val = Repeat ++ " " ++ Duration ++ ListOfOffsets, #'PropertyParm'{name = "r", value = [Val]}. encode_rtimes_repeat(Repeat) when is_list(Repeat) -> Repeat; encode_rtimes_repeat(BadRepeat) -> error({invalid_rtimes_repeat, BadRepeat}). encode_rtimes_duration(Duration) when is_list(Duration) -> Duration; encode_rtimes_duration(BadDuration) -> error({invalid_rtimes_duration, BadDuration}). encode_rtimes_list_of_offsets(LOO) when is_list(LOO) -> F = fun(Off, Acc) when is_list(Off) -> Acc ++ " " ++ Off; (BadOff, Acc) -> error({invalid_rtimes_list_of_offsets, {BadOff, Acc}}) end, lists:foldl(F, [], LOO); encode_rtimes_list_of_offsets(BadLoo) -> error({invalid_rtimes_list_of_offsets, BadLoo}). %% ===== Time Zones ===== %% decode_pp_tzones(Value) when is_list(Value) and (length(Value) > 0) -> ?d("decode_pp_ztimes -> entry with" "~n Value: ~p", [Value]), LOA = decode_tzones_list_of_adjustments(string:tokens(Value, " \t"), []), {ok, #megaco_sdp_z{list_of_adjustments = LOA}}; decode_pp_tzones(BadValue) -> error({invalid_tzones_list_of_adjustments, BadValue}). encode_pp_tzones(LOA) -> ?d("encode_pp_ztimes -> entry with" "~n LOA: ~p", [LOA]), Val = encode_tzones_list_of_adjustments(LOA), #'PropertyParm'{name = "z", value = [Val]}. decode_tzones_list_of_adjustments([], Acc) -> lists:reverse(Acc); decode_tzones_list_of_adjustments([Adj], Acc) -> error({invalid_tzones_list_of_adjustments, Adj, lists:reverse(Acc)}); decode_tzones_list_of_adjustments([Time, Offset | LOA], Acc) -> Adj = #megaco_sdp_z_adjustement{time = Time, offset = Offset}, decode_tzones_list_of_adjustments(LOA, [Adj | Acc]). encode_tzones_list_of_adjustments([H|_] = LOA) when is_record(H, megaco_sdp_z_adjustement) -> F = fun(#megaco_sdp_z_adjustement{time = T, offset = O}, Acc) -> Acc ++ " " ++ T ++ " " ++ O; (BadAdjustment, Acc) -> error({invalid_tzones_list_of_adjustments, {BadAdjustment, Acc}}) end, lists:foldl(F, [], LOA); encode_tzones_list_of_adjustments(LOA) -> error({invalid_tzones_list_of_adjustments, LOA}). %% ===== Encryption Keys ===== %% decode_pp_encryption_keys(Value) -> ?d("decode_pp_encryption_keys -> entry with" "~n Value: ~p", [Value]), {M, E} = case string:tokens(Value, ":") of [Method, EncryptionKey] -> ?d("decode_pp_encryption_keys -> " "~n Method: ~p" "~n EncryptionKey: ~p", [Method, EncryptionKey]), {Method, EncryptionKey}; [Method] -> ?d("decode_pp_encryption_keys -> " "~n Method: ~p", [Method]), {Method, undefined}; Err -> invalid_pp(encryption_key, Value, Err) end, M2 = case tolower(M) of "clear" -> clear; "base64" -> base64; "uri" -> uri; "prompt" -> prompt; _ -> M end, ?d("decode_pp_encryption_keys -> " "~n M2: ~p", [M2]), SDP = #megaco_sdp_k{method = M2, encryption_key = E}, {ok, SDP}. encode_pp_encryption_keys(prompt = _Method, undefined) -> ?d("encode_pp_encryption_keys(prompt) -> entry", []), #'PropertyParm'{name = "k", value = ["prompt"]}; encode_pp_encryption_keys(clear = _Method, EncryptionKey) when is_list(EncryptionKey) -> ?d("encode_pp_encryption_keys(clear) -> entry with" "~n EncryptionKey: ~p", [EncryptionKey]), #'PropertyParm'{name = "k", value = ["clear:" ++ EncryptionKey]}; encode_pp_encryption_keys(base64 = _Method, EncryptionKey) when is_list(EncryptionKey) -> ?d("encode_pp_encryption_keys(base64) -> entry with" "~n EncryptionKey: ~p", [EncryptionKey]), #'PropertyParm'{name = "k", value = ["base64:" ++ EncryptionKey]}; encode_pp_encryption_keys(uri = _Method, EncryptionKey) when is_list(EncryptionKey) -> ?d("encode_pp_encryption_keys(uri) -> entry with" "~n EncryptionKey: ~p", [EncryptionKey]), #'PropertyParm'{name = "k", value = ["uri:" ++ EncryptionKey]}; encode_pp_encryption_keys(Method, EncryptionKey) when is_list(Method) and is_list(EncryptionKey) -> ?d("encode_pp_encryption_keys -> entry with" "~n Method: ~p" "~n EncryptionKey: ~p", [Method, EncryptionKey]), #'PropertyParm'{name = "k", value = [Method ++ ":" ++ EncryptionKey]}; encode_pp_encryption_keys(BadMethod, BadEK) -> error({invalid_encryption_keys, {BadMethod, BadEK}}). %% ===== Attributes ===== %% decode_pp_attribute(Value) -> ?d("decode_pp_attribute -> entry with" "~n Value: ~p", [Value]), First = string:chr(Value, $:), if (First > 0) and (First < length(Value)) -> ?d("decode_pp_attribute -> value attribute", []), Attr = string:substr(Value, 1, First -1), AttrValue = string:substr(Value, First + 1), ?d("decode_pp_attribute -> " "~n Attr: ~p" "~n AttrValue: ~p", [Attr, AttrValue]), decode_pp_attribute_value(Attr, AttrValue); First > 0 -> ?d("decode_pp_attribute -> value attribute (empty)", []), Attr = string:substr(Value, 1, First -1), ?d("decode_pp_attribute -> " "~n Attr: ~p", [Attr]), decode_pp_attribute_value(Attr, []); true -> ?d("decode_pp_attribute -> binary attribute", []), {ok, #megaco_sdp_a{attribute = Value}} end. decode_pp_attribute_value("cat", AttrValue) -> ?d("decode_pp_attribute -> cat", []), SDP = #megaco_sdp_a_cat{category = AttrValue}, {ok, SDP}; decode_pp_attribute_value("keywds", AttrValue) -> ?d("decode_pp_attribute -> keywds", []), SDP = #megaco_sdp_a_keywds{keywords = AttrValue}, {ok, SDP}; decode_pp_attribute_value("tool", AttrValue) -> ?d("decode_pp_attribute -> tool", []), SDP = #megaco_sdp_a_tool{name_and_version = AttrValue}, {ok, SDP}; decode_pp_attribute_value("ptime", AttrValue) -> ?d("decode_pp_attribute -> ptime", []), PacketTimeStr = string:strip(AttrValue, both, $ ), PacketTime = s2i(PacketTimeStr, invalid_ptime_packet_time), ?d("decode_pp_attribute -> PacketTime: ~w", [PacketTime]), SDP = #megaco_sdp_a_ptime{packet_time = PacketTime}, {ok, SDP}; decode_pp_attribute_value("maxptime", AttrValue) -> ?d("decode_pp_attribute -> maxptime", []), MaxPacketTimeStr = string:strip(AttrValue, both, $ ), MaxPacketTime = s2i(MaxPacketTimeStr, invalid_maxptime_maximum_packet_time), ?d("decode_pp_attribute -> MaxPacketTime: ~w", [MaxPacketTime]), SDP = #megaco_sdp_a_maxptime{maximum_packet_time = MaxPacketTime}, {ok, SDP}; decode_pp_attribute_value("rtpmap", AttrValue) -> ?d("decode_pp_attribute -> rtpmap", []), case string:tokens(AttrValue, "\/ \t") of [PayloadStr, EncName, ClockRateStr | EncPar] -> ?d("decode_pp_attribute -> " "~n PayloadStr: ~p" "~n EncName: ~p" "~n ClockRateStr: ~p" "~n EncPar: ~p", [PayloadStr, EncName, ClockRateStr, EncPar]), Payload = s2i(PayloadStr, invalid_rtpmap_payload), ?d("decode_pp_attribute -> Payload: ~w", [Payload]), ClockRate = s2i(ClockRateStr, invalid_rtpmap_payload), ?d("decode_pp_attribute -> ClockRate: ~w", [ClockRate]), SDP = #megaco_sdp_a_rtpmap{payload_type = Payload, encoding_name = EncName, clock_rate = ClockRate, encoding_parms = EncPar}, {ok, SDP}; _ -> error({invalid_rtpmap, AttrValue}) end; decode_pp_attribute_value("orient", AttrValue) -> ?d("decode_pp_attribute -> orient", []), Orientation = decode_attribute_orientation(AttrValue), SDP = #megaco_sdp_a_orient{orientation = Orientation}, {ok, SDP}; decode_pp_attribute_value("type", AttrValue) -> ?d("decode_pp_attribute -> type", []), SDP = #megaco_sdp_a_type{conf_type = AttrValue}, {ok, SDP}; decode_pp_attribute_value("charset", AttrValue) -> ?d("decode_pp_attribute -> charset", []), SDP = #megaco_sdp_a_charset{char_set = AttrValue}, {ok, SDP}; decode_pp_attribute_value("sdplang", AttrValue) -> ?d("decode_pp_attribute -> sdplang", []), SDP = #megaco_sdp_a_sdplang{tag = AttrValue}, {ok, SDP}; decode_pp_attribute_value("lang", AttrValue) -> ?d("decode_pp_attribute -> lang", []), SDP = #megaco_sdp_a_lang{tag = AttrValue}, {ok, SDP}; decode_pp_attribute_value("framerate", AttrValue) -> ?d("decode_pp_attribute -> framerate", []), SDP = #megaco_sdp_a_framerate{frame_rate = AttrValue}, {ok, SDP}; decode_pp_attribute_value("quality", AttrValue) -> ?d("decode_pp_attribute -> quality", []), QualityStr = AttrValue, Quality = s2i(QualityStr, invalid_quality_quality), ?d("decode_pp_attribute -> Quality: ~w", [Quality]), SDP = #megaco_sdp_a_quality{quality = Quality}, {ok, SDP}; decode_pp_attribute_value("fmtp", AttrValue) -> ?d("decode_pp_attribute -> fmtp", []), FMTP = AttrValue, First = string:chr(FMTP, $ ), if (First > 0) and (First < length(FMTP)) -> ?d("decode_pp_attribute_value -> valid fmtp with params", []), Format = string:substr(FMTP, 1, First - 1), Params = string:substr(FMTP, First + 1), ?d("decode_pp_attribute_value -> " "~n Format: ~p" "~n Params: ~p", [Format, Params]), SDP = #megaco_sdp_a_fmtp{format = Format, param = Params}, {ok, SDP}; First > 0 -> ?d("decode_pp_attribute -> valid fmtp", []), Format = string:substr(FMTP, 1, First - 1), ?d("decode_pp_attribute -> " "~n Format: ~p", [Format]), {ok, #megaco_sdp_a_fmtp{format = Format, param = []}}; true -> ?d("decode_pp_attribute_value -> no params", []), {ok, #megaco_sdp_a_fmtp{format = FMTP, param = []}} end; decode_pp_attribute_value(Attr, AttrValue) -> ?d("decode_pp_attribute -> unknown value attribute", []), {ok, #megaco_sdp_a{attribute = Attr, value = AttrValue}}. decode_attribute_orientation("portrait") -> portrait; decode_attribute_orientation("landscape") -> landscape; decode_attribute_orientation("seascape") -> seascape; decode_attribute_orientation(BadOrientation) -> error({invalid_orient_orientation, BadOrientation}). encode_attribute_orientation(portrait) -> "portrait"; encode_attribute_orientation(landscape) -> "landscape"; encode_attribute_orientation(seascape) -> "seascape"; encode_attribute_orientation(BadOrientation) -> error({invalid_orient_orientation, BadOrientation}). encode_pp_attribute_cat(Cat) when is_list(Cat) -> ?d("encode_pp_attribute_cat -> entry with" "~n Cat: ~p", [Cat]), #'PropertyParm'{name = "a", value = ["cat:" ++ Cat]}; encode_pp_attribute_cat(BadCat) -> error({invalid_cat_category, BadCat}). encode_pp_attribute_keywds(Keywords) when is_list(Keywords) -> ?d("encode_pp_attribute_keywds -> entry with" "~n Keywords: ~p", [Keywords]), #'PropertyParm'{name = "a", value = ["keywds:" ++ Keywords]}; encode_pp_attribute_keywds(BadKeywords) -> error({invalid_keywds_keywords, BadKeywords}). encode_pp_attribute_tool(NameAndVersion) when is_list(NameAndVersion) -> ?d("encode_pp_attribute_tool -> entry with" "~n NameAndVersion: ~p", [NameAndVersion]), #'PropertyParm'{name = "a", value = ["tool:" ++ NameAndVersion]}; encode_pp_attribute_tool(BadNameAndVersion) -> error({invalid_tool_name_and_version, BadNameAndVersion}). encode_pp_attribute_ptime(PacketTime) when is_integer(PacketTime) -> ?d("encode_pp_attribute_ptime -> entry with" "~n PacketTime: ~w", [PacketTime]), #'PropertyParm'{name = "a", value = ["ptime:" ++ integer_to_list(PacketTime)]}; encode_pp_attribute_ptime(BadPT) -> error({invalid_ptime_packet_time, BadPT}). encode_pp_attribute_maxptime(MaxPacketTime) when is_integer(MaxPacketTime) -> ?d("encode_pp_attribute_maxptime -> entry with" "~n MaxPacketTime: ~w", [MaxPacketTime]), #'PropertyParm'{name = "a", value = ["maxptime:" ++ integer_to_list(MaxPacketTime)]}; encode_pp_attribute_maxptime(BadMPT) -> error({invalid_maxptime_maximum_packet_time, BadMPT}). encode_pp_attribute_rtpmap(Payload0, EncName0, ClockRate0, EncPar0) -> ?d("encode_pp_attribute_rtpmap -> entry with" "~n Payload0: ~p" "~n EncName0: ~p" "~n ClockRate0: ~p" "~n EncPar0: ~p", [Payload0, EncName0, ClockRate0, EncPar0]), Payload = encode_rtpmap_payload(Payload0), EncName = encode_rtpmap_encoding_name(EncName0), ClockRate = encode_rtpmap_clockrate(ClockRate0), EncPar = encode_rtpmap_encoding_parms(EncPar0), Val = "rtpmap:" ++ Payload ++ " " ++ EncName ++ "/" ++ ClockRate ++ EncPar, #'PropertyParm'{name = "a", value = [Val]}. encode_rtpmap_payload(Payload) when is_integer(Payload) -> integer_to_list(Payload); encode_rtpmap_payload(BadPayload) -> error({invalid_rtpmap_payload, BadPayload}). encode_rtpmap_encoding_name(EncName) when is_list(EncName) -> EncName; encode_rtpmap_encoding_name(BadEncName) -> error({invalid_rtpmap_encoding_name, BadEncName}). encode_rtpmap_clockrate(ClockRate) when is_integer(ClockRate) -> integer_to_list(ClockRate); encode_rtpmap_clockrate(BadClockRate) -> error({invalid_rtpmap_clockrate, BadClockRate}). encode_rtpmap_encoding_parms(EncPar) when is_list(EncPar) -> F = fun(EP, Acc) when is_list(EP) -> Acc ++ "/" ++ EP; (BadEP, Acc) -> error({invalid_rtpmap_encoding_parms, {BadEP, Acc}}) end, lists:foldl(F, [], EncPar); encode_rtpmap_encoding_parms(BadEncPar) -> error({invalid_rtpmap_encoding_parms, BadEncPar}). encode_pp_attribute_orient(Orientation0) -> ?d("encode_pp_attribute_orient -> entry with" "~n Orientation0: ~w", [Orientation0]), Orientation = encode_attribute_orientation(Orientation0), #'PropertyParm'{name = "a", value = ["orient:" ++ Orientation]}. encode_pp_attribute_type(CType) when is_list(CType) -> ?d("encode_pp_attribute_type -> entry with" "~n CType: ~p", [CType]), #'PropertyParm'{name = "a", value = ["type:" ++ CType]}; encode_pp_attribute_type(BadCType) -> error({invalid_type_conf_type, BadCType}). encode_pp_attribute_charset(CharSet) when is_list(CharSet) -> ?d("encode_pp_attribute_charset -> entry with" "~n CharSet: ~p", [CharSet]), #'PropertyParm'{name = "a", value = ["charset:" ++ CharSet]}; encode_pp_attribute_charset(BadCharSet) -> error({invalid_charset_char_set, BadCharSet}). encode_pp_attribute_sdplang(SdpLang) when is_list(SdpLang) -> ?d("encode_pp_attribute_sdplang -> entry with" "~n SdpLang: ~p", [SdpLang]), #'PropertyParm'{name = "a", value = ["sdplang:" ++ SdpLang]}; encode_pp_attribute_sdplang(BadSdpLang) -> error({invalid_sdplang_tag, BadSdpLang}). encode_pp_attribute_lang(Lang) when is_list(Lang) -> ?d("encode_pp_attribute_lang -> entry with" "~n Lang: ~p", [Lang]), #'PropertyParm'{name = "a", value = ["lang:" ++ Lang]}; encode_pp_attribute_lang(BadLang) -> error({invalid_lang_tag, BadLang}). encode_pp_attribute_framerate(FrameRate) when is_list(FrameRate) -> ?d("encode_pp_attribute_framerate -> entry with" "~n FrameRate: ~p", [FrameRate]), #'PropertyParm'{name = "a", value = ["framerate:" ++ FrameRate]}; encode_pp_attribute_framerate(BadFrameRate) -> error({invalid_framerate_frame_rate, BadFrameRate}). encode_pp_attribute_quality(Quality) when is_integer(Quality) -> ?d("encode_pp_attribute_quality -> entry with" "~n Quality: ~w", [Quality]), #'PropertyParm'{name = "a", value = ["quality:" ++ integer_to_list(Quality)]}; encode_pp_attribute_quality(BadQ) -> error({invalid_quality_quality, BadQ}). encode_pp_attribute_fmtp(Fmt0, Params0) -> ?d("encode_pp_attribute_rtpmap -> entry with" "~n Fmt0: ~p" "~n Params0: ~p", [Fmt0, Params0]), Fmt = encode_fmtp_format(Fmt0), Params = encode_fmtp_param(Params0), Val = "fmtp:" ++ Fmt ++ " " ++ Params, #'PropertyParm'{name = "a", value = [Val]}. encode_fmtp_format(Fmt) when is_list(Fmt) -> Fmt; encode_fmtp_format(BadFmt) -> error({invalid_fmtp_format, BadFmt}). encode_fmtp_param(Param) when is_list(Param) -> Param; encode_fmtp_param(BadParam) -> error({invalid_fmtp_param, BadParam}). encode_pp_attribute(Attr, undefined) when is_list(Attr) -> ?d("encode_pp_attribute_rtpmap -> entry with" "~n Attr: ~p", [Attr]), #'PropertyParm'{name = "a", value = [Attr]}; encode_pp_attribute(Attr, Value) when is_list(Attr) and is_list(Value) -> ?d("encode_pp_attribute_rtpmap -> entry with" "~n Attr: ~p" "~n Value: ~p", [Attr, Value]), #'PropertyParm'{name = "a", value = [Attr ++ ":" ++ Value]}; encode_pp_attribute(BadAttr, BadAttrValue) -> error({invalid_attribute, {BadAttr, BadAttrValue}}). %% ===== Media Announcements ===== %% decode_pp_media_announcement(Value) -> case string:tokens(Value, " \t") of [Media0, PortInfo, Transport | FMT] -> Media = case tolower(Media0) of "audio" -> audio; "video" -> video; "application" -> application; "data" -> data; "control" -> control; _ -> Media0 end, {Port, NoOfPorts} = case string:tokens(PortInfo, "/") of [P1, NP] -> {s2i(P1, invalid_media_announcement_port), s2i(NP, invalid_media_announcement_nof_ports)}; [P2] -> {s2i(P2, invalid_media_announcement_port), undefined}; Err -> invalid_pp(mnta_port_info, Value, Err) end, SDP = #megaco_sdp_m{media = Media, port = Port, num_ports = NoOfPorts, transport = Transport, fmt_list = FMT}, {ok, SDP}; Err -> invalid_pp(media_name_transp_addr, Value, Err) end. encode_pp_media_announcement(Media0, Port0, undefined, Transport0, FMT0) -> ?d("encode_pp_media_announcement -> entry with" "~n Media0: ~p" "~n Port0: ~p" "~n Transport0: ~p" "~n FMT0: ~p", [Media0, Port0, Transport0, FMT0]), Media = encode_media_announcement_media(Media0), Port = encode_media_announcement_port(Port0), Transport = encode_media_announcement_transport(Transport0), FMT = encode_media_announcement_fmt_list(FMT0), do_encode_pp_media_announcement(Media, Port, "", Transport, FMT); encode_pp_media_announcement(Media0, Port0, NumPorts0, Transport0, FMT0) -> ?d("encode_pp_media_announcement -> entry with" "~n Media0: ~p" "~n Port0: ~p" "~n NumPorts0: ~p" "~n Transport0: ~p" "~n FMT0: ~p", [Media0, Port0, NumPorts0, Transport0, FMT0]), Media = encode_media_announcement_media(Media0), Port = encode_media_announcement_port(Port0), NumPorts = encode_media_announcement_num_port(NumPorts0), Transport = encode_media_announcement_transport(Transport0), FMT = encode_media_announcement_fmt_list(FMT0), do_encode_pp_media_announcement(Media, Port, NumPorts, Transport, FMT). do_encode_pp_media_announcement(Media, Port, NumOfPorts, Transport, FMT) -> Val = Media ++ " " ++ Port ++ NumOfPorts ++ " " ++ Transport ++ FMT, #'PropertyParm'{name = "m", value = [Val]}. encode_media_announcement_media(Media) when is_atom(Media) -> MaMedia = [audio, video, application, data, control], case lists:member(Media, MaMedia) of true -> atom_to_list(Media); false -> error({invalid_media_announcement_media, Media}) end; encode_media_announcement_media(Media) when is_list(Media) -> Media; encode_media_announcement_media(BadMedia) -> error({invalid_media_announcement_media, BadMedia}). encode_media_announcement_port(Port) when is_integer(Port) -> integer_to_list(Port); encode_media_announcement_port(BadPort) -> error({invalid_media_announcement_port, BadPort}). encode_media_announcement_num_port(NumPort) when is_integer(NumPort) -> "/" ++ integer_to_list(NumPort); encode_media_announcement_num_port(BadNumPort) -> error({invalid_media_announcement_num_port, BadNumPort}). encode_media_announcement_transport(Transport) when is_list(Transport) -> Transport; encode_media_announcement_transport(BadTransport) -> error({invalid_media_announcement_transport, BadTransport}). encode_media_announcement_fmt_list(FmtList) when is_list(FmtList) -> F = fun(FMT, Acc) when is_list(FMT) -> Acc ++ " " ++ FMT; (BadFMT, Acc) -> error({invalid_media_announcement_fmt_list, {BadFMT, Acc}}) end, lists:foldl(F, [], FmtList); encode_media_announcement_fmt_list(BadFmtList) -> error({invalid_media_announcement_fmt_list, BadFmtList}). decode_network_type(NT) when is_list(NT) -> case tolower(NT) of "in" -> in; _ -> NT end. encode_network_type(in) -> "IN"; encode_network_type(NT) when is_list(NT) -> NT; encode_network_type(Bad) -> {error, {invalid_network_type, Bad}}. decode_address_type(AT) when is_list(AT) -> case tolower(AT) of "ip4" -> ip4; "ip6" -> ip6; _ -> AT end. encode_address_type(ip4) -> "IP4"; encode_address_type(ip6) -> "IP6"; encode_address_type(AT) when is_list(AT) -> case toupper(AT) of "IP4" -> "IP4"; "IP6" -> "IP6"; _ -> AT end; encode_address_type(Crap) -> {error, {invalid_address_type, Crap}}. s2i(S, E) -> case (catch list_to_integer(S)) of I when is_integer(I) -> I; _ -> error({E, S}) end. -define(LOWER(Char), if Char >= $A, Char =< $Z -> Char - ($A - $a); true -> Char end). tolower(Chars) -> [?LOWER(Char) || Char <- Chars]. -define(UPPER(Char), if Char >= $a, Char =< $z -> Char + ($A - $a); true -> Char end). toupper(Chars) -> [?UPPER(Char) || Char <- Chars]. invalid_pp(What, Value, Error) -> {error, {invalid_PropertyParm, {What, Value, Error}}}. error(Reason) -> throw({error, Reason}).