aboutsummaryrefslogtreecommitdiffstats
path: root/lib/megaco/src/engine/megaco_sdp.erl
diff options
context:
space:
mode:
authorErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
committerErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
commit84adefa331c4159d432d22840663c38f155cd4c1 (patch)
treebff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/megaco/src/engine/megaco_sdp.erl
downloadotp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz
otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2
otp-84adefa331c4159d432d22840663c38f155cd4c1.zip
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/megaco/src/engine/megaco_sdp.erl')
-rw-r--r--lib/megaco/src/engine/megaco_sdp.erl1645
1 files changed, 1645 insertions, 0 deletions
diff --git a/lib/megaco/src/engine/megaco_sdp.erl b/lib/megaco/src/engine/megaco_sdp.erl
new file mode 100644
index 0000000000..90911fe24a
--- /dev/null
+++ b/lib/megaco/src/engine/megaco_sdp.erl
@@ -0,0 +1,1645 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights 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
+%%----------------------------------------------------------------------
+
+-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;
+decode_bandwidth_bwt(BadBwType) ->
+ error({invalid_bandwidth_bwtype, BadBwType}).
+
+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}).
+