This source file includes following definitions.
- gf_sdp_fmtp_new
- gf_sdp_fmtp_del
- SDP_GetFMTPForPayload
- SDP_ParseAttribute
- gf_sdp_media_del
- gf_sdp_conn_new
- gf_sdp_conn_del
- gf_sdp_media_new
- gf_sdp_info_new
- gf_sdp_info_reset
- gf_sdp_info_del
- SDP_IsDynamicPayload
- SDP_MakeSeconds
- gf_sdp_info_parse
- SDP_CheckConnection
- gf_sdp_info_check
- gf_sdp_info_write
#include <gpac/ietf.h>
#ifndef GPAC_DISABLE_STREAMING
#include <gpac/token.h>
#define SDP_WRITE_STEPALLOC 2048
GF_EXPORT
GF_SDP_FMTP *gf_sdp_fmtp_new()
{
GF_SDP_FMTP *tmp = (GF_SDP_FMTP*)gf_malloc(sizeof(GF_SDP_FMTP));
tmp->PayloadType = 0;
tmp->Attributes = gf_list_new();
return tmp;
}
GF_EXPORT
void gf_sdp_fmtp_del(GF_SDP_FMTP *fmtp)
{
GF_X_Attribute *att;
if (!fmtp) return;
while (gf_list_count(fmtp->Attributes)) {
att = (GF_X_Attribute*)gf_list_get(fmtp->Attributes, 0);
gf_list_rem(fmtp->Attributes, 0);
if (att->Name) gf_free(att->Name);
if (att->Value) gf_free(att->Value);
gf_free(att);
}
gf_list_del(fmtp->Attributes);
gf_free(fmtp);
}
GF_SDP_FMTP *SDP_GetFMTPForPayload(GF_SDPMedia *media, u32 PayloadType)
{
GF_SDP_FMTP *tmp;
u32 i;
if (!media) return NULL;
i=0;
while ((tmp = (GF_SDP_FMTP*)gf_list_enum(media->FMTP, &i))) {
if (tmp->PayloadType == PayloadType) return tmp;
}
return NULL;
}
void SDP_ParseAttribute(GF_SDPInfo *sdp, char *buffer, GF_SDPMedia *media)
{
s32 pos;
u32 PayT;
char comp[3000];
GF_RTPMap *map;
GF_SDP_FMTP *fmtp;
GF_X_Attribute *att;
pos = gf_token_get(buffer, 0, " :\t\r\n", comp, 3000);
if (!strcmp(comp, "cat")) {
if (media) return;
gf_token_get(buffer, pos, ":\t\r\n", comp, 3000);
sdp->a_cat = gf_strdup(comp);
return;
}
if (!strcmp(comp, "keywds")) {
if (media) return;
gf_token_get(buffer, pos, ":\t\r\n", comp, 3000);
sdp->a_keywds = gf_strdup(comp);
return;
}
if (!strcmp(comp, "tool")) {
if (media) return;
gf_token_get(buffer, pos, ":\r\n", comp, 3000);
sdp->a_tool = gf_strdup(comp);
return;
}
if (!strcmp(comp, "ptime")) {
if (!media) return;
gf_token_get(buffer, pos, ":\r\n", comp, 3000);
media->PacketTime = atoi(comp);
return;
}
if (!strcmp(comp, "recvonly")) {
if (!media) {
sdp->a_SendReceive = 1;
} else {
media->SendReceive = 1;
}
return;
}
if (!strcmp(comp, "sendonly")) {
if (!media) {
sdp->a_SendReceive = 2;
} else {
media->SendReceive = 2;
}
return;
}
if (!strcmp(comp, "sendrecv")) {
if (!media) {
sdp->a_SendReceive = 3;
} else {
media->SendReceive = 3;
}
return;
}
if (!strcmp(comp, "orient")) {
if (!media || media->Type) return;
gf_token_get(buffer, pos, ":\r\n", comp, 3000);
media->orientation = gf_strdup(comp);
return;
}
if (!strcmp(comp, "type")) {
if (media) return;
gf_token_get(buffer, pos, ":\r\n", comp, 3000);
sdp->a_type = gf_strdup(comp);
return;
}
if (!strcmp(comp, "charset")) {
if (media) return;
gf_token_get(buffer, pos, ":\r\n", comp, 3000);
sdp->a_charset = gf_strdup(comp);
return;
}
if (!strcmp(comp, "sdplang")) {
gf_token_get(buffer, pos, ":\r\n", comp, 3000);
if (media) {
media->sdplang = gf_strdup(comp);
} else {
sdp->a_sdplang = gf_strdup(comp);
}
return;
}
if (!strcmp(comp, "lang")) {
gf_token_get(buffer, pos, ":\r\n", comp, 3000);
if (media) {
media->lang = gf_strdup(comp);
} else {
sdp->a_lang = gf_strdup(comp);
}
return;
}
if (!strcmp(comp, "framerate")) {
if (!media || (media->Type != 1)) return;
gf_token_get(buffer, pos, ":\r\n", comp, 3000);
media->FrameRate = atof(comp);
return;
}
if (!strcmp(comp, "quality")) {
if (!media) return;
gf_token_get(buffer, pos, ":\r\n", comp, 3000);
media->Quality = atoi(comp);
return;
}
if (!strcmp(comp, "rtpmap")) {
if (!media) return;
map = (GF_RTPMap*)gf_malloc(sizeof(GF_RTPMap));
pos = gf_token_get(buffer, pos, ": \r\n", comp, 3000);
map->PayloadType = atoi(comp);
pos = gf_token_get(buffer, pos, " /\r\n", comp, 3000);
map->payload_name = gf_strdup(comp);
pos = gf_token_get(buffer, pos, " /\r\n", comp, 3000);
map->ClockRate = atoi(comp);
pos = gf_token_get(buffer, pos, " /\r\n", comp, 3000);
map->AudioChannels = (pos > 0) ? atoi(comp) : 0;
gf_list_add(media->RTPMaps, map);
return;
}
if (!strcmp(comp, "fmtp")) {
if (!media) return;
pos = gf_token_get(buffer, pos, ": \r\n", comp, 3000);
PayT = atoi(comp);
fmtp = SDP_GetFMTPForPayload(media, PayT);
if (!fmtp) {
fmtp = gf_sdp_fmtp_new();
fmtp->PayloadType = PayT;
gf_list_add(media->FMTP, fmtp);
}
while (1) {
pos = gf_token_get(buffer, pos, "; =\r\n", comp, 3000);
if (pos <= 0) break;
att = (GF_X_Attribute*)gf_malloc(sizeof(GF_X_Attribute));
att->Name = gf_strdup(comp);
att->Value = NULL;
pos ++;
pos = gf_token_get(buffer, pos, ";\r\n", comp, 3000);
if (pos > 0) att->Value = gf_strdup(comp);
gf_list_add(fmtp->Attributes, att);
}
return;
}
pos = gf_token_get(buffer, 0, " :\r\n", comp, 3000);
att = (GF_X_Attribute*)gf_malloc(sizeof(GF_X_Attribute));
att->Name = gf_strdup(comp);
att->Value = NULL;
pos += 1;
if (buffer[pos] == ' ') pos += 1;
pos = gf_token_get(buffer, pos, "\r\n", comp, 3000);
if (pos > 0) att->Value = gf_strdup(comp);
if (media) {
gf_list_add(media->Attributes, att);
} else {
gf_list_add(sdp->Attributes, att);
}
}
#define SDPM_DESTROY(p) if (media->p) gf_free(media->p)
GF_EXPORT
void gf_sdp_media_del(GF_SDPMedia *media)
{
GF_SDPBandwidth *bw;
GF_RTPMap *map;
GF_SDPConnection *conn;
GF_SDP_FMTP *fmtp;
GF_X_Attribute *att;
if (!media) return;
while (gf_list_count(media->FMTP)) {
fmtp = (GF_SDP_FMTP*)gf_list_get(media->FMTP, 0);
gf_list_rem(media->FMTP, 0);
gf_sdp_fmtp_del(fmtp);
}
gf_list_del(media->FMTP);
while (gf_list_count(media->Attributes)) {
att = (GF_X_Attribute*)gf_list_get(media->Attributes, 0);
gf_list_rem(media->Attributes, 0);
if (att->Name) gf_free(att->Name);
if (att->Value) gf_free(att->Value);
gf_free(att);
}
gf_list_del(media->Attributes);
while (gf_list_count(media->RTPMaps)) {
map = (GF_RTPMap*)gf_list_get(media->RTPMaps, 0);
gf_free(map->payload_name);
gf_free(map);
gf_list_rem(media->RTPMaps, 0);
}
gf_list_del(media->RTPMaps);
while (gf_list_count(media->Connections)) {
conn = (GF_SDPConnection*)gf_list_get(media->Connections, 0);
gf_list_rem(media->Connections, 0);
gf_sdp_conn_del(conn);
}
gf_list_del(media->Connections);
while (gf_list_count(media->Bandwidths)) {
bw = (GF_SDPBandwidth*)gf_list_get(media->Bandwidths, 0);
gf_list_rem(media->Bandwidths, 0);
if (bw->name) gf_free(bw->name);
gf_free(bw);
}
gf_list_del(media->Bandwidths);
SDPM_DESTROY(orientation);
SDPM_DESTROY(sdplang);
SDPM_DESTROY(lang);
SDPM_DESTROY(Profile);
SDPM_DESTROY(fmt_list);
SDPM_DESTROY(k_method);
SDPM_DESTROY(k_key);
gf_free(media);
}
GF_EXPORT
GF_SDPConnection *gf_sdp_conn_new()
{
GF_SDPConnection *conn;
GF_SAFEALLOC(conn, GF_SDPConnection);
if (!conn) return NULL;
conn->TTL = -1;
return conn;
}
GF_EXPORT
void gf_sdp_conn_del(GF_SDPConnection *conn)
{
if (conn->add_type) gf_free(conn->add_type);
if (conn->host) gf_free(conn->host);
if (conn->net_type) gf_free(conn->net_type);
gf_free(conn);
}
GF_EXPORT
GF_SDPMedia *gf_sdp_media_new()
{
GF_SDPMedia *tmp;
GF_SAFEALLOC(tmp, GF_SDPMedia);
if (!tmp) return NULL;
tmp->FMTP = gf_list_new();
tmp->RTPMaps = gf_list_new();
tmp->Attributes = gf_list_new();
tmp->Connections = gf_list_new();
tmp->Bandwidths = gf_list_new();
tmp->Quality = -1;
return tmp;
}
GF_EXPORT
GF_SDPInfo *gf_sdp_info_new()
{
GF_SDPInfo *sdp;
GF_SAFEALLOC(sdp, GF_SDPInfo);
if (!sdp) return NULL;
sdp->b_bandwidth = gf_list_new();
sdp->media_desc = gf_list_new();
sdp->Attributes = gf_list_new();
sdp->Timing = gf_list_new();
return sdp;
}
#define SDP_DESTROY(p) if (sdp->p) \
gf_free(sdp->p); \
sdp->p = NULL;
GF_EXPORT
void gf_sdp_info_reset(GF_SDPInfo *sdp)
{
GF_SDPBandwidth *bw;
GF_SDPMedia *media;
GF_SDPTiming *timing;
GF_X_Attribute *att;
if (!sdp) return;
while (gf_list_count(sdp->media_desc)) {
media = (GF_SDPMedia*)gf_list_get(sdp->media_desc, 0);
gf_list_rem(sdp->media_desc, 0);
gf_sdp_media_del(media);
}
while (gf_list_count(sdp->Attributes)) {
att = (GF_X_Attribute*)gf_list_get(sdp->Attributes, 0);
gf_list_rem(sdp->Attributes, 0);
if (att->Name) gf_free(att->Name);
if (att->Value) gf_free(att->Value);
gf_free(att);
}
while (gf_list_count(sdp->b_bandwidth)) {
bw = (GF_SDPBandwidth*)gf_list_get(sdp->b_bandwidth, 0);
gf_list_rem(sdp->b_bandwidth, 0);
if (bw->name) gf_free(bw->name);
gf_free(bw);
}
while (gf_list_count(sdp->Timing)) {
timing = (GF_SDPTiming*)gf_list_get(sdp->Timing, 0);
gf_list_rem(sdp->Timing, 0);
gf_free(timing);
}
SDP_DESTROY(o_username);
SDP_DESTROY(o_session_id);
SDP_DESTROY(o_version);
SDP_DESTROY(o_address);
SDP_DESTROY(o_net_type);
SDP_DESTROY(o_add_type);
SDP_DESTROY(s_session_name);
SDP_DESTROY(i_description);
SDP_DESTROY(u_uri);
SDP_DESTROY(e_email);
SDP_DESTROY(p_phone);
SDP_DESTROY(k_method);
SDP_DESTROY(k_key);
SDP_DESTROY(a_cat);
SDP_DESTROY(a_keywds);
SDP_DESTROY(a_tool);
SDP_DESTROY(a_type);
SDP_DESTROY(a_charset);
SDP_DESTROY(a_sdplang);
SDP_DESTROY(a_lang);
if (sdp->c_connection) {
gf_sdp_conn_del(sdp->c_connection);
sdp->c_connection = NULL;
}
sdp->a_SendReceive = 0;
}
GF_EXPORT
void gf_sdp_info_del(GF_SDPInfo *sdp)
{
if (!sdp) return;
gf_sdp_info_reset(sdp);
gf_list_del(sdp->media_desc);
gf_list_del(sdp->Attributes);
gf_list_del(sdp->b_bandwidth);
gf_list_del(sdp->Timing);
gf_free(sdp);
}
Bool SDP_IsDynamicPayload(GF_SDPMedia *media, char *payt)
{
u32 i;
GF_RTPMap *map;
char buf[10];
i=0;
while ((map = (GF_RTPMap*)gf_list_enum(media->RTPMaps, &i))) {
sprintf(buf, "%d", map->PayloadType);
if (!strcmp(payt, buf)) return GF_TRUE;
}
return GF_FALSE;
}
s32 SDP_MakeSeconds(char *buf)
{
s32 sign;
char num[30], *test;
sign = 1;
if (buf[0] == '-') {
sign = -1;
buf += 1;
}
memset(num, 0, 30);
test = strstr(buf, "d");
if (test) {
assert(strlen(buf)-strlen(test) < sizeof(num));
strncpy(num, buf, strlen(buf)-strlen(test));
return (atoi(num)*sign*86400);
}
test = strstr(buf, "h");
if (test) {
assert(strlen(buf)-strlen(test) < sizeof(num));
strncpy(num, buf, strlen(buf)-strlen(test));
return (atoi(num)*sign*3600);
}
test = strstr(buf, "m");
if (test) {
assert(strlen(buf)-strlen(test) < sizeof(num));
strncpy(num, buf, strlen(buf)-strlen(test));
return (atoi(num)*sign*60);
}
return (atoi(buf) * sign);
}
GF_EXPORT
GF_Err gf_sdp_info_parse(GF_SDPInfo *sdp, char *sdp_text, u32 text_size)
{
GF_SDPBandwidth *bw;
GF_SDPConnection *conn;
GF_SDPMedia *media;
GF_SDPTiming *timing;
u32 i;
s32 pos, LinePos;
char LineBuf[3000], comp[3000];
media = NULL;
timing = NULL;
if (!sdp) return GF_BAD_PARAM;
gf_sdp_info_reset(sdp);
LinePos = 0;
while (1) {
LinePos = gf_token_get_line(sdp_text, LinePos, text_size, LineBuf, 3000);
if (LinePos <= 0) break;
if (!strcmp(LineBuf, "\r\n") || !strcmp(LineBuf, "\n") || !strcmp(LineBuf, "\r")) continue;
switch (LineBuf[0]) {
case 'v':
gf_token_get(LineBuf, 2, "\t\r\n", comp, 3000);
sdp->Version = atoi(comp);
break;
case 'o':
pos = gf_token_get(LineBuf, 2, " \t\r\n", comp, 3000);
sdp->o_username = gf_strdup(comp);
pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000);
sdp->o_session_id = gf_strdup(comp);
pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000);
sdp->o_version = gf_strdup(comp);
pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000);
sdp->o_net_type = gf_strdup(comp);
pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000);
sdp->o_add_type = gf_strdup(comp);
gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000);
sdp->o_address = gf_strdup(comp);
break;
case 's':
gf_token_get(LineBuf, 2, "\t\r\n", comp, 3000);
sdp->s_session_name = gf_strdup(comp);
break;
case 'i':
gf_token_get(LineBuf, 2, "\t\r\n", comp, 3000);
sdp->i_description = gf_strdup(comp);
break;
case 'u':
gf_token_get(LineBuf, 2, "\t\r\n", comp, 3000);
sdp->u_uri = gf_strdup(comp);
break;
case 'e':
gf_token_get(LineBuf, 2, "\t\r\n", comp, 3000);
sdp->e_email = gf_strdup(comp);
break;
case 'p':
gf_token_get(LineBuf, 2, "\t\r\n", comp, 3000);
sdp->p_phone = gf_strdup(comp);
break;
case 'c':
if (sdp->c_connection) break;
conn = gf_sdp_conn_new();
pos = gf_token_get(LineBuf, 2, " \t\r\n", comp, 3000);
conn->net_type = gf_strdup(comp);
pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000);
conn->add_type = gf_strdup(comp);
pos = gf_token_get(LineBuf, pos, " /\r\n", comp, 3000);
conn->host = gf_strdup(comp);
if (gf_sk_is_multicast_address(conn->host)) {
pos = gf_token_get(LineBuf, pos, "/\r\n", comp, 3000);
if (pos > 0) {
conn->TTL = atoi(comp);
pos = gf_token_get(LineBuf, pos, "/\r\n", comp, 3000);
}
if (pos > 0) {
if (!media) {
gf_sdp_conn_del(conn);
break;
}
conn->add_count = atoi(comp);
}
}
if (!media)
sdp->c_connection = conn;
else
gf_list_add(media->Connections, conn);
break;
case 'b':
pos = gf_token_get(LineBuf, 2, ":\r\n", comp, 3000);
if (strcmp(comp, "CT") && strcmp(comp, "AS") && (comp[0] != 'X')) break;
GF_SAFEALLOC(bw, GF_SDPBandwidth);
if (!bw) return GF_OUT_OF_MEM;
bw->name = gf_strdup(comp);
gf_token_get(LineBuf, pos, ":\r\n", comp, 3000);
bw->value = atoi(comp);
if (media) {
gf_list_add(media->Bandwidths, bw);
} else {
gf_list_add(sdp->b_bandwidth, bw);
}
break;
case 't':
if (media) break;
GF_SAFEALLOC(timing, GF_SDPTiming);
if (!timing) return GF_OUT_OF_MEM;
pos = gf_token_get(LineBuf, 2, " \t\r\n", comp, 3000);
timing->StartTime = atoi(comp);
gf_token_get(LineBuf, pos, "\r\n", comp, 3000);
timing->StopTime = atoi(comp);
gf_list_add(sdp->Timing, timing);
break;
case 'r':
if (media) break;
pos = gf_token_get(LineBuf, 2, " \t\r\n", comp, 3000);
if (!timing) return GF_NON_COMPLIANT_BITSTREAM;
timing->RepeatInterval = SDP_MakeSeconds(comp);
pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000);
timing->ActiveDuration = SDP_MakeSeconds(comp);
while (1) {
pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000);
if (pos <= 0) break;
timing->OffsetFromStart[timing->NbRepeatOffsets] = SDP_MakeSeconds(comp);
timing->NbRepeatOffsets += 1;
}
break;
case 'z':
if (media) break;
pos = 2;
if (!timing) return GF_NON_COMPLIANT_BITSTREAM;
while (1) {
pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000);
if (pos <= 0) break;
timing->AdjustmentTime[timing->NbZoneOffsets] = atoi(comp);
pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000);
timing->AdjustmentOffset[timing->NbZoneOffsets] = SDP_MakeSeconds(comp);
timing->NbZoneOffsets += 1;
}
break;
case 'k':
pos = gf_token_get(LineBuf, 2, ":\t\r\n", comp, 3000);
if (media) {
media->k_method = gf_strdup(comp);
} else {
sdp->k_method = gf_strdup(comp);
}
pos = gf_token_get(LineBuf, pos, ":\r\n", comp, 3000);
if (pos > 0) {
if (media) {
media->k_key = gf_strdup(comp);
} else {
sdp->k_key = gf_strdup(comp);
}
}
break;
case 'a':
SDP_ParseAttribute(sdp, LineBuf+2, media);
break;
case 'm':
pos = gf_token_get(LineBuf, 2, " \t\r\n", comp, 3000);
if (strcmp(comp, "audio")
&& strcmp(comp, "data")
&& strcmp(comp, "control")
&& strcmp(comp, "video")
&& strcmp(comp, "text")
&& strcmp(comp, "application")) {
return GF_SERVICE_ERROR;
}
media = gf_sdp_media_new();
if (!strcmp(comp, "video")) media->Type = 1;
else if (!strcmp(comp, "audio")) media->Type = 2;
else if (!strcmp(comp, "text")) media->Type = 3;
else if (!strcmp(comp, "data")) media->Type = 4;
else if (!strcmp(comp, "control")) media->Type = 5;
else media->Type = 0;
gf_token_get(LineBuf, pos, " ", comp, 3000);
if (!strstr(comp, "/")) {
pos = gf_token_get(LineBuf, pos, " \r\n", comp, 3000);
media->PortNumber = atoi(comp);
media->NumPorts = 0;
} else {
pos = gf_token_get(LineBuf, pos, " /\r\n", comp, 3000);
media->PortNumber = atoi(comp);
pos = gf_token_get(LineBuf, pos, " \r\n", comp, 3000);
media->NumPorts = atoi(comp);
}
pos = gf_token_get(LineBuf, pos, " \r\n", comp, 3000);
media->Profile = gf_strdup(comp);
gf_token_get(LineBuf, pos, " \r\n", comp, 3000);
media->fmt_list = gf_strdup(comp);
gf_list_add(sdp->media_desc, media);
break;
}
}
i=0;
while ((media = (GF_SDPMedia*)gf_list_enum(sdp->media_desc, &i))) {
pos = 0;
LinePos = 1;
strcpy(LineBuf, "");
while (1) {
if (!media->fmt_list) break;
pos = gf_token_get(media->fmt_list, pos, " ", comp, 3000);
if (pos <= 0) break;
if (!SDP_IsDynamicPayload(media, comp)) {
if (!LinePos) {
strcat(LineBuf, " ");
} else {
LinePos = 0;
}
strcat(LineBuf, comp);
}
gf_free(media->fmt_list);
media->fmt_list = NULL;
if (strlen(LineBuf)) {
media->fmt_list = gf_strdup(LineBuf);
}
}
}
return GF_OK;
}
GF_Err SDP_CheckConnection(GF_SDPConnection *conn)
{
if (!conn) return GF_BAD_PARAM;
if (!conn->host || !conn->add_type || !conn->net_type) return GF_REMOTE_SERVICE_ERROR;
if (gf_sk_is_multicast_address(conn->host)) {
if (conn->TTL < 0 || conn->TTL > 255) return GF_REMOTE_SERVICE_ERROR;
} else {
conn->TTL = -1;
conn->add_count = 0;
}
return GF_OK;
}
GF_EXPORT
GF_Err gf_sdp_info_check(GF_SDPInfo *sdp)
{
GF_Err e;
u32 i, j, count;
GF_SDPMedia *media;
GF_SDPConnection *conn;
GF_RTPMap *map;
Bool HasGlobalConnection, HasSeveralPorts;
if (!sdp || !sdp->media_desc || !sdp->Attributes) return GF_BAD_PARAM;
if (!gf_list_count(sdp->media_desc)) return GF_REMOTE_SERVICE_ERROR;
if (!sdp->o_add_type || !sdp->o_address || !sdp->o_username || !sdp->o_session_id || !sdp->o_version)
return GF_REMOTE_SERVICE_ERROR;
if (sdp->c_connection) {
e = SDP_CheckConnection(sdp->c_connection);
if (e) return e;
if (sdp->c_connection->add_count >= 2) return GF_REMOTE_SERVICE_ERROR;
HasGlobalConnection = GF_TRUE;
} else {
HasGlobalConnection = GF_FALSE;
}
i=0;
while ((media = (GF_SDPMedia*)gf_list_enum(sdp->media_desc, &i))) {
HasSeveralPorts = GF_FALSE;
if ( !media->Profile) return GF_REMOTE_SERVICE_ERROR;
if (media->NumPorts) HasSeveralPorts = GF_TRUE;
if (HasGlobalConnection && gf_list_count(media->Connections)) return GF_REMOTE_SERVICE_ERROR;
count = gf_list_count(media->Connections);
if (count>1 && HasSeveralPorts) return GF_REMOTE_SERVICE_ERROR;
for (j=0; j<count; j++) {
conn = (GF_SDPConnection*)gf_list_get(media->Connections, j);
e = SDP_CheckConnection(conn);
if (e) return e;
if ((conn->add_count >= 2) && HasSeveralPorts) return GF_REMOTE_SERVICE_ERROR;
}
j=0;
while ((map = (GF_RTPMap*)gf_list_enum(media->RTPMaps, &j))) {
if (!map->payload_name || !map->ClockRate) return GF_REMOTE_SERVICE_ERROR;
}
}
return GF_OK;
}
#define SDP_WRITE_ALLOC_STR_WITHOUT_CHECK(str, space) \
if (strlen(str)+pos + (space ? 1 : 0) >= buf_size) { \
buf_size += SDP_WRITE_STEPALLOC; \
buf = (char*)gf_realloc(buf, sizeof(char)*buf_size); \
} \
strcpy(buf+pos, str); \
pos += (u32) strlen(str); \
if (space) { \
strcat(buf+pos, " "); \
pos += 1; \
}
#define SDP_WRITE_ALLOC_STR(str, space) \
if (str) { \
SDP_WRITE_ALLOC_STR_WITHOUT_CHECK(str, space); \
} \
#define SDP_WRITE_ALLOC_INT(d, spa, sig) \
if (sig < 0) { \
sprintf(temp, "%d", d); \
} else { \
sprintf(temp, "%u", d); \
} \
SDP_WRITE_ALLOC_STR_WITHOUT_CHECK(temp, spa);
#define SDP_WRITE_ALLOC_FLOAT(d, spa) \
sprintf(temp, "%.2f", d); \
SDP_WRITE_ALLOC_STR_WITHOUT_CHECK(temp, spa);
#define TEST_SDP_WRITE_SINGLE(type, str, sep) \
if (str) { \
SDP_WRITE_ALLOC_STR(type, 0); \
if (sep) SDP_WRITE_ALLOC_STR(":", 0); \
SDP_WRITE_ALLOC_STR(str, 0); \
SDP_WRITE_ALLOC_STR("\r\n", 0); \
}
#define SDP_WRITE_CONN(conn) \
if (conn) { \
SDP_WRITE_ALLOC_STR("c=", 0); \
SDP_WRITE_ALLOC_STR(conn->net_type, 1); \
SDP_WRITE_ALLOC_STR(conn->add_type, 1); \
SDP_WRITE_ALLOC_STR(conn->host, 0); \
if (gf_sk_is_multicast_address(conn->host)) { \
SDP_WRITE_ALLOC_STR("/", 0); \
SDP_WRITE_ALLOC_INT(conn->TTL, 0, 0); \
if (conn->add_count >= 2) { \
SDP_WRITE_ALLOC_STR("/", 0); \
SDP_WRITE_ALLOC_INT(conn->add_count, 0, 0); \
} \
} \
SDP_WRITE_ALLOC_STR("\r\n", 0); \
}
GF_EXPORT
GF_Err gf_sdp_info_write(GF_SDPInfo *sdp, char **out_str_buf)
{
char *buf;
GF_SDP_FMTP *fmtp;
char temp[50];
GF_SDPMedia *media;
GF_SDPBandwidth *bw;
u32 buf_size, pos, i, j, k;
GF_RTPMap *map;
GF_SDPConnection *conn;
GF_Err e;
GF_SDPTiming *timing;
GF_X_Attribute *att;
e = gf_sdp_info_check(sdp);
if (e) return e;
buf = (char *)gf_malloc(SDP_WRITE_STEPALLOC);
buf_size = SDP_WRITE_STEPALLOC;
pos = 0;
SDP_WRITE_ALLOC_STR("v=", 0);
SDP_WRITE_ALLOC_INT(sdp->Version, 0, 0);
SDP_WRITE_ALLOC_STR("\r\n", 0);
SDP_WRITE_ALLOC_STR("o=", 0);
SDP_WRITE_ALLOC_STR(sdp->o_username, 1);
SDP_WRITE_ALLOC_STR(sdp->o_session_id, 1);
SDP_WRITE_ALLOC_STR(sdp->o_version, 1);
SDP_WRITE_ALLOC_STR(sdp->o_net_type, 1);
SDP_WRITE_ALLOC_STR(sdp->o_add_type, 1);
SDP_WRITE_ALLOC_STR(sdp->o_address, 0);
SDP_WRITE_ALLOC_STR("\r\n", 0);
TEST_SDP_WRITE_SINGLE("s=", sdp->s_session_name, 0);
TEST_SDP_WRITE_SINGLE("i=", sdp->i_description, 0);
TEST_SDP_WRITE_SINGLE("u=", sdp->u_uri, 0);
TEST_SDP_WRITE_SINGLE("e=", sdp->e_email, 0);
TEST_SDP_WRITE_SINGLE("p=", sdp->p_phone, 0);
SDP_WRITE_CONN(sdp->c_connection);
i=0;
while ((bw = (GF_SDPBandwidth*)gf_list_enum(sdp->b_bandwidth, &i))) {
SDP_WRITE_ALLOC_STR("b=", 0);
SDP_WRITE_ALLOC_STR(bw->name, 0);
SDP_WRITE_ALLOC_STR(":", 0);
SDP_WRITE_ALLOC_INT(bw->value, 0, 0);
SDP_WRITE_ALLOC_STR("\r\n", 0);
}
i=0;
while ((timing = (GF_SDPTiming*)gf_list_enum(sdp->Timing, &i))) {
if (timing->NbRepeatOffsets > GF_SDP_MAX_TIMEOFFSET) timing->NbRepeatOffsets = GF_SDP_MAX_TIMEOFFSET;
if (timing->NbZoneOffsets > GF_SDP_MAX_TIMEOFFSET) timing->NbZoneOffsets = GF_SDP_MAX_TIMEOFFSET;
SDP_WRITE_ALLOC_STR("t=", 0);
SDP_WRITE_ALLOC_INT(timing->StartTime, 1, 0);
SDP_WRITE_ALLOC_INT(timing->StopTime, 0, 0);
SDP_WRITE_ALLOC_STR("\r\n", 0);
if (timing->NbRepeatOffsets) {
SDP_WRITE_ALLOC_STR("r=", 0);
SDP_WRITE_ALLOC_INT(timing->RepeatInterval, 1, 0);
SDP_WRITE_ALLOC_INT(timing->ActiveDuration, 0, 0);
for (j=0; j<timing->NbRepeatOffsets; j++) {
SDP_WRITE_ALLOC_STR(" ", 0);
SDP_WRITE_ALLOC_INT(timing->OffsetFromStart[j], 0, 0);
}
SDP_WRITE_ALLOC_STR("\r\n", 0);
}
if (timing->NbZoneOffsets) {
SDP_WRITE_ALLOC_STR("z=", 0);
for (j=0; j<timing->NbZoneOffsets; j++) {
SDP_WRITE_ALLOC_INT(timing->AdjustmentTime[j], 1, 0);
if (j+1 == timing->NbRepeatOffsets) {
SDP_WRITE_ALLOC_INT(timing->AdjustmentOffset[j], 0, 1);
} else {
SDP_WRITE_ALLOC_INT(timing->AdjustmentOffset[j], 1, 1);
}
}
SDP_WRITE_ALLOC_STR("\r\n", 0);
}
}
if (sdp->k_method) {
SDP_WRITE_ALLOC_STR("k=", 0);
SDP_WRITE_ALLOC_STR(sdp->k_method, 0);
if (sdp->k_key) {
SDP_WRITE_ALLOC_STR(":", 0);
SDP_WRITE_ALLOC_STR(sdp->k_key, 0);
}
SDP_WRITE_ALLOC_STR("\r\n", 0);
}
TEST_SDP_WRITE_SINGLE("a=cat", sdp->a_cat, 1);
TEST_SDP_WRITE_SINGLE("a=keywds", sdp->a_keywds, 1);
TEST_SDP_WRITE_SINGLE("a=tool", sdp->a_tool, 1);
switch (sdp->a_SendReceive) {
case 1:
TEST_SDP_WRITE_SINGLE("a=", "recvonly", 0);
break;
case 2:
TEST_SDP_WRITE_SINGLE("a=", "sendonly", 0);
break;
case 3:
TEST_SDP_WRITE_SINGLE("a=", "sendrecv", 0);
break;
default:
break;
}
TEST_SDP_WRITE_SINGLE("a=type", sdp->a_type, 1);
TEST_SDP_WRITE_SINGLE("a=charset", sdp->a_charset, 1);
TEST_SDP_WRITE_SINGLE("a=sdplang", sdp->a_sdplang, 1);
TEST_SDP_WRITE_SINGLE("a=lang", sdp->a_lang, 1);
i=0;
while ((att = (GF_X_Attribute*)gf_list_enum(sdp->Attributes, &i))) {
SDP_WRITE_ALLOC_STR("a=", 0);
SDP_WRITE_ALLOC_STR(att->Name, 0);
if (att->Value) {
SDP_WRITE_ALLOC_STR(":", 0);
SDP_WRITE_ALLOC_STR(att->Value, 0);
}
SDP_WRITE_ALLOC_STR("\r\n", 0);
}
i=0;
while ((media = (GF_SDPMedia*)gf_list_enum(sdp->media_desc, &i))) {
SDP_WRITE_ALLOC_STR("m=", 0);
switch (media->Type) {
case 1:
SDP_WRITE_ALLOC_STR("video", 1);
break;
case 2:
SDP_WRITE_ALLOC_STR("audio", 1);
break;
case 3:
SDP_WRITE_ALLOC_STR("data", 1);
break;
case 4:
SDP_WRITE_ALLOC_STR("control", 1);
break;
default:
SDP_WRITE_ALLOC_STR("application", 1);
break;
}
SDP_WRITE_ALLOC_INT(media->PortNumber, 0, 0);
if (media->NumPorts >= 2) {
SDP_WRITE_ALLOC_STR("/", 0);
SDP_WRITE_ALLOC_INT(media->NumPorts, 1, 0);
} else {
SDP_WRITE_ALLOC_STR(" ", 0);
}
SDP_WRITE_ALLOC_STR(media->Profile, 1);
SDP_WRITE_ALLOC_STR(media->fmt_list, 0);
j=0;
while ((map = (GF_RTPMap*)gf_list_enum(media->RTPMaps, &j))) {
SDP_WRITE_ALLOC_STR(" ", 0);
SDP_WRITE_ALLOC_INT(map->PayloadType, 0, 0);
}
SDP_WRITE_ALLOC_STR("\r\n", 0);
j=0;
while ((conn = (GF_SDPConnection*)gf_list_enum(media->Connections, &j))) {
SDP_WRITE_CONN(conn);
}
if (media->k_method) {
SDP_WRITE_ALLOC_STR("k=", 0);
SDP_WRITE_ALLOC_STR(media->k_method, 0);
if (media->k_key) {
SDP_WRITE_ALLOC_STR(":", 0);
SDP_WRITE_ALLOC_STR(media->k_key, 0);
}
SDP_WRITE_ALLOC_STR("\r\n", 0);
}
j=0;
while ((bw = (GF_SDPBandwidth*)gf_list_enum(media->Bandwidths, &j))) {
SDP_WRITE_ALLOC_STR("b=", 0);
SDP_WRITE_ALLOC_STR(bw->name, 0);
SDP_WRITE_ALLOC_STR(":", 0);
SDP_WRITE_ALLOC_INT(bw->value, 0, 0);
SDP_WRITE_ALLOC_STR("\r\n", 0);
}
j=0;
while ((map = (GF_RTPMap*)gf_list_enum(media->RTPMaps, &j))) {
SDP_WRITE_ALLOC_STR("a=rtpmap", 0);
SDP_WRITE_ALLOC_STR(":", 0);
SDP_WRITE_ALLOC_INT(map->PayloadType, 1, 0);
SDP_WRITE_ALLOC_STR(map->payload_name, 0);
SDP_WRITE_ALLOC_STR("/", 0);
SDP_WRITE_ALLOC_INT(map->ClockRate, 0, 0);
if (map->AudioChannels > 1) {
SDP_WRITE_ALLOC_STR("/", 0);
SDP_WRITE_ALLOC_INT(map->AudioChannels, 0, 0);
}
SDP_WRITE_ALLOC_STR("\r\n", 0);
}
j=0;
while ((fmtp = (GF_SDP_FMTP*)gf_list_enum(media->FMTP, &j))) {
SDP_WRITE_ALLOC_STR("a=fmtp:", 0);
SDP_WRITE_ALLOC_INT(fmtp->PayloadType, 1 , 0);
k=0;
while ((att = (GF_X_Attribute*)gf_list_enum(fmtp->Attributes, &k)) ) {
if (k>1) SDP_WRITE_ALLOC_STR(";", 0);
SDP_WRITE_ALLOC_STR(att->Name, 0);
if (att->Value) {
SDP_WRITE_ALLOC_STR("=", 0);
SDP_WRITE_ALLOC_STR(att->Value, 0);
}
}
SDP_WRITE_ALLOC_STR("\r\n", 0);
}
if (media->PacketTime) {
SDP_WRITE_ALLOC_STR("a=ptime:", 0);
SDP_WRITE_ALLOC_INT(media->PacketTime, 0, 0);
SDP_WRITE_ALLOC_STR("\r\n", 0);
}
if (media->Type == 1 && media->FrameRate) {
SDP_WRITE_ALLOC_STR("a=framerate:", 0);
SDP_WRITE_ALLOC_FLOAT(media->FrameRate, 0);
SDP_WRITE_ALLOC_STR("\r\n", 0);
}
switch (media->SendReceive) {
case 1:
TEST_SDP_WRITE_SINGLE("a=", "recvonly", 0);
break;
case 2:
TEST_SDP_WRITE_SINGLE("a=", "sendonly", 0);
break;
case 3:
TEST_SDP_WRITE_SINGLE("a=", "sendrecv", 0);
break;
default:
break;
}
TEST_SDP_WRITE_SINGLE("a=orient", media->orientation, 1);
TEST_SDP_WRITE_SINGLE("a=sdplang", media->sdplang, 1);
TEST_SDP_WRITE_SINGLE("a=lang", media->lang, 1);
if (media->Quality >= 0) {
SDP_WRITE_ALLOC_STR("a=quality:", 0);
SDP_WRITE_ALLOC_INT(media->Quality, 0, 0);
SDP_WRITE_ALLOC_STR("\r\n", 0);
}
j=0;
while ((att = (GF_X_Attribute*)gf_list_enum(media->Attributes, &j))) {
SDP_WRITE_ALLOC_STR("a=", 0);
SDP_WRITE_ALLOC_STR(att->Name, 0);
if (att->Value) {
SDP_WRITE_ALLOC_STR(":", 0);
SDP_WRITE_ALLOC_STR(att->Value, 0);
}
SDP_WRITE_ALLOC_STR("\r\n", 0);
}
}
pos += 1;
buf = (char *)gf_realloc(buf, pos);
*out_str_buf = buf;
return GF_OK;
}
#endif