API 库函数支持以下操作:
创建 SDP 会话结构
在 SDP 会话结构中搜索
关闭 SDP 会话结构
实用程序函数
创建新的 SDP 会话结构的第一步是通过调用 sdp_new_session() 函数来为新结构分配内存。此函数可返回指向新会话结构的指针。本节中的其他函数使用该指针来构建新会话结构。完成新会话结构的构建之后,请使用 sdp_session_to_str() 函数将其转换为字符串表示形式。
sdp_new_session() 函数可为 session 参数指定的新 SDP 会话结构分配内存,并向该新结构分配版本号。可以通过调用 sdp_free_session() 函数来释放分配给此会话结构的内存。
返回值:如果 sdp_new_session() 函数成功完成,该函数将返回新分配的 SDP 会话结构。如果失败,该函数将返回 NULL。
sdp_add_origin() 函数使用 name、id、ver、nettype、addrtype 和 address 参数将 ORIGIN (o=) SDP 字段添加到由 session 参数 (sdp_session_t) 的值指定的会话结构。
返回值:如果 sdp_add_origin() 函数成功完成,该函数将返回 0。如果强制参数不存在,该函数将返回 EINVAL。如果内存分配失败,该函数将返回 ENOMEM。在出现错误时,errno 的值不会发生更改。
sdp_add_name() 函数使用 name 参数将 NAME (s=) SDP 字段添加到由 session 参数 (sdp_session_t) 的值指定的会话结构。
返回值:如果 sdp_add_name() 函数成功完成,该函数将返回 0。如果强制参数不存在,该函数将返回 EINVAL。如果内存分配失败,该函数将返回 ENOMEM。在出现错误时,errno 的值不会发生更改。
sdp_add_information() 函数使用 value 参数将 INFO (i=) SDP 字段添加到会话结构 (sdp_session_t) 或介质结构 (sdp_media_t)。此字段可以进入 SDP 描述的介质部分或会话部分。您必须将 &session->s_info 或 &media->m_info 作为第一个参数进行传递,以指定该部分。
返回值:如果 sdp_add_information() 函数成功完成,该函数将返回 0。如果强制参数不存在,该函数将返回 EINVAL。如果内存分配失败,该函数将返回 ENOMEM。在出现错误时,errno 的值不会发生更改。
sdp_add_uri() 函数使用 uri 参数将 URI (u=) SDP 字段添加到由 session 参数 (sdp_session_t) 的值指定的会话结构。
返回值:如果 sdp_add_uri() 函数成功完成,该函数将返回 0。如果强制参数不存在,该函数将返回 EINVAL。如果内存分配失败,该函数将返回 ENOMEM。在出现错误时,errno 的值不会发生更改。
sdp_add_email() 函数使用 email 参数将 EMAIL (e=) SDP 字段添加到由 session 参数 (sdp_session_t) 的值指定的会话结构。
返回值:如果 sdp_add_email() 函数成功完成,该函数将返回 0。如果强制参数不存在,该函数将返回 EINVAL。如果内存分配失败,该函数将返回 ENOMEM。在出现错误时,errno 的值不会发生更改。
sdp_add_phone() 函数使用 phone 参数将 PHONE (p=) SDP 字段添加到由 session 参数 (sdp_session_t) 的值指定的会话结构。
返回值:如果 sdp_add_phone() 函数成功完成,该函数将返回 0。如果强制参数不存在,该函数将返回 EINVAL。如果内存分配失败,该函数将返回 ENOMEM。在出现错误时,errno 的值不会发生更改。
sdp_add_connection() 函数使用 nettype、addrtype、address、ttl 和 addrcount 参数将 CONNECTION (c=) SDP 字段添加到会话结构 (sdp_session_t) 或介质结构 (sdp_media_t)。对于 IPv4 或 IPv6 单播地址,将 ttl 和 addrcount 参数的值设置为零。对于多播地址,将 ttl 参数的值设置为零到 255 之间的某个值。多播地址不能包含值为零的 addrcount 参数。
此字段可以进入 SDP 描述的介质部分或会话部分。您必须将 &session->s_info 或 &media->m_info 作为第一个参数进行传递,以指定该部分。
返回值:如果 sdp_add_connection() 函数成功完成,该函数将返回 0。如果强制参数不存在,该函数将返回 EINVAL。如果内存分配失败,该函数将返回 ENOMEM。在出现错误时,errno 的值不会发生更改。
sdp_add_bandwidth() 函数使用 type 参数和 value 参数将 BANDWIDTH (b=) SDP 字段添加到会话结构 (sdp_session_t) 或介质结构 (sdp_media_t)。
此字段可以进入 SDP 描述的介质部分或会话部分。您必须将 &session->s_info 或 &media->m_info 作为第一个参数进行传递,以指定该部分。
返回值:如果 sdp_add_bandwidth() 函数成功完成,该函数将返回 0。如果强制参数不存在,该函数将返回 EINVAL。如果内存分配失败,该函数将返回 ENOMEM。在出现错误时,errno 的值不会发生更改。
sdp_add_time() 函数使用 starttime 和 stoptime 参数的值将 TIME (t=) SDP 字段添加到会话结构。此函数使用 time 参数创建新的时间结构并返回指向该结构的指针。
返回值:如果 sdp_add_time() 函数成功完成,该函数将返回 0。如果强制参数不存在,该函数将返回 EINVAL。如果内存分配失败,该函数将返回 ENOMEM。在出现错误时,errno 的值不会发生更改。
sdp_add_repeat() 函数使用 interval、duration 和 offset 参数的值将 REPEAT (r=) SDP 字段添加到会话结构。offset 参数的值是包含一个或多个偏移值的字符串,如 60 或 60 1d 3h。time 参数的值是指向 sdp_add_time() 函数创建的时间结构的指针。
返回值:如果 sdp_add_repeat() 函数成功完成,该函数将返回 0。如果强制参数不存在,该函数将返回 EINVAL。如果内存分配失败,该函数将返回 ENOMEM。在出现错误时,errno 的值不会发生更改。
sdp_add_zone() 函数使用 time 参数和 offset 参数将 ZONE (z=) SDP 字段添加到由 session 参数 (sdp_session_t) 的值指定的会话结构。通过针对每个时间/偏移值对调用此函数,可以为单个区域字段添加多个时间和偏移值。
返回值:如果 sdp_add_zone() 函数成功完成,该函数将返回 0。如果强制参数不存在,该函数将返回 EINVAL。如果内存分配失败,该函数将返回 ENOMEM。在出现错误时,errno 的值不会发生更改。
sdp_add_key() 函数使用 method 参数和 enckey 参数将 KEY (k=) SDP 字段添加到会话结构 (sdp_session_t) 或介质结构 (sdp_media_t)。此字段可以进入 SDP 描述的介质部分或会话部分。您必须将 &session->s_info 或 &media->m_info 作为第一个参数进行传递,以指定该部分。
返回值:如果 sdp_add_key() 函数成功完成,该函数将返回 0。如果强制参数不存在,该函数将返回 EINVAL。如果内存分配失败,该函数将返回 ENOMEM。在出现错误时,errno 的值不会发生更改。
sdp_add_attribute() 函数使用 name 参数和 value 参数将 ATTRIBUTE (a=) SDP 字段添加到会话结构 (sdp_session_t) 或介质结构 (sdp_media_t)。此字段可以进入 SDP 描述的介质部分或会话部分。您必须将 &session->s_info 或 &media->m_info 作为第一个参数进行传递,以指定该部分。
返回值:如果 sdp_add_attribute() 函数成功完成,该函数将返回 0。如果强制参数不存在,该函数将返回 EINVAL。如果内存分配失败,该函数将返回 ENOMEM。在出现错误时,errno 的值不会发生更改。
sdp_add_media() 函数使用 name、port、portcount、protocol 和 format 参数的值将 MEDIA (m=) SDP 字段添加到由 session 参数 (sdp_session_t) 的值指定的会话结构。format 参数是包含一个或多个值的字符串,如字符串 0 32 97。
此函数使用 media 参数创建新的介质结构并返回指向该结构的指针。将 SDP 字段添加到介质结构的函数会使用该指针。
返回值:如果 sdp_add_media() 函数成功完成,该函数将返回 0。如果强制参数不存在,该函数将返回 EINVAL。如果内存分配失败,该函数将返回 ENOMEM。在出现错误时,errno 的值不会发生更改。
本示例使用本节中述及的函数来创建新的 SDP 会话结构、将字段添加到该结构,并将已完成的结构转换为该结构的字符串表示形式。在示例的结尾,程序将调用 sdp_free_session() 函数以释放会话。
示例 3-1 构建 SDP 会话结构
/* SDP Message we will be building "v=0\r\n\ o=Alice 2890844526 2890842807 IN IP4 10.47.16.5\r\n\ s=-\r\n\ i=A Seminar on the session description protocol\r\n\ u=http://www.example.com/seminars/sdp.pdf\r\n\ e=alice@example.com (Alice Smith)\r\n\ p=+1 911-345-1160\r\n\ c=IN IP4 10.47.16.5\r\n\ b=CT:1024\r\n\ t=2854678930 2854679000\r\n\ r=604800 3600 0 90000\r\n\ z=2882844526 -1h 2898848070 0h\r\n\ a=recvonly\r\n\ m=audio 49170 RTP/AVP 0\r\n\ i=audio media\r\n\ b=CT:1000\r\n\ k=prompt\r\n\ m=video 51372 RTP/AVP 99 90\r\n\ i=video media\r\n\ a=rtpmap:99 h232-199/90000\r\n\ a=rtpmap:90 h263-1998/90000\r\n" */ #include stdio.h> #include string.h> #include errno.h> #include sdp.h> int main () { sdp_session_t *my_sess; sdp_media_t *my_media; sdp_time_t *my_time; char *b_sdp; my_sess = sdp_new_session(); if (my_sess == NULL) { return (ENOMEM); } my_sess->version = 0; if (sdp_add_name(my_sess, "-") != 0) goto err_ret; if (sdp_add_origin(my_sess, "Alice", 2890844526ULL, 2890842807ULL, "IN", "IP4", "10.47.16.5") != 0) goto err_ret; if (sdp_add_information(&my_sess->s_info, "A Seminar on the session" "description protocol") != 0) goto err_ret; if (sdp_add_uri (my_sess, "http://www.example.com/seminars/sdp.pdf") != 0) goto err_ret; if (sdp_add_email(my_sess, "alice@example.com (Alice smith)") != 0) goto err_ret; if (sdp_add_phone(my_sess, "+1 911-345-1160") != 0) goto err_ret; if (sdp_add_connection(&my_sess->s_conn, "IN", "IP4", "10.47.16.5", 0, 0) != 0) goto err_ret; if (sdp_add_bandwidth(&my_sess->s_bw, "CT", 1024) != 0) goto err_ret; if (sdp_add_time(my_sess, 2854678930ULL, 2854679000ULL, &my_time) != 0) goto err_ret; if (sdp_add_repeat(my_time, 604800ULL, 3600ULL, "0 90000") != 0) goto err_ret; if (sdp_add_zone(my_sess, 2882844526ULL, "-1h") != 0) goto err_ret; if (sdp_add_zone(my_sess, 2898848070ULL, "0h") != 0) goto err_ret; if (sdp_add_attribute(&my_sess->s_attr, "sendrecv", NULL) != 0) goto err_ret; if (sdp_add_media(my_sess, "audio", 49170, 1, "RTP/AVP", "0", &my_media) != 0) goto err_ret; if (sdp_add_information(&my_media->m_info, "audio media") != 0) goto err_ret; if (sdp_add_bandwidth(&my_media->m_bw, "CT", 1000) != 0) goto err_ret; if (sdp_add_key(&my_media->m_key, "prompt", NULL) != 0) goto err_ret; if (sdp_add_media(my_sess, "video", 51732, 1, "RTP/AVP", "99 90", &my_media) != 0) goto err_ret; if (sdp_add_information(&my_media->m_info, "video media") != 0) goto err_ret; if (sdp_add_attribute(&my_media->m_attr, "rtpmap", "99 h232-199/90000") != 0) goto err_ret; if (sdp_add_attribute(&my_media->m_attr, "rtpmap", "90 h263-1998/90000") != 0) goto err_ret; b_sdp = sdp_session_to_str(my_sess, &error); /* * b_sdp is the string representation of my_sess structure */ free(b_sdp); sdp_free_session(my_sess); return (0); err_ret: free(b_sdp); sdp_free_session(my_sess); return (1); }
本节中述及的函数可在 SDP 会话结构中搜索特定值,并返回指向这些值的指针。
sdp_find_attribute() 函数可在 attr 参数指定的属性列表中搜索 name 参数指定的属性名称。
返回值:如果 sdp_find_attribute() 函数成功完成,该函数将返回指向 name 参数指定的属性 (sdp_attr_t *) 的指针。在其他所有情况下,sdp_find_attribute() 函数返回 NULL 值。
示例 3-2 使用 sdp_find_attribute() 函数
本示例中的不完整 SDP 描述包含音频部分。
m=audio 49170 RTP/AVP 0 8 a=rtpmap:0 PCMU/8000 a=rtpmap:8 PCMA/8000 a=sendonly a=ptime:10000 a=maxptime:20000 /* * Assuming that above description is parsed using sdp_parse and that * the parsed structure is in "session" sdp_session_t structure. */ sdp_attr_t *ptime; sdp_attr_t *max_ptime; sdp_media_t *media = session->s_media; if ((ptime = sdp_find_attribute(media->m_attr, "ptime")) == NULL) /* ptime attribute not present */ else if((max_ptime = sdp_find_attribute(media->m_attr, "maxptime")) == NULL) /* max_ptime attribute not present */
sdp_find_media() 函数可在 media 参数指定的介质列表中搜索 name 参数指定的介质条目。
返回值:如果 sdp_find_media() 函数成功完成,该函数将返回指向 name 参数指定的介质列表条目 (sdp_media_t *) 的指针。在其他所有情况下,sdp_find_media() 函数返回 NULL 值。
示例 3-3 使用 sdp_find_media() 函数
本示例中的不完整 SDP 描述包含两个部分,分别是音频部分和视频部分。
m=audio 49170 RTP/AVP 0 8 a=rtpmap:0 PCMU/8000 a=rtpmap:8 PCMA/8000 m=video 51372 RTP/AVP 31 32 a=rtpmap:31 H261/90000 a=rtpmap:32 MPV/90000 /* * Assuming that above description is parsed using sdp_parse() and that * the parsed structure is in "session" sdp_session_t structure. */ sdp_media_t *my_media; my_media = sdp_find_media(session->s_media, "video"); /* * my_media now points to the structure containg video media section * information */
sdp_find_media_rtpmap() 函数可在 media 参数指定的介质结构的属性列表中搜索 format 参数指定的格式条目。
返回值:如果 sdp_find_media_rtpmap() 函数成功完成,该函数将返回指向 name 参数指定的格式条目 (sdp_attr_t *) 的指针。在其他所有情况下,sdp_find_media() 函数返回 NULL 值。
示例 3-4 使用 sdp_find_media_rtpmap() 函数
本示例中的不完整 SDP 描述包含两个部分,分别是音频部分和视频部分。
m=audio 49170 RTP/AVP 0 8 a=rtpmap:0 PCMU/8000 a=rtpmap:8 PCMA/8000 m=video 51372 RTP/AVP 31 32 a=rtpmap:31 H261/90000 a=rtpmap:32 MPV/90000 /* * Assuming that above description is parsed using sdp_parse() and that * the parsed structure is in "session" sdp_session_t structure. */ sdp_media_t *video; sdp_attr_t *mpv; video = sdp_find_media(session->s_media, "video); mpv = sdp_find_media_rtpmap(video, "32"); /* * Now the attribute structure sdp_attr_t, mpv will be having * values from the attribute field "a=rtpmap:32 MPV/90000" */
本节中述及的函数可实现以下功能:
从 SDP 会话结构中删除字段
释放 SDP 会话结构
sdp_delete_all_field() 函数可从 SDP 结构中删除 field 参数指定的所出现的所有 SDP 字段。例如,如果 SDP 结构具有三个 BANDWIDTH (b=) 字段,使用 field 参数中的值 SDP_BANDWIDTH_FIELD 调用此函数可从会话结构中删除所有三个 BANDWIDTH 字段。
返回值:如果 sdp_delete_all_field() 函数成功完成,该函数将返回 0。如果会话参数为 NULL 或字段类型未知,该函数将返回 EINVAL。在出现错误时,errno 的值不会发生更改。
sdp_delete_all_media_field() 函数可从 SDP 介质结构中删除 field 参数指定的所出现的所有 SDP 字段。
返回值:如果 sdp_delete_all_media_field() 函数成功完成,该函数将返回 0。如果会话参数为 NULL 或字段类型未知,该函数将返回 EINVAL。在出现错误时,errno 的值不会发生更改。
sdp_delete_media() 函数可从介质列表中删除 media 参数指定的介质条目。此函数可通过调用 sdp_find_media() 函数来查找指定的介质条目。此函数将在删除介质条目之后释放分配给介质结构的内存。
返回值:如果 sdp_delete_media() 函数成功完成,该函数将返回 0。如果会话参数为 NULL 或强制参数不存在,该函数将返回 EINVAL。在出现错误时,errno 的值不会发生更改。
sdp_delete_attribute() 函数可从介质列表中删除 attr 参数指定的属性。此函数可通过调用 sdp_find_media_rtpmap() 函数或 sdp_find_attribute() 函数来查找指定的属性。此函数将在删除该属性之后释放分配给属性结构的内存。
返回值:如果 sdp_delete_attribute() 函数成功完成,该函数将返回 0。如果会话参数为 NULL 或强制参数不存在,该函数将返回 EINVAL。在出现错误时,errno 的值不会发生更改。
sdp_free_session() 函数可销毁 session 参数指定的会话,并释放与该结构关联的资源。
本节中述及的函数可解析并填充 SDP 会话结构、克隆现有会话,以及将现有会话转换为字符串表示形式。
sdp_parse() 函数可解析 sdp_info 参数中的 SDP 描述并填充 sdp_session_t 结构。len 参数可指定字符缓冲区 sdp_info 的长度。该函数可分配 sdp_session_t 结构所需的内存。要释放该内存,请调用 sdp_free_session() 函数。
flags 参数的值必须设置为零。如果 flags 参数具有非零值,sdp_parse() 函数将失败并返回值 EINVAL,并且会将 *session 的值设置为 NULL。
p_error 参数可采用具有解析错误的任何字段的值。此参数不能采用 NULL 值。下面列出了 p_error 参数的可能值:
SDP_VERSION_ERROR 0x00000001 SDP_ORIGIN_ERROR 0x00000002 SDP_NAME_ERROR 0x00000004 SDP_INFO_ERROR 0x00000008 SDP_URI_ERROR 0x00000010 SDP_EMAIL_ERROR 0x00000020 SDP_PHONE_ERROR 0x00000040 SDP_CONNECTION_ERROR 0x00000080 SDP_BANDWIDTH_ERROR 0x00000100 SDP_TIME_ERROR 0x00000200 SDP_REPEAT_TIME_ERROR 0x00000400 SDP_ZONE_ERROR 0x00000800 SDP_KEY_ERROR 0x00001000 SDP_ATTRIBUTE_ERROR 0x00002000 SDP_MEDIA_ERROR 0x00004000 SDP_FIELDS_ORDER_ERROR 0x00008000 SDP_MISSING_FIELDS 0x00010000
如果 SDP 结构中的字段次序颠倒,与 RFC 4566 有冲突,sdp_parse() 函数会将 p_error 参数的值设置为 SDP_FIELDS_ORDER_ERROR。如果 SDP 结构中缺少必填字段,与 RFC 4566 有冲突,sdp_parse() 函数会将 p_error 参数的值设置为 SDP_MISSING_FIELDS。
sdp_parse() 函数在处理具有解析错误的字段之后将继续进行解析,但是具有解析错误的字段将不会显示在生成的 sdp_session_t 结构中。
返回值:如果 sdp_parse() 函数成功完成,该函数将返回 0。如果会话参数无效,sdp_parse() 函数将返回 EINVAL。如果内存分配在 sdp_parse() 函数正在解析 sdp_info 时失败,该函数将返回 ENOMEM。在出现错误时,errno 的值不会发生更改。
示例 3-5 示例:解析 SDP 会话结构
在本示例中,SDP 会话结构如下所示:
v=0\r\n o=jdoe 23423423 234234234 IN IP4 192.168.1.1\r\n s=SDP seminar\r\n i=A seminar on the session description protocol\r\n e=test@host.com c=IN IP4 156.78.90.1\r\n t=2873397496 2873404696\r\n
在调用 sdp_parse_t() 函数之后,生成的 sdp_session_t 结构如下所示:
session { sdp_session_version = 1 s_version = 0 s_origin { o_username = "jdoe" o_id = 23423423ULL o_version = 234234234ULL o_nettype = "IN" o_addrtype = "IP4" o_address = "192.168.1.1" } s_name = "SDP seminar" s_info = "A seminar on the session description protocol" s_uri = (nil) s_email { value = "test@host.com" next = (nil) } s_phone = (nil) s_conn { c_nettype = "IN" c_addrtype = "IP4" c_address = "156.78.90.1" c_addrcount = 0 c_ttl = 0 c_next = (nil) } s_bw = (nil) s_time { t_start = 2873397496ULL t_stop = 2873404696ULL t_repeat = (nil) t_next = (nil) } s_zone = (nil) s_key = (nil) s_attr = (nil) s_media = (nil) }
sdp_clone_session() 函数可创建新的 SDP 会话结构,该会话结构与 session 参数中指定的 SDP 会话结构相同。sdp_clone_session() 函数将在成功完成时返回克隆的会话结构。sdp_clone_session() 函数将在失败时返回 NULL。
sdp_session_to_str() 函数返回 session 参数指定的 SDP 会话结构的字符串表示形式。sdp_session_to_str() 函数先将回车/换行符附加到每个 SDP 字段的结尾,然后再将此字段附加到字符串。
返回值:sdp_session_to_str() 函数将在成功完成时返回 SDP 会话结构的字符串表示形式。在其他所有情况下,sdp_session_to_str() 函数将返回 NULL。如果输入为空,sdp_session_to_str() 函数将返回指向 EINVAL 的错误指针。如果内存分配失败,sdp_session_to_str() 函数将返回指向 ENOMEM 的错误指针。在出现错误时,errno 的值不会发生更改。