741 lines
19 KiB
C
741 lines
19 KiB
C
/*
|
|
* This file is part of the Sofia-SIP package
|
|
*
|
|
* Copyright (C) 2005 Nokia Corporation.
|
|
*
|
|
* Contact: Pekka Pessi <pekka.pessi@nokia.com>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public License
|
|
* as published by the Free Software Foundation; either version 2.1 of
|
|
* the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
|
* 02110-1301 USA
|
|
*
|
|
*/
|
|
|
|
/**@ingroup sdp_printer
|
|
*
|
|
* @CFILE sdp_print.c Simple SDP printer interface.
|
|
*
|
|
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
|
|
*
|
|
* @date Created: Fri Feb 18 10:25:08 2000 ppessi
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <sofia-sip/su_alloc.h>
|
|
#include <sofia-sip/su_string.h>
|
|
|
|
#include "sofia-sip/sdp.h"
|
|
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <assert.h>
|
|
|
|
/* ========================================================================= */
|
|
/* Printing API */
|
|
/* */
|
|
|
|
#define SDP_BLOCK (512)
|
|
|
|
#define CRLF "\015\012"
|
|
|
|
typedef unsigned longlong ull;
|
|
|
|
/** @typedef struct sdp_printer_s sdp_printer_t
|
|
*
|
|
* SDP printer handle.
|
|
*
|
|
* @sa #sdp_session_t, sdp_print(), sdp_printing_error(),
|
|
* sdp_message(), sdp_message_size(), sdp_printer_free()
|
|
*/
|
|
|
|
struct sdp_printer_s {
|
|
int pr_size;
|
|
su_home_t *pr_home;
|
|
char *pr_buffer;
|
|
size_t pr_bsiz;
|
|
size_t pr_used;
|
|
/* various flags */
|
|
unsigned pr_ok : 1;
|
|
unsigned pr_strict : 1;
|
|
unsigned pr_owns_buffer:1;
|
|
unsigned pr_may_realloc:1;
|
|
unsigned pr_all_rtpmaps:1;
|
|
unsigned pr_mode_manual:1;
|
|
unsigned pr_mode_always:1;
|
|
};
|
|
|
|
static struct sdp_printer_s printer_memory_error = {
|
|
sizeof(printer_memory_error),
|
|
NULL,
|
|
"memory exhausted",
|
|
sizeof(printer_memory_error.pr_buffer),
|
|
sizeof(printer_memory_error.pr_buffer)
|
|
};
|
|
|
|
static void print_session(sdp_printer_t *p, sdp_session_t const *session);
|
|
static void printing_error(sdp_printer_t *p, const char *fmt, ...);
|
|
|
|
/** Print a SDP description.
|
|
*
|
|
* Encode the contents of the SDP session structure #sdp_session_t
|
|
* to the @a msgbuf. The @a msgbuf has size @a msgsize
|
|
* bytes. If @a msgbuf is @c NULL, the sdp_print() function allocates the
|
|
* required buffer from the @a home heap.
|
|
*
|
|
* @param home Memory home (may be NULL).
|
|
* @param session SDP session description structure to be encoded.
|
|
* @param msgbuf Buffer to which encoding is stored (may be NULL).
|
|
* @param msgsize Size of @a msgbuf.
|
|
* @param flags Flags specifying the encoding options.
|
|
*
|
|
* The @a flags specify encoding options as follows:
|
|
*
|
|
* @li #sdp_f_strict - Printer should only emit messages conforming strictly
|
|
* to the * specification.
|
|
*
|
|
* @li #sdp_f_realloc - If this flag is specified, and @a msgbuf is too
|
|
* small for the resulting SDP message, @c sdp_print() may allocate a new
|
|
* buffer for it from the heap.
|
|
*
|
|
* @li #sdp_f_print_prefix - The buffer provided by caller already contains
|
|
* valid data. The result will concatenated to the string in the buffer.
|
|
*
|
|
* @li #sdp_f_mode_always - Always add mode attributes to media
|
|
*
|
|
* @li #sdp_f_mode_manual - Do not generate mode attributes
|
|
*
|
|
* @return
|
|
* Always return a handle to an #sdp_printer_t object.
|
|
*
|
|
* @sa #sdp_printer_t, #sdp_session_t, sdp_printing_error(),
|
|
* sdp_message(), sdp_message_size(), sdp_printer_free(),
|
|
* sdp_parse().
|
|
*/
|
|
sdp_printer_t *sdp_print(su_home_t *home,
|
|
sdp_session_t const *session,
|
|
char msgbuf[],
|
|
isize_t msgsize,
|
|
int flags)
|
|
{
|
|
sdp_printer_t *p = su_salloc(home, sizeof(*p));
|
|
|
|
if (p) {
|
|
p->pr_size = sizeof(p);
|
|
p->pr_home = home;
|
|
p->pr_used = 0;
|
|
if (msgbuf) {
|
|
p->pr_may_realloc = (flags & sdp_f_realloc) != 0;
|
|
p->pr_buffer = msgbuf;
|
|
p->pr_bsiz = msgsize;
|
|
if (flags & sdp_f_print_prefix)
|
|
p->pr_used = strlen(msgbuf);
|
|
}
|
|
else {
|
|
p->pr_owns_buffer = 1;
|
|
p->pr_buffer = su_alloc(home, SDP_BLOCK);
|
|
p->pr_bsiz = SDP_BLOCK;
|
|
}
|
|
p->pr_strict = (flags & sdp_f_strict) != 0;
|
|
p->pr_all_rtpmaps = (flags & sdp_f_all_rtpmaps) != 0;
|
|
p->pr_mode_manual = (flags & sdp_f_mode_manual) != 0;
|
|
p->pr_mode_always = (flags & sdp_f_mode_always) != 0;
|
|
|
|
if (session)
|
|
print_session(p, session);
|
|
else
|
|
printing_error(p, "NULL session description");
|
|
|
|
return p;
|
|
}
|
|
else {
|
|
return &printer_memory_error;
|
|
}
|
|
}
|
|
|
|
/** @brief Get encoding error.
|
|
*
|
|
* Return a message describing the encoding error.
|
|
*
|
|
* @param p Pointer to an #sdp_printer_t object.
|
|
*
|
|
* @return
|
|
* Return a pointer to C string describing printing errors, or NULL if no
|
|
* error was encountered.
|
|
*/
|
|
char const *sdp_printing_error(sdp_printer_t *p)
|
|
{
|
|
if (p)
|
|
if (!p->pr_ok)
|
|
return p->pr_buffer;
|
|
else
|
|
return NULL;
|
|
else
|
|
return "null sdp_printer_t*";
|
|
}
|
|
|
|
/** @brief Get encoded SDP message.
|
|
*
|
|
* Return a pointer to a C string containing the SDP message.
|
|
*
|
|
* @param p Pointer to an #sdp_printer_t object.
|
|
*
|
|
* @return
|
|
* Return a pointer to a C string containing the encoded SDP message, or
|
|
* NULL upon an error.
|
|
*/
|
|
char const *sdp_message(sdp_printer_t *p)
|
|
{
|
|
if (p && p->pr_ok)
|
|
return p->pr_buffer;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
/** @brief Get size of encoded SDP message.
|
|
*
|
|
* Return the size of the encoded SDP message.
|
|
*
|
|
* @param p Pointer to an #sdp_printer_t object.
|
|
*
|
|
* @return
|
|
* Number of bytes in SDP message excluding final NUL or 0 upon an error.
|
|
*/
|
|
isize_t sdp_message_size(sdp_printer_t *p)
|
|
{
|
|
if (p && p->pr_ok)
|
|
return p->pr_used;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
/** Free a SDP printer.
|
|
*
|
|
* Free the printer object @a p and the message buffer possibly associated
|
|
* with it.
|
|
*
|
|
* @param p Pointer to an #sdp_printer_t object.
|
|
*/
|
|
void sdp_printer_free(sdp_printer_t *p)
|
|
{
|
|
if (p && p != &printer_memory_error) {
|
|
if (p->pr_owns_buffer && p->pr_buffer)
|
|
su_free(p->pr_home, p->pr_buffer), p->pr_buffer = NULL;
|
|
su_free(p->pr_home, p);
|
|
}
|
|
}
|
|
|
|
/* ========================================================================= */
|
|
static void print_version(sdp_printer_t *p, sdp_version_t const *v);
|
|
static void print_origin(sdp_printer_t *p, sdp_origin_t const *o);
|
|
static void print_subject(sdp_printer_t *p, sdp_text_t *s);
|
|
static void print_information(sdp_printer_t *p, sdp_text_t *i);
|
|
static void print_uri(sdp_printer_t *p, sdp_text_t *u);
|
|
static void print_emails(sdp_printer_t *p, sdp_list_t const *e);
|
|
static void print_phones(sdp_printer_t *p, sdp_list_t const *ph);
|
|
static void print_connection(sdp_printer_t *p, sdp_connection_t const *c);
|
|
static void print_connection_list(sdp_printer_t *p, sdp_connection_t const *c);
|
|
static void print_connection2(sdp_printer_t *p, sdp_connection_t const *c);
|
|
static void print_bandwidths(sdp_printer_t *p, sdp_bandwidth_t const *b);
|
|
static void print_time(sdp_printer_t *p, sdp_time_t const *t);
|
|
static void print_repeat(sdp_printer_t *p, sdp_repeat_t const *r);
|
|
static void print_zone(sdp_printer_t *p, sdp_zone_t const *z);
|
|
static void print_typed_time(sdp_printer_t *p, unsigned long t);
|
|
static void print_key(sdp_printer_t *p, sdp_key_t const *k);
|
|
static void print_attributes(sdp_printer_t *p, sdp_attribute_t const *a);
|
|
static void print_charset(sdp_printer_t *p, sdp_text_t *charset);
|
|
static void print_media(sdp_printer_t *p, sdp_session_t const *,
|
|
sdp_media_t const *m);
|
|
|
|
static void print_text_list(sdp_printer_t*,
|
|
const char *, sdp_list_t const *l);
|
|
|
|
static void sdp_printf(sdp_printer_t *p, const char *fmt, ...);
|
|
|
|
static void print_session(sdp_printer_t *p, sdp_session_t const *sdp)
|
|
{
|
|
p->pr_ok = 1;
|
|
|
|
if (p->pr_ok && sdp->sdp_version)
|
|
print_version(p, sdp->sdp_version);
|
|
if (p->pr_ok && sdp->sdp_origin)
|
|
print_origin(p, sdp->sdp_origin);
|
|
if (p->pr_ok && sdp->sdp_subject)
|
|
print_subject(p, sdp->sdp_subject);
|
|
if (p->pr_ok && sdp->sdp_information)
|
|
print_information(p, sdp->sdp_information);
|
|
if (p->pr_ok && sdp->sdp_uri)
|
|
print_uri(p, sdp->sdp_uri);
|
|
if (p->pr_ok && sdp->sdp_emails)
|
|
print_emails(p, sdp->sdp_emails);
|
|
if (p->pr_ok && sdp->sdp_phones)
|
|
print_phones(p, sdp->sdp_phones);
|
|
if (p->pr_ok && sdp->sdp_connection)
|
|
print_connection(p, sdp->sdp_connection);
|
|
if (p->pr_ok && sdp->sdp_bandwidths)
|
|
print_bandwidths(p, sdp->sdp_bandwidths);
|
|
if (p->pr_ok)
|
|
print_time(p, sdp->sdp_time);
|
|
if (p->pr_ok && sdp->sdp_time) {
|
|
if (p->pr_ok && sdp->sdp_time->t_repeat)
|
|
print_repeat(p, sdp->sdp_time->t_repeat);
|
|
if (p->pr_ok && sdp->sdp_time->t_zone)
|
|
print_zone(p, sdp->sdp_time->t_zone);
|
|
}
|
|
if (p->pr_ok && sdp->sdp_key)
|
|
print_key(p, sdp->sdp_key);
|
|
if (p->pr_ok && sdp->sdp_charset)
|
|
print_charset(p, sdp->sdp_charset);
|
|
if (p->pr_ok && sdp->sdp_attributes)
|
|
print_attributes(p, sdp->sdp_attributes);
|
|
if (p->pr_ok && sdp->sdp_media)
|
|
print_media(p, sdp, sdp->sdp_media);
|
|
}
|
|
|
|
static void print_version(sdp_printer_t *p, sdp_version_t const *v)
|
|
{
|
|
sdp_printf(p, "v=%lu" CRLF, *v);
|
|
}
|
|
|
|
static void print_origin(sdp_printer_t *p, sdp_origin_t const *o)
|
|
{
|
|
if (!o->o_address ||
|
|
!o->o_address->c_address ||
|
|
o->o_address->c_ttl != 0 ||
|
|
o->o_address->c_groups > 1) {
|
|
printing_error(p, "o= address malformed");
|
|
return;
|
|
}
|
|
|
|
sdp_printf(p, "o=%s "LLU" "LLU" ",
|
|
o->o_username,
|
|
(ull)o->o_id,
|
|
(ull)o->o_version);
|
|
|
|
print_connection2(p, o->o_address);
|
|
}
|
|
|
|
static void print_subject(sdp_printer_t *p, sdp_text_t *subject)
|
|
{
|
|
sdp_printf(p, "s=%s" CRLF, subject);
|
|
}
|
|
|
|
static void print_information(sdp_printer_t *p, sdp_text_t *information)
|
|
{
|
|
sdp_printf(p, "i=%s" CRLF, information);
|
|
}
|
|
|
|
static void print_uri(sdp_printer_t *p, sdp_text_t *uri)
|
|
{
|
|
sdp_printf(p, "u=%s" CRLF, uri);
|
|
}
|
|
|
|
static void print_emails(sdp_printer_t *p, sdp_list_t const *emails)
|
|
{
|
|
print_text_list(p, "e=%s" CRLF, emails);
|
|
}
|
|
|
|
static void print_phones(sdp_printer_t *p, sdp_list_t const *phones)
|
|
{
|
|
print_text_list(p, "p=%s" CRLF, phones);
|
|
}
|
|
|
|
static void print_connection(sdp_printer_t *p, sdp_connection_t const *c)
|
|
{
|
|
sdp_printf(p, "c=");
|
|
print_connection2(p, c);
|
|
}
|
|
|
|
static void print_connection_list(sdp_printer_t *p, sdp_connection_t const *c)
|
|
{
|
|
for (; c ; c = c->c_next) {
|
|
sdp_printf(p, "c=");
|
|
print_connection2(p, c);
|
|
}
|
|
}
|
|
|
|
static void print_connection2(sdp_printer_t *p, sdp_connection_t const *c)
|
|
{
|
|
const char *nettype;
|
|
const char *addrtype;
|
|
|
|
switch (c->c_nettype) {
|
|
case sdp_net_x:
|
|
nettype = NULL;
|
|
break;
|
|
case sdp_net_in:
|
|
nettype = "IN ";
|
|
break;
|
|
default:
|
|
printing_error(p, "unknown nettype %u", c->c_nettype);
|
|
return;
|
|
}
|
|
|
|
switch (c->c_addrtype) {
|
|
case sdp_addr_x:
|
|
addrtype = NULL;
|
|
break;
|
|
case sdp_addr_ip4:
|
|
nettype = "IN ";
|
|
addrtype = "IP4 ";
|
|
break;
|
|
case sdp_addr_ip6:
|
|
nettype = "IN ";
|
|
addrtype = "IP6 ";
|
|
break;
|
|
default:
|
|
printing_error(p, "unknown address type %u", c->c_addrtype);
|
|
return;
|
|
}
|
|
|
|
if (c->c_address == NULL) {
|
|
printing_error(p, "missing address");
|
|
return;
|
|
}
|
|
|
|
if (nettype && addrtype)
|
|
sdp_printf(p, "%s%s%s", nettype, addrtype, c->c_address);
|
|
else if (nettype)
|
|
sdp_printf(p, "%s%s%s", nettype, c->c_address);
|
|
else
|
|
sdp_printf(p, "%s", c->c_address);
|
|
|
|
if (c->c_mcast || c->c_ttl) {
|
|
sdp_printf(p, "/%u", c->c_ttl);
|
|
if (c->c_groups > 1)
|
|
sdp_printf(p, "/%u", c->c_groups);
|
|
}
|
|
sdp_printf(p, CRLF);
|
|
}
|
|
|
|
static void print_bandwidths(sdp_printer_t *p, sdp_bandwidth_t const *b)
|
|
{
|
|
for (; b ; b = b->b_next) {
|
|
char const *name;
|
|
|
|
switch (b->b_modifier) {
|
|
case sdp_bw_ct: name = "CT"; break;
|
|
case sdp_bw_as: name = "AS"; break;
|
|
default: name = b->b_modifier_name; break;
|
|
}
|
|
|
|
sdp_printf(p, "b=%s:%lu" CRLF, name, b->b_value);
|
|
}
|
|
}
|
|
|
|
static void print_time(sdp_printer_t *p, sdp_time_t const *t)
|
|
{
|
|
if (t || p->pr_strict)
|
|
sdp_printf(p, "t=%lu %lu" CRLF, t ? t->t_start : 0L, t ? t->t_stop : 0L);
|
|
}
|
|
|
|
static void print_repeat(sdp_printer_t *p, sdp_repeat_t const *r)
|
|
{
|
|
int i;
|
|
|
|
sdp_printf(p, "r=");
|
|
print_typed_time(p, r->r_interval);
|
|
sdp_printf(p, " ");
|
|
print_typed_time(p, r->r_duration);
|
|
for (i = 0; i < r->r_number_of_offsets; i++) {
|
|
sdp_printf(p, " ");
|
|
print_typed_time(p, r->r_offsets[i]);
|
|
}
|
|
sdp_printf(p, CRLF);
|
|
}
|
|
|
|
static void print_zone(sdp_printer_t *p, sdp_zone_t const *z)
|
|
{
|
|
int i;
|
|
sdp_printf(p, "z=");
|
|
|
|
for (i = 0; i < z->z_number_of_adjustments; i++) {
|
|
int negative = z->z_adjustments[i].z_offset < 0L;
|
|
sdp_printf(p, "%s%lu %s",
|
|
i > 0 ? " " : "",
|
|
z->z_adjustments[i].z_at,
|
|
negative ? "-" : "");
|
|
if (negative)
|
|
print_typed_time(p, -z->z_adjustments[i].z_offset);
|
|
else
|
|
print_typed_time(p, z->z_adjustments[i].z_offset);
|
|
}
|
|
|
|
sdp_printf(p, CRLF);
|
|
}
|
|
|
|
static void print_typed_time(sdp_printer_t *p, unsigned long t)
|
|
{
|
|
if (t % 60 || t == 0) {
|
|
sdp_printf(p, "%lu", t);
|
|
}
|
|
else {
|
|
t /= 60;
|
|
|
|
if (t % 60) {
|
|
sdp_printf(p, "%lum", t); /* minutes */
|
|
}
|
|
else {
|
|
t /= 60;
|
|
|
|
if (t % 24) {
|
|
sdp_printf(p, "%luh", t); /* hours */
|
|
}
|
|
else {
|
|
t /= 24;
|
|
|
|
sdp_printf(p, "%lud", t); /* days */
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void print_key(sdp_printer_t *p, sdp_key_t const *k)
|
|
{
|
|
const char *method;
|
|
int have_material = k->k_material != NULL;
|
|
|
|
switch (k->k_method) {
|
|
case sdp_key_x:
|
|
method = k->k_method_name; break;
|
|
case sdp_key_clear:
|
|
method = "clear"; break;
|
|
case sdp_key_base64:
|
|
method = "base64"; break;
|
|
case sdp_key_uri:
|
|
method = "uri"; break;
|
|
case sdp_key_prompt:
|
|
method = "prompt"; break;
|
|
default:
|
|
printing_error(p, "unknown key method (%d)", k->k_method);
|
|
return;
|
|
}
|
|
|
|
sdp_printf(p, "k=%s%s%s" CRLF, method,
|
|
have_material ? ":" : "",
|
|
have_material ? k->k_material : "");
|
|
}
|
|
|
|
static void print_attributes(sdp_printer_t *p, sdp_attribute_t const *a)
|
|
{
|
|
for (;a; a = a->a_next) {
|
|
char const *name = a->a_name;
|
|
char const *value = a->a_value;
|
|
sdp_printf(p, "a=%s%s%s" CRLF, name, value ? ":" : "", value ? value : "");
|
|
}
|
|
}
|
|
|
|
static void
|
|
print_attributes_without_mode(sdp_printer_t *p, sdp_attribute_t const *a)
|
|
{
|
|
for (;a; a = a->a_next) {
|
|
char const *name = a->a_name;
|
|
char const *value = a->a_value;
|
|
|
|
if (su_casematch(name, "inactive") ||
|
|
su_casematch(name, "sendonly") ||
|
|
su_casematch(name, "recvonly") ||
|
|
su_casematch(name, "sendrecv"))
|
|
continue;
|
|
|
|
sdp_printf(p, "a=%s%s%s" CRLF, name, value ? ":" : "", value ? value : "");
|
|
}
|
|
}
|
|
|
|
static void print_charset(sdp_printer_t *p, sdp_text_t *charset)
|
|
{
|
|
sdp_printf(p, "a=charset%s%s" CRLF, charset ? ":" : "", charset ? charset : "");
|
|
}
|
|
|
|
static void print_media(sdp_printer_t *p,
|
|
sdp_session_t const *sdp,
|
|
sdp_media_t const *m)
|
|
{
|
|
char const *media, *proto;
|
|
sdp_rtpmap_t *rm;
|
|
|
|
sdp_mode_t session_mode = sdp_sendrecv;
|
|
|
|
if (!p->pr_mode_manual)
|
|
session_mode = sdp_attribute_mode(sdp->sdp_attributes, sdp_sendrecv);
|
|
|
|
for (;m ; m = m->m_next) {
|
|
switch (m->m_type) {
|
|
case sdp_media_audio: media = "audio"; break;
|
|
case sdp_media_video: media = "video"; break;
|
|
case sdp_media_application: media = "application"; break;
|
|
case sdp_media_data: media = "data"; break;
|
|
case sdp_media_control: media = "control"; break;
|
|
case sdp_media_message: media = "message"; break;
|
|
case sdp_media_image : media = "image"; break;
|
|
default: media = m->m_type_name;
|
|
}
|
|
|
|
switch (m->m_proto) {
|
|
case sdp_proto_tcp: proto = "tcp"; break;
|
|
case sdp_proto_udp: proto = "udp"; break;
|
|
case sdp_proto_rtp: proto = "RTP/AVP"; break;
|
|
case sdp_proto_srtp: proto = "RTP/SAVP"; break;
|
|
case sdp_proto_udptl: proto = "udptl"; break;
|
|
case sdp_proto_tls: proto = "tls"; break;
|
|
default: proto = m->m_proto_name; break;
|
|
}
|
|
|
|
if (m->m_number_of_ports <= 1)
|
|
sdp_printf(p, "m=%s %u %s", media, m->m_port, proto);
|
|
else
|
|
sdp_printf(p, "m=%s %u/%u %s",
|
|
media, m->m_port, m->m_number_of_ports, proto);
|
|
|
|
if (m->m_rtpmaps) {
|
|
for (rm = m->m_rtpmaps; rm; rm = rm->rm_next) {
|
|
if (rm->rm_any)
|
|
sdp_printf(p, " *");
|
|
else
|
|
sdp_printf(p, " %u", (unsigned)rm->rm_pt);
|
|
}
|
|
}
|
|
else if (m->m_format) {
|
|
sdp_list_t *l = m->m_format;
|
|
for (; l; l = l->l_next)
|
|
sdp_printf(p, " %s", l->l_text);
|
|
}
|
|
else {
|
|
sdp_printf(p, " 19"); /* SDP syntax requires at least one format.
|
|
19 is used by nobody, right?. */
|
|
}
|
|
|
|
|
|
sdp_printf(p, CRLF);
|
|
|
|
if (m->m_information)
|
|
print_information(p, m->m_information);
|
|
if (m->m_connections)
|
|
#ifdef nomore
|
|
if (m->m_connections != sdp->sdp_connection)
|
|
#endif
|
|
print_connection_list(p, m->m_connections);
|
|
if (m->m_bandwidths)
|
|
print_bandwidths(p, m->m_bandwidths);
|
|
if (m->m_key)
|
|
print_key(p, m->m_key);
|
|
|
|
for (rm = m->m_rtpmaps; rm; rm = rm->rm_next) {
|
|
if (!rm->rm_predef || p->pr_all_rtpmaps)
|
|
sdp_printf(p, "a=rtpmap:%u %s/%lu%s%s" CRLF,
|
|
rm->rm_pt, rm->rm_encoding, rm->rm_rate,
|
|
rm->rm_params ? "/" : "",
|
|
rm->rm_params ? rm->rm_params : "");
|
|
if (rm->rm_fmtp)
|
|
sdp_printf(p, "a=fmtp:%u %s" CRLF,
|
|
rm->rm_pt, rm->rm_fmtp);
|
|
}
|
|
|
|
if (!p->pr_mode_manual && !m->m_rejected &&
|
|
(m->m_mode != (unsigned int)session_mode || p->pr_mode_always)) {
|
|
switch (m->m_mode) {
|
|
case sdp_inactive:
|
|
sdp_printf(p, "a=inactive" CRLF);
|
|
break;
|
|
case sdp_sendonly:
|
|
sdp_printf(p, "a=sendonly" CRLF);
|
|
break;
|
|
case sdp_recvonly:
|
|
sdp_printf(p, "a=recvonly" CRLF);
|
|
break;
|
|
case sdp_sendrecv:
|
|
sdp_printf(p, "a=sendrecv" CRLF);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (p->pr_mode_manual)
|
|
print_attributes(p, m->m_attributes);
|
|
else
|
|
print_attributes_without_mode(p, m->m_attributes);
|
|
}
|
|
}
|
|
|
|
static void print_text_list(sdp_printer_t *p,
|
|
const char *fmt, sdp_list_t const *l)
|
|
{
|
|
for (;l; l = l->l_next) {
|
|
sdp_printf(p, fmt, l->l_text);
|
|
}
|
|
}
|
|
|
|
static void printing_error(sdp_printer_t *p, const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
if (p->pr_ok) {
|
|
int n;
|
|
va_start(ap, fmt);
|
|
n = vsnprintf(p->pr_buffer, p->pr_bsiz, fmt, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
p->pr_ok = 0;
|
|
}
|
|
|
|
static void sdp_printf(sdp_printer_t *p, const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
while (p->pr_ok) {
|
|
int n;
|
|
|
|
va_start(ap, fmt);
|
|
n = vsnprintf(p->pr_buffer + p->pr_used, p->pr_bsiz - p->pr_used, fmt, ap);
|
|
va_end(ap);
|
|
|
|
if (n > -1 && (size_t)n < p->pr_bsiz - p->pr_used) {
|
|
p->pr_used += n;
|
|
break;
|
|
}
|
|
else {
|
|
if (p->pr_owns_buffer) {
|
|
p->pr_buffer = su_realloc(p->pr_home, p->pr_buffer, 2 * p->pr_bsiz);
|
|
if (p->pr_buffer) {
|
|
p->pr_bsiz = 2 * p->pr_bsiz;
|
|
continue;
|
|
}
|
|
p->pr_owns_buffer = 0;
|
|
}
|
|
else if (p->pr_may_realloc) {
|
|
char *buffer;
|
|
size_t size;
|
|
if (p->pr_bsiz < SDP_BLOCK)
|
|
size = SDP_BLOCK;
|
|
else
|
|
size = 2 * p->pr_bsiz;
|
|
buffer = su_alloc(p->pr_home, size);
|
|
if (buffer) {
|
|
p->pr_owns_buffer = 1;
|
|
p->pr_buffer = memcpy(buffer, p->pr_buffer, p->pr_bsiz);
|
|
p->pr_bsiz = size;
|
|
continue;
|
|
}
|
|
}
|
|
p->pr_ok = 0;
|
|
p->pr_buffer = "Memory exhausted";
|
|
}
|
|
}
|
|
}
|