|
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825 |
- #include "sdp.h"
- #include <errno.h>
- #include <stdlib.h>
- #include <string.h>
- #include <assert.h>
-
- #if defined(OS_WINDOWS)
- #define strdup _strdup
- #define strcasecmp _stricmp
- #endif
-
- #define N_EMAIL 1
- #define N_PHONE 1
- #define N_CONNECTION 1
- #define N_BANDWIDTH 1
- #define N_TIMING 1
- #define N_REPEAT 1
- #define N_TIMEZONE 1
- #define N_REPEAT_OFFSET 1
- #define N_ATTRIBUTE 5
- #define N_MEDIA 3 // audio/video/whiteboard
- #define N_MEDIA_FORMAT 5
-
- struct sdp_connection
- {
- char* network;
- char* addrtype;
- char* address;
- };
-
- struct sdp_origin
- {
- char* username;
- char* session;
- char* session_version;
- struct sdp_connection c;
- };
-
- struct sdp_email
- {
- char* email;
- };
-
- struct sdp_phone
- {
- char* phone;
- };
-
- struct sdp_bandwidth
- {
- char* bwtype;
- char* bandwidth;
- };
-
- struct bandwidths
- {
- int count;
- int capacity;
- struct sdp_bandwidth bandwidths[N_BANDWIDTH];
- struct sdp_bandwidth *ptr;
- };
-
- struct sdp_repeat
- {
- char* interval;
- char* duration;
-
- struct offset
- {
- int count;
- int capacity;
- char *offsets[N_REPEAT_OFFSET];
- char **ptr;
- } offsets;
- };
-
- struct sdp_timezone
- {
- char* time;
- char* offset;
- };
-
- struct sdp_timing
- {
- char* start;
- char* stop;
-
- struct repeat
- {
- int count;
- int capacity;
- struct sdp_repeat repeats[N_REPEAT];
- struct sdp_repeat *ptr;
- } r;
-
- struct timezone_t
- {
- int count;
- int capacity;
- struct sdp_timezone timezones[N_TIMEZONE];
- struct sdp_timezone *ptr;
- } z;
- };
-
- struct sdp_encryption
- {
- char* method;
- char* key;
- };
-
- struct sdp_attribute
- {
- char* name;
- char* value;
- };
-
- struct attributes
- {
- int count;
- int capacity;
- struct sdp_attribute attrs[N_ATTRIBUTE];
- struct sdp_attribute *ptr;
- };
-
- struct sdp_media
- {
- char* media; //audio, video, text, application, message
- char* port;
- char* proto; // udp, RTP/AVP, RTP/SAVP
- struct format
- {
- int count;
- int capacity;
- char *formats[N_MEDIA_FORMAT];
- char **ptr;
- } fmt;
-
- char* i;
- struct connection
- {
- int count;
- int capacity;
- struct sdp_connection connections[N_EMAIL];
- struct sdp_connection *ptr;
- } c;
-
- struct attributes a;
- struct bandwidths b;
- struct sdp_encryption k;
- };
-
- struct sdp_t
- {
- char *raw; // raw source string
- int offset; // parse offset
-
- int v;
-
- struct sdp_origin o;
- char* s;
- char* i;
- char* u;
-
- struct email
- {
- int count;
- int capacity;
- struct sdp_email emails[N_EMAIL];
- struct sdp_email *ptr;
- } e;
-
- struct phone
- {
- int count;
- int capacity;
- struct sdp_phone phones[N_PHONE];
- struct sdp_phone *ptr;
- } p;
-
- struct sdp_connection c;
-
- struct bandwidths b;
-
- struct timing
- {
- int count;
- int capacity;
- struct sdp_timing times[N_TIMING];
- struct sdp_timing *ptr;
- } t;
-
- struct sdp_encryption k;
-
- struct attributes a;
-
- struct media
- {
- int count;
- int capacity;
- struct sdp_media medias[N_MEDIA];
- struct sdp_media *ptr;
- } m;
- };
-
- static inline void sdp_skip_space(struct sdp_t* sdp)
- {
- char c = sdp->raw[sdp->offset];
- while(' ' == c || '\t' == c)
- c = sdp->raw[++sdp->offset];
- }
-
- static inline int sdp_token_word(struct sdp_t* sdp, const char* escape)
- {
- int n = sdp->offset;
- sdp->offset += strcspn(sdp->raw + sdp->offset, escape);
- return sdp->offset - n;
- }
-
- static inline int sdp_token_crlf(struct sdp_t* sdp)
- {
- sdp_skip_space(sdp);
-
- if('\r' == sdp->raw[sdp->offset])
- ++sdp->offset;
-
- if('\n' == sdp->raw[sdp->offset])
- {
- ++sdp->offset;
- return 0;
- }
-
- // sdp end line
- if('\0' == sdp->raw[sdp->offset])
- return 0;
-
- return -1;
- }
-
- static inline void trim_right(const char* s, int *len)
- {
- //// left trim
- //while(*len > 0 && isspace(s[*pos]))
- //{
- // --*len;
- // ++*pos;
- //}
-
- // right trim
- while(*len > 0 && ' '==(s[*len - 1]))
- {
- --*len;
- }
- }
-
- static inline struct sdp_timing* sdp_get_timing(struct sdp_t* sdp, int idx)
- {
- if(idx >= sdp->t.count)
- return NULL;
-
- return idx >= N_TIMING ? &sdp->t.ptr[idx - N_TIMING] : &sdp->t.times[idx];
- }
-
- static inline struct sdp_media* sdp_get_media(struct sdp_t* sdp, int idx)
- {
- if(idx >= sdp->m.count)
- return NULL;
-
- return idx >= N_MEDIA ? &sdp->m.ptr[idx - N_MEDIA] : &sdp->m.medias[idx];
- }
-
- // RFC4566 5.1
- static int sdp_parse_version(struct sdp_t* sdp)
- {
- char c;
- assert(sdp);
-
- if(!sdp) return -1;
- sdp->v = 0;
-
- sdp_skip_space(sdp);
-
- c = sdp->raw[sdp->offset];
- while('0' <= c && c <= '9')
- {
- sdp->v = sdp->v * 10 + (c - '0');
- c = sdp->raw[++sdp->offset];
- }
-
- return sdp_token_crlf(sdp);
- }
-
- // RFC4566 5.2
- // o=<username> <sess-id> <sess-version> <nettype> <addrtype> <unicast-address>
- // <username> "-" if the originating host does not support the concept of user IDs.
- // <sess-id> is a numeric string
- // <sess-version> is a version number for this session description
- // <nettype> IN
- // <addrtype> IP4/IP6
- static int sdp_parse_origin(struct sdp_t* sdp)
- {
- char* v[6];
- char** vv[6];
- int i, j, n[6];
- struct sdp_origin *o;
- static const char* default_username = "-";
-
- o = &sdp->o;
- memset(o, 0, sizeof(struct sdp_origin));
- memset(n, 0, sizeof(n));
-
- sdp_skip_space(sdp);
- for (i = 0; i < 6 && sdp->raw[sdp->offset] && !strchr("\r\n", sdp->raw[sdp->offset]); i++)
- {
- v[i] = sdp->raw + sdp->offset;
- n[i] = sdp_token_word(sdp, " \t\r\n");
- sdp_skip_space(sdp);
- }
-
- sdp_token_crlf(sdp);
- if (i < 5)
- return 0;
-
- o->username = (char*)default_username; // default value
- vv[0] = &o->username;
- vv[1] = &o->session;
- vv[2] = &o->session_version;
- vv[3] = &o->c.network;
- vv[4] = &o->c.addrtype;
- vv[5] = &o->c.address;
- for (j = 5; i > 0; j--)
- {
- i--;
- v[i][n[i]] = '\0';
- *vv[j] = v[i];
- }
-
- return 0;
- }
-
- // RFC4566 5.3
- // s=<session name>
- // There MUST be one and only one "s=" field per session description. can be empty
- static int sdp_parse_session(struct sdp_t* sdp)
- {
- int n = 0;
-
- sdp->s = sdp->raw + sdp->offset;
-
- n = sdp_token_word(sdp, "\r\n");
- if(0 != sdp_token_crlf(sdp))
- return -1;
-
- sdp->s[n] = '\0';
- return 0;
- }
-
- // RFC4566 5.4
- // i=<session description>
- // There MUST be at most one session-level "i=" field per session description,
- // and at most one "i=" field per media.
- // default UTF-8
- static int sdp_parse_information(struct sdp_t* sdp)
- {
- int n = 0;
- char **i;
-
- if(sdp->m.count > 0)
- {
- i = &sdp_get_media(sdp, sdp->m.count-1)->i;
- }
- else
- {
- i = &sdp->i;
- }
-
- *i = sdp->raw + sdp->offset;
-
- n = sdp_token_word(sdp, "\r\n");
- if(0 != sdp_token_crlf(sdp))
- return -1;
-
- (*i)[n] = '\0';
- return 0;
- }
-
- // RFC4566 5.5
- // u=<uri>
- // This field is OPTIONAL, but if it is present it MUST be
- // specified before the first media field.
- static int sdp_parse_uri(struct sdp_t* sdp)
- {
- int n = 0;
-
- // No more than one URI field is allowed per session description.
- assert(!sdp->u);
-
- sdp->u = sdp->raw + sdp->offset;
-
- n = sdp_token_word(sdp, "\r\n");
- if(0 != sdp_token_crlf(sdp))
- return -1;
-
- sdp->u[n] = '\0';
- return 0;
- }
-
- // RFC4566 5.6
- // e=<email-address>
- // p=<phone-number>
- // OPTIONAL, If an email address or phone number is present, it MUST be specified
- // before the first media field. More than one email or phone field can
- // be given for a session description.
- // p=+1 617 555-6011
- // e=j.doe@example.com (Jane Doe)
- // e=Jane Doe <j.doe@example.com>
- static int sdp_parse_email(struct sdp_t* sdp)
- {
- int n = 0;
- struct sdp_email *e;
-
- if(sdp->e.count >= N_EMAIL)
- {
- if(sdp->e.count - N_EMAIL >= sdp->e.capacity)
- {
- void* ptr;
- ptr = (struct sdp_email*)realloc(sdp->e.ptr, (sdp->e.capacity+8)*sizeof(struct sdp_email));
- if(!ptr)
- return -ENOMEM;
-
- sdp->e.ptr = ptr;
- sdp->e.capacity += 8;
- }
-
- e = &sdp->e.ptr[sdp->e.count - N_EMAIL];
- }
- else
- {
- e = &sdp->e.emails[sdp->e.count];
- }
-
- memset(e, 0, sizeof(struct sdp_email));
- e->email = sdp->raw + sdp->offset;
-
- n = sdp_token_word(sdp, "\r\n");
- if(0 != sdp_token_crlf(sdp))
- return -1;
-
- e->email[n] = '\0';
- ++sdp->e.count;
- return 0;
- }
-
- static int sdp_parse_phone(struct sdp_t* sdp)
- {
- int n = 0;
- struct sdp_phone *p;
-
- if(sdp->p.count >= N_PHONE)
- {
- if(sdp->p.count - N_PHONE >= sdp->p.capacity)
- {
- void* ptr;
- ptr = (struct sdp_phone*)realloc(sdp->p.ptr, (sdp->p.capacity+8)*sizeof(struct sdp_phone));
- if(!ptr)
- return -ENOMEM;
-
- sdp->p.ptr = ptr;
- sdp->p.capacity += 8;
- }
-
- p = &sdp->p.ptr[sdp->p.count - N_PHONE];
- }
- else
- {
- p = &sdp->p.phones[sdp->p.count];
- }
-
- memset(p, 0, sizeof(struct sdp_phone));
- p->phone = sdp->raw + sdp->offset;
-
- n = sdp_token_word(sdp, "\r\n");
- if(0 != sdp_token_crlf(sdp))
- return -1;
-
- trim_right(p->phone, &n);
- p->phone[n] = '\0';
- ++sdp->p.count;
- return 0;
- }
-
- // RFC4566 5.7
- // c=<nettype> <addrtype> <connection-address>
- // A session description MUST contain either at least one "c=" field in
- // each media description or a single "c=" field at the session level.
- // c=IN IP4 224.2.36.42/127
- // c=IN IP4 224.2.1.1/127/3
- // c=IN IP6 FF15::101/3
- // The slash notation for multiple addresses described above MUST NOT be
- // used for IP unicast addresses
- static int sdp_parse_connection(struct sdp_t* sdp)
- {
- int n[3];
- struct sdp_media *m;
- struct sdp_connection *c;
-
- m = NULL;
- if(sdp->m.count > 0)
- {
- m = sdp_get_media(sdp, sdp->m.count-1);
- if(m->c.count >= N_CONNECTION)
- {
- if(m->c.count - N_CONNECTION >= m->c.capacity)
- {
- void* ptr;
- ptr = (struct sdp_connection*)realloc(m->c.ptr, (m->c.capacity+8)*sizeof(struct sdp_connection));
- if(!ptr)
- return -ENOMEM;
-
- m->c.ptr = ptr;
- m->c.capacity += 8;
- }
-
- c = &m->c.ptr[m->c.count - N_CONNECTION];
- }
- else
- {
- c = &m->c.connections[m->c.count];
- }
- }
- else
- {
- c = &sdp->c;
- }
-
- memset(c, 0, sizeof(struct sdp_connection));
- memset(n, 0, sizeof(n));
-
- sdp_skip_space(sdp);
- c->network = sdp->raw + sdp->offset;
- n[0] = sdp_token_word(sdp, " \t\r\n");
-
- sdp_skip_space(sdp);
- c->addrtype = sdp->raw + sdp->offset;
- n[1] = sdp_token_word(sdp, " \t\r\n");
-
- sdp_skip_space(sdp);
- c->address = sdp->raw + sdp->offset;
- n[2] = sdp_token_word(sdp, "\r\n");
- trim_right(c->address, &n[2]);
-
- // check before assign '\0'
- if(0==sdp_token_crlf(sdp) && n[0]>0 && n[1]>0 && n[2]>0)
- {
- c->network[n[0]] = '\0';
- c->addrtype[n[1]] = '\0';
- c->address[n[2]] = '\0';
- if(m) ++m->c.count; // add media connection
- return 0;
- }
-
- return -1;
- }
-
- // RFC4566 5.8
- // b=<bwtype>:<bandwidth>
- // bwtype: CT/AS
- // bandwidth: kilobits per second by default
- // A prefix "X-" is defined for <bwtype> names.
- // b=X-YZ:128
- static int sdp_parse_bandwidth(struct sdp_t* sdp)
- {
- int n[2];
- struct bandwidths *bs;
- struct sdp_bandwidth *b;
-
- if(sdp->m.count > 0)
- {
- bs = &sdp_get_media(sdp, sdp->m.count-1)->b;
- }
- else
- {
- bs = &sdp->b;
- }
-
- if(bs->count >= N_BANDWIDTH)
- {
- if(bs->count - N_BANDWIDTH >= bs->capacity)
- {
- void* ptr;
- ptr = (struct sdp_bandwidth*)realloc(bs->ptr, (bs->capacity+8)*sizeof(struct sdp_bandwidth));
- if(!ptr)
- return -ENOMEM;
-
- bs->ptr = ptr;
- bs->capacity += 8;
- }
-
- b = &bs->ptr[bs->count - N_BANDWIDTH];
- }
- else
- {
- b = &bs->bandwidths[bs->count];
- }
-
- memset(n, 0, sizeof(n));
- memset(b, 0, sizeof(struct sdp_bandwidth));
-
- sdp_skip_space(sdp);
- b->bwtype = sdp->raw + sdp->offset;
- n[0] = sdp_token_word(sdp, ":\r\n");
- trim_right(b->bwtype, &n[0]);
-
- if(':' == sdp->raw[sdp->offset])
- ++sdp->offset;
-
- sdp_skip_space(sdp);
- b->bandwidth = sdp->raw + sdp->offset;
- n[1] = sdp_token_word(sdp, "\r\n");
- trim_right(b->bandwidth, &n[1]);
-
- if(0 == sdp_token_crlf(sdp))
- {
- ++bs->count;
- b->bwtype[n[0]] = '\0';
- b->bandwidth[n[1]] = '\0';
- return 0;
- }
- return -1;
- }
-
- // RFC4566 5.9 (p17)
- // t=<start-time> <stop-time>
- // If the <stop-time> is set to zero, then the session is not bounded,
- // though it will not become active until after the <start-time>. If
- // the <start-time> is also zero, the session is regarded as permanent.
- //
- // 1. These values are the decimal representation of Network Time Protocol (NTP) time values in seconds
- // since 1900 [13]. To convert these values to UNIX time, subtract decimal 2208988800.
- // 2. If the <stop-time> is set to zero, then the session is not bounded, though it will not become active
- // until after the <start-time>. If the <start-time> is also zero, the session is regarded as permanent.
- static int sdp_parse_timing(struct sdp_t* sdp)
- {
- int n[2];
- struct sdp_timing *t;
-
- if(sdp->t.count >= N_TIMING)
- {
- if(sdp->t.count - N_TIMING >= sdp->t.capacity)
- {
- void* ptr;
- ptr = (struct sdp_timing*)realloc(sdp->t.ptr, (sdp->t.capacity+8)*sizeof(struct sdp_timing));
- if(!ptr)
- return -ENOMEM;
-
- sdp->t.ptr = ptr;
- sdp->t.capacity += 8;
- }
-
- t = &sdp->t.ptr[sdp->t.count - N_TIMING];
- }
- else
- {
- t = &sdp->t.times[sdp->t.count];
- }
-
- memset(n, 0, sizeof(n));
- memset(t, 0, sizeof(struct sdp_timing));
-
- sdp_skip_space(sdp);
- t->start = sdp->raw + sdp->offset;
- n[0] = sdp_token_word(sdp, " \t\r\n");
-
- sdp_skip_space(sdp);
- t->stop = sdp->raw + sdp->offset;
- n[1] = sdp_token_word(sdp, "\r\n");
- trim_right(t->stop, &n[1]);
-
- if(0 == sdp_token_crlf(sdp))
- {
- t->start[n[0]] = '\0';
- t->stop[n[1]] = '\0';
- ++sdp->t.count;
- return 0;
- }
- return -1;
- }
-
- static int sdp_append_timing_repeat_offset(struct sdp_repeat *r, char* offset)
- {
- if(r->offsets.count >= N_REPEAT_OFFSET)
- {
- if(r->offsets.count - N_REPEAT_OFFSET >= r->offsets.capacity)
- {
- void* ptr;
- ptr = (char**)realloc(r->offsets.ptr, (r->offsets.capacity+8)*sizeof(char*));
- if(!ptr)
- return -ENOMEM;
-
- r->offsets.ptr = ptr;
- r->offsets.capacity += 8;
- }
-
- r->offsets.ptr[r->offsets.count - N_REPEAT_OFFSET] = offset;
- }
- else
- {
- r->offsets.offsets[r->offsets.count] = offset;
- }
-
- ++r->offsets.count;
- return 0;
- }
-
- // RFC4566 5.10
- // r=<repeat interval> <active duration> <offsets from start-time>
- // t=3034423619 3042462419
- // r=604800 3600 0 90000
- // r=7d 1h 0 25h
- static int sdp_parse_repeat(struct sdp_t* sdp)
- {
- int ret;
- int n[3];
- char *offset;
- struct sdp_timing *t;
- struct sdp_repeat *r;
-
- assert(sdp->t.count > 0);
- if(sdp->t.count < 1)
- return -1; // repeat must after timing
- t = sdp_get_timing(sdp, sdp->t.count-1);
-
- if(t->r.count >= N_REPEAT)
- {
- if(t->r.count - N_REPEAT >= t->r.capacity)
- {
- void* ptr;
- ptr = (struct sdp_repeat*)realloc(t->r.ptr, (t->r.capacity+8)*sizeof(struct sdp_repeat));
- if(!ptr)
- return -ENOMEM;
-
- t->r.ptr = ptr;
- t->r.capacity += 8;
- }
-
- r = &t->r.ptr[t->r.count - N_REPEAT];
- }
- else
- {
- r = &t->r.repeats[t->r.count];
- }
-
- offset = NULL;
- memset(n, 0, sizeof(n));
- memset(r, 0, sizeof(struct sdp_repeat));
-
- sdp_skip_space(sdp);
- r->interval = sdp->raw + sdp->offset;
- n[0] = sdp_token_word(sdp, " \t\r\n");
-
- sdp_skip_space(sdp);
- r->duration = sdp->raw + sdp->offset;
- n[1] = sdp_token_word(sdp, " \t\r\n");
-
- while(strchr(" \t", sdp->raw[sdp->offset]))
- {
- if(n[2] > 0 && offset)
- {
- offset[n[2]] = '\0';
- ret = sdp_append_timing_repeat_offset(r, offset);
- if(0 != ret)
- return ret;
- }
-
- sdp_skip_space(sdp);
- offset = sdp->raw + sdp->offset;
- n[2] = sdp_token_word(sdp, " \t\r\n");
- }
-
- if(0 == sdp_token_crlf(sdp))
- {
- r->interval[n[0]] = '\0';
- r->duration[n[1]] = '\0';
- if(n[2] > 0 && offset)
- {
- offset[n[2]] = '\0';
- ret = sdp_append_timing_repeat_offset(r, offset);
- if(0 != ret)
- return ret;
- }
- ++t->r.count;
- return 0;
- }
- return -1;
- }
-
- // RFC4566 5.11
- // z=<adjustment time> <offset> <adjustment time> <offset> ....
- // z=2882844526 -1h 2898848070 0
- static int sdp_parse_timezone(struct sdp_t* sdp)
- {
- int n[2];
- char *time, *offset;
- struct sdp_timing *t;
- struct sdp_timezone *z;
-
- assert(sdp->t.count > 0);
- if(sdp->t.count < 1)
- return -1; // timezone must after timing
- t = sdp_get_timing(sdp, sdp->t.count-1);
-
- do
- {
- sdp_skip_space(sdp);
- time = sdp->raw + sdp->offset;
- n[0] = sdp_token_word(sdp, " \t\r\n");
-
- sdp_skip_space(sdp);
- offset = sdp->raw + sdp->offset;
- n[1] = sdp_token_word(sdp, " \t\r\n");
-
- if(n[0] < 1 || n[1] < 1)
- break;
-
- if(t->z.count >= N_TIMEZONE)
- {
- if(t->z.count - N_TIMEZONE >= t->z.capacity)
- {
- void* ptr;
- ptr = (struct sdp_timezone*)realloc(t->z.ptr, (t->z.capacity+8)*sizeof(struct sdp_timezone));
- if(!ptr)
- return -ENOMEM;
-
- t->z.ptr = ptr;
- t->z.capacity += 8;
- }
-
- z = &t->z.ptr[t->r.count - N_TIMEZONE];
- }
- else
- {
- z = &t->z.timezones[t->r.count];
- }
-
- z->time = time;
- z->offset = offset;
- ++t->z.count;
-
- } while(n[0] > 0 && n[1] > 0);
-
- return sdp_token_crlf(sdp);
- }
-
- // RFC4566 5.12
- // k=<method>
- // k=<method>:<encryption key>
- // k=clear:<encryption key>
- // k=base64:<encoded encryption key>
- // k=uri:<URI to obtain key>
- // k=prompt
- // A key field is permitted before the first media entry (in which case
- // it applies to all media in the session), or for each media entry as required.
- static int sdp_parse_encryption(struct sdp_t* sdp)
- {
- int n[2];
- struct sdp_encryption *k;
-
- if(sdp->m.count > 0)
- {
- k = &sdp_get_media(sdp, sdp->m.count-1)->k;
- }
- else
- {
- k = &sdp->k;
- }
- memset(k, 0, sizeof(struct sdp_encryption));
-
- sdp_skip_space(sdp);
- k->method = sdp->raw + sdp->offset;
- n[0] = sdp_token_word(sdp, ":\r\n");
- trim_right(k->method, &n[0]);
-
- if(':' == sdp->raw[sdp->offset])
- ++sdp->offset; // skip ':'
-
- sdp_skip_space(sdp);
- k->key = sdp->raw + sdp->offset;
- n[1] = sdp_token_word(sdp, "\r\n");
- trim_right(k->key, &n[1]);
-
- if(0 == sdp_token_crlf(sdp))
- {
- k->method[n[0]] = '\0';
- k->key[n[1]] = '\0';
- return 0;
- }
- return -1;
- }
-
- // RFC4566 5.13
- // a=<attribute>
- // a=<attribute>:<value>
- // a=cat:<category>
- // a=keywds:<keywords>
- // a=tool:<name and version of tool>
- // a=ptime:<packet time>
- // a=maxptime:<maximum packet time>
- // a=rtpmap:<payload type> <encoding name>/<clock rate> [/<encoding parameters>]
- // a=recvonly
- // a=sendrecv
- // a=sendonly
- // a=inactive
- // a=orient:<orientation>
- // a=type:<conference type>
- // a=charset:<character set>
- // a=sdplang:<language tag>
- // a=lang:<language tag>
- // a=framerate:<frame rate>
- // a=quality:<quality>
- // a=fmtp:<format> <format specific parameters>
- static int sdp_parse_attribute(struct sdp_t* sdp)
- {
- int n[2];
- struct attributes *as;
- struct sdp_attribute *a;
-
- if(sdp->m.count > 0)
- {
- as = &sdp_get_media(sdp, sdp->m.count-1)->a;
- }
- else
- {
- as = &sdp->a;
- }
-
- if(as->count >= N_ATTRIBUTE)
- {
- if(as->count - N_ATTRIBUTE >= as->capacity)
- {
- void* ptr;
- ptr = (struct sdp_attribute*)realloc(as->ptr, (as->capacity+8)*sizeof(struct sdp_attribute));
- if(!ptr)
- return -ENOMEM;
-
- as->ptr = ptr;
- as->capacity += 8;
- }
-
- a = &as->ptr[as->count - N_ATTRIBUTE];
- }
- else
- {
- a = &as->attrs[as->count];
- }
-
- memset(a, 0, sizeof(struct sdp_attribute));
-
- sdp_skip_space(sdp);
- a->name = sdp->raw + sdp->offset;
- n[0] = sdp_token_word(sdp, ":\r\n");
- trim_right(a->name, &n[0]);
-
- if(':' == sdp->raw[sdp->offset])
- ++sdp->offset; // skip ':'
-
- sdp_skip_space(sdp);
- a->value = sdp->raw + sdp->offset;
- n[1] = sdp_token_word(sdp, "\r\n");
- trim_right(a->value, &n[1]);
-
- if(0 == sdp_token_crlf(sdp))
- {
- ++as->count;
- a->name[n[0]] = '\0';
- a->value[n[1]] = '\0';
- return 0;
- }
- return -1;
- }
-
- static int sdp_append_media_format(struct sdp_media *m, char* fmt)
- {
- if(m->fmt.count >= N_MEDIA_FORMAT)
- {
- if(m->fmt.count - N_MEDIA_FORMAT >= m->fmt.capacity)
- {
- void* ptr;
- ptr = (char**)realloc(m->fmt.ptr, (m->fmt.capacity+8)*sizeof(char*));
- if(!ptr)
- return -ENOMEM;
-
- m->fmt.ptr = ptr;
- m->fmt.capacity += 8;
- }
-
- m->fmt.ptr[m->fmt.count - N_MEDIA_FORMAT] = fmt;
- }
- else
- {
- m->fmt.formats[m->fmt.count] = fmt;
- }
-
- ++m->fmt.count;
- return 0;
- }
-
- // RFC4566 5.14
- // m=<media> <port> <proto> <fmt> ...
- // media: audio/video/text/application/message
- // proto: udp, RTP/AVP, RTP/SAVP
- // m=<media> <port>/<number of ports> <proto> <fmt> ...
- // m=video 49170/2 RTP/AVP 31
- // c=IN IP4 224.2.1.1/127/2
- // m=video 49170/2 RTP/AVP 31
- static int sdp_parse_media(struct sdp_t* sdp)
- {
- int ret;
- int n[4];
- char *fmt;
- struct sdp_media *m;
-
- if(sdp->m.count >= N_MEDIA)
- {
- if(sdp->m.count - N_MEDIA >= sdp->m.capacity)
- {
- void* ptr;
- ptr = (struct sdp_media*)realloc(sdp->m.ptr, (sdp->m.capacity+8)*sizeof(struct sdp_media));
- if(!ptr)
- return -ENOMEM;
-
- sdp->m.ptr = ptr;
- sdp->m.capacity += 8;
- }
-
- m = &sdp->m.ptr[sdp->m.count - N_MEDIA];
- }
- else
- {
- m = &sdp->m.medias[sdp->m.count];
- }
-
- memset(m, 0, sizeof(struct sdp_media));
-
- sdp_skip_space(sdp);
- m->media = sdp->raw + sdp->offset;
- n[0] = sdp_token_word(sdp, " \t\r\n");
-
- sdp_skip_space(sdp);
- m->port = sdp->raw + sdp->offset;
- n[1] = sdp_token_word(sdp, " \t\r\n");
-
- sdp_skip_space(sdp);
- m->proto = sdp->raw + sdp->offset;
- n[2] = sdp_token_word(sdp, " \t\r\n");
-
- sdp_skip_space(sdp);
- fmt = sdp->raw + sdp->offset;
- n[3] = sdp_token_word(sdp, " \t\r\n");
-
- while (' ' == fmt[n[3]] || '\t' == fmt[n[3]])
- {
- fmt[n[3]] = '\0';
- ret = sdp_append_media_format(m, fmt);
- if(0 != ret)
- return ret;
-
- sdp->offset += 1; // skip '\0'
- sdp_skip_space(sdp);
- fmt = sdp->raw + sdp->offset;
- n[3] = sdp_token_word(sdp, " \t\r\n");
- }
-
- if(0 == sdp_token_crlf(sdp))
- {
- m->media[n[0]] = '\0';
- m->port[n[1]] = '\0';
- m->proto[n[2]] = '\0';
- if(n[3] > 0)
- {
- fmt[n[3]] = '\0';
- ret = sdp_append_media_format(m, fmt);
- if(0 != ret)
- return ret;
- }
-
- ++sdp->m.count;
- return 0;
- }
- return -1;
- }
-
- // gb28181 extension
- static int sdp_parse_gb28181_ssrc(struct sdp_t* sdp)
- {
- int n;
- struct attributes* as;
- struct sdp_attribute* a;
-
- if (sdp->m.count > 0)
- {
- as = &sdp_get_media(sdp, sdp->m.count - 1)->a;
- }
- else
- {
- as = &sdp->a;
- }
-
- if (as->count >= N_ATTRIBUTE)
- {
- if (as->count - N_ATTRIBUTE >= as->capacity)
- {
- void* ptr;
- ptr = (struct sdp_attribute*)realloc(as->ptr, (as->capacity + 8) * sizeof(struct sdp_attribute));
- if (!ptr)
- return -ENOMEM;
-
- as->ptr = ptr;
- as->capacity += 8;
- }
-
- a = &as->ptr[as->count - N_ATTRIBUTE];
- }
- else
- {
- a = &as->attrs[as->count];
- }
-
- memset(a, 0, sizeof(struct sdp_attribute));
- a->name = "ssrc";
- a->value = sdp->raw + sdp->offset;
-
- n = sdp_token_word(sdp, "\r\n");
- if (0 != sdp_token_crlf(sdp))
- return -1;
-
- a->value[n] = '\0';
- ++as->count;
- return 0;
- }
-
- static void* sdp_create(const char* s, int len)
- {
- struct sdp_t *sdp;
- sdp = (struct sdp_t*)malloc(sizeof(struct sdp_t) + len + 1);
- if( !sdp )
- return NULL;
-
- memset(sdp, 0, sizeof(struct sdp_t));
- sdp->raw = (char*)(sdp + 1);
- memcpy(sdp->raw, s, len);
- sdp->raw[len] = 0;
- return sdp;
- }
-
- void sdp_destroy(struct sdp_t* sdp)
- {
- int i;
- struct sdp_media *m;
- struct sdp_timing *t;
-
- if(sdp->e.count > N_EMAIL)
- free(sdp->e.ptr);
-
- if(sdp->p.count > N_PHONE)
- free(sdp->p.ptr);
-
- if(sdp->b.count > N_BANDWIDTH)
- free(sdp->b.ptr);
-
- for(i = 0; i < sdp->t.count; i++)
- {
- t = sdp_get_timing(sdp, i);
- if(t->r.count > N_REPEAT)
- free(t->r.ptr);
-
- if(t->z.count > N_TIMEZONE)
- free(t->z.ptr);
- }
-
- if(sdp->t.count > N_TIMING)
- free(sdp->t.ptr);
-
- if(sdp->a.count > N_ATTRIBUTE)
- free(sdp->a.ptr);
-
- for(i = 0; i < sdp->m.count; i++)
- {
- m = sdp_get_media(sdp, i);
- if(m->fmt.count > N_MEDIA_FORMAT)
- free(m->fmt.ptr);
-
- if(m->a.count > N_ATTRIBUTE)
- free(m->a.ptr);
-
- if(m->c.count > N_CONNECTION)
- free(m->c.ptr);
-
- if (m->b.count > N_BANDWIDTH)
- free(m->b.ptr);
- }
-
- if(sdp->m.count > N_MEDIA)
- free(sdp->m.ptr);
-
- free(sdp);
- }
-
- struct sdp_t* sdp_parse(const char* s, int len)
- {
- int r;
- char c;
- struct sdp_t *sdp;
-
- assert(s);
- sdp = (struct sdp_t*)sdp_create(s, len);
- if(!sdp)
- return NULL;
-
- while(sdp->raw[sdp->offset] && !strchr("\r\n", sdp->raw[sdp->offset]))
- {
- sdp_skip_space(sdp);
- c = sdp->raw[sdp->offset++];
-
- sdp_skip_space(sdp);
- if('=' != sdp->raw[sdp->offset++])
- goto parse_failed;
-
- sdp_skip_space(sdp);
-
- switch(c)
- {
- case 'v':
- r = sdp_parse_version(sdp);
- break;
-
- case 'o':
- r = sdp_parse_origin(sdp);
- break;
-
- case 's':
- r = sdp_parse_session(sdp);
- break;
-
- case 'i':
- r = sdp_parse_information(sdp);
- break;
-
- case 'u':
- r = sdp_parse_uri(sdp);
- break;
-
- case 'e':
- r = sdp_parse_email(sdp);
- break;
-
- case 'p':
- r = sdp_parse_phone(sdp);
- break;
-
- case 'c':
- r = sdp_parse_connection(sdp);
- break;
-
- case 'b':
- r = sdp_parse_bandwidth(sdp);
- break;
-
- case 't':
- r = sdp_parse_timing(sdp);
- break;
-
- case 'r':
- r = sdp_parse_repeat(sdp);
- break;
-
- case 'z':
- r = sdp_parse_timezone(sdp);
- break;
-
- case 'k':
- r = sdp_parse_encryption(sdp);
- break;
-
- case 'a':
- r = sdp_parse_attribute(sdp);
- break;
-
- case 'm':
- r = sdp_parse_media(sdp);
- break;
-
- case 'y':
- r = sdp_parse_gb28181_ssrc(sdp);
- break;
-
- default:
- // unknown sdp
- sdp_token_word(sdp, "\r\n");
- r = sdp_token_crlf(sdp);
- break;
- }
-
- if(0 != r)
- goto parse_failed;
- }
-
- return sdp;
-
- parse_failed:
- sdp_destroy(sdp);
- return NULL;
- }
-
- int sdp_version_get(struct sdp_t* sdp)
- {
- return sdp->v;
- }
-
- //void sdp_version_set(struct sdp_t* sdp, int version)
- //{
- // struct sdp_t *sdp;
- // sdp = (struct sdp_t*)sdp;
- // sdp->v = version;
- //}
-
- int sdp_origin_get(struct sdp_t* sdp, const char **username, const char** session, const char** version, const char** network, const char** addrtype, const char** address)
- {
- if(sdp->o.username && sdp->o.session && sdp->o.session_version
- && sdp->o.c.network && sdp->o.c.addrtype && sdp->o.c.address)
- {
- *username = sdp->o.username;
- *session = sdp->o.session;
- *version = sdp->o.session_version;
- *network = sdp->o.c.network;
- *addrtype = sdp->o.c.addrtype;
- *address = sdp->o.c.address;
- return 0;
- }
- return -1;
- }
-
- int sdp_origin_get_network(struct sdp_t* sdp)
- {
- if(0 == strcasecmp("IN", sdp->o.c.network))
- return SDP_C_NETWORK_IN;
- return SDP_C_NETWORK_UNKNOWN;
- }
-
- int sdp_origin_get_addrtype(struct sdp_t* sdp)
- {
- if(0 == strcasecmp("IP4", sdp->o.c.addrtype))
- return SDP_C_ADDRESS_IP4;
- if(0 == strcasecmp("IP6", sdp->o.c.addrtype))
- return SDP_C_ADDRESS_IP6;
- return SDP_C_ADDRESS_UNKNOWN;
- }
-
- const char* sdp_session_get_name(struct sdp_t* sdp)
- {
- return sdp->s;
- }
-
- const char* sdp_session_get_information(struct sdp_t* sdp)
- {
- return sdp->i;
- }
-
- const char* sdp_uri_get(struct sdp_t* sdp)
- {
- return sdp->u;
- }
-
- int sdp_email_count(struct sdp_t* sdp)
- {
- return sdp->e.count;
- }
-
- const char* sdp_email_get(struct sdp_t* sdp, int idx)
- {
- if(idx >= sdp->e.count || idx < 0)
- return NULL;
-
- return idx < N_EMAIL ? sdp->e.emails[idx].email : sdp->e.ptr[idx - N_EMAIL].email;
- }
-
- int sdp_phone_count(struct sdp_t* sdp)
- {
- return sdp->p.count;
- }
-
- const char* sdp_phone_get(struct sdp_t* sdp, int idx)
- {
- if(idx >= sdp->p.count || idx < 0)
- return NULL;
-
- return idx < N_PHONE ? sdp->p.phones[idx].phone : sdp->p.ptr[idx - N_PHONE].phone;
- }
-
- int sdp_connection_get(struct sdp_t* sdp, const char** network, const char** addrtype, const char** address)
- {
- if(sdp->c.network && sdp->c.addrtype && sdp->c.address)
- {
- *network = sdp->c.network;
- *addrtype = sdp->c.addrtype;
- *address = sdp->c.address;
- return 0;
- }
- return -1;
- }
-
- int sdp_connection_get_address(struct sdp_t* sdp, char* ip, int bytes)
- {
- const char* p;
- if(sdp->c.address && bytes > 0)
- {
- p = sdp->c.address;
- while(*p && '/' != *p && bytes > 1)
- {
- *ip++ = *p;
- --bytes;
- }
-
- if(0 == *p || '/' == *p)
- {
- *ip = '\0';
- return 0;
- }
- }
- return -1;
- }
-
- int sdp_connection_get_network(struct sdp_t* sdp)
- {
- if(0 == strcasecmp("IN", sdp->c.network))
- return SDP_C_NETWORK_IN;
- return SDP_C_NETWORK_UNKNOWN;
- }
-
- int sdp_connection_get_addrtype(struct sdp_t* sdp)
- {
- if(0 == strcasecmp("IP4", sdp->c.addrtype))
- return SDP_C_ADDRESS_IP4;
- if(0 == strcasecmp("IP6", sdp->c.addrtype))
- return SDP_C_ADDRESS_IP6;
- return SDP_C_ADDRESS_UNKNOWN;
- }
-
- int sdp_bandwidth_count(struct sdp_t* sdp)
- {
- return sdp->b.count;
- }
-
- const char* sdp_bandwidth_get_type(struct sdp_t* sdp, int idx)
- {
- if(idx >= (int)sdp->b.count || idx < 0)
- return NULL;
- return idx < N_BANDWIDTH ? sdp->b.bandwidths[idx].bwtype : sdp->b.ptr[idx - N_BANDWIDTH].bwtype;
- }
-
- int sdp_bandwidth_get_value(struct sdp_t* sdp, int idx)
- {
- const char* b;
- if(idx >= (int)sdp->b.count || idx < 0)
- return -1;
-
- b = idx < N_BANDWIDTH ? sdp->b.bandwidths[idx].bandwidth : sdp->b.ptr[idx - N_BANDWIDTH].bandwidth;
- return atoi(b);
- }
-
- int sdp_timing_count(struct sdp_t* sdp)
- {
- return sdp->t.count;
- }
-
- int sdp_timing_get(sdp_t* sdp, int idx, const char** start, const char** stop)
- {
- struct sdp_timing* t;
- t = sdp_get_timing(sdp, idx);
- if (NULL == t)
- return -1;
- *start = t->start;
- *stop = t->stop;
- return 0;
- }
-
- int sdp_timing_repeat_count(sdp_t* sdp, int idx)
- {
- struct sdp_timing* t;
- t = sdp_get_timing(sdp, idx);
- return t ? t->r.count : -1;
- }
-
- int sdp_timing_timezone_count(sdp_t* sdp, int idx)
- {
- struct sdp_timing* t;
- t = sdp_get_timing(sdp, idx);
- return t ? t->z.count : -1;
- }
-
- int sdp_media_count(struct sdp_t* sdp)
- {
- return sdp->m.count;
- }
-
- const char* sdp_media_type(struct sdp_t* sdp, int media)
- {
- struct sdp_media *m;
- m = sdp_get_media(sdp, media);
- return m ? m->media : NULL;
- }
-
- int sdp_media_port(struct sdp_t* sdp, int media, int port[], int num)
- {
- int i, n;
- const char* p;
- struct sdp_media *m;
- m = sdp_get_media(sdp, media);
- if (!m || !port)
- return -1;
-
- p = strchr(m->port, '/');
- port[0] = atoi(m->port);
- n = atoi(p ? p + 1 : "1");
- for (i = 1; i < num && i < n; i++)
- port[i] = port[0] + i;
- return i;
- }
-
- const char* sdp_media_proto(struct sdp_t* sdp, int media)
- {
- struct sdp_media *m;
- m = sdp_get_media(sdp, media);
- return m ? m->proto : NULL;
- }
-
- // rfc 4566 5.14. Media Descriptions ("m=")
- // (p24) If the <proto> sub-field is "udp" the <fmt> sub-fields MUST
- // reference a media type describing the format under the "audio",
- // "video", "text", "application", or "message" top-level media types.
- static inline int sdp_media_format_value(const char* format)
- {
- switch(format[0])
- {
- case 'a': return ('u' == format[1]) ? SDP_M_MEDIA_AUDIO : SDP_M_MEDIA_APPLICATION;
- case 'v': return SDP_M_MEDIA_VIDEO;
- case 't': return SDP_M_MEDIA_TEXT;
- case 'm': return SDP_M_MEDIA_MESSAGE;
- default: return atoi(format);
- }
- //if(0 == strcasecmp("video", format))
- // return SDP_M_MEDIA_VIDEO;
- //else if(0 == strcasecmp("audio", format))
- // return SDP_M_MEDIA_AUDIO;
- //else if(0 == strcasecmp("text", format))
- // return SDP_M_MEDIA_TEXT;
- //else if(0 == strcasecmp("application", format))
- // return SDP_M_MEDIA_APPLICATION;
- //else if(0 == strcasecmp("message", format))
- // return SDP_M_MEDIA_MESSAGE;
- //else
- // return atoi(format);
- }
-
- int sdp_media_formats(struct sdp_t* sdp, int media, int *formats, int count)
- {
- int i;
- struct sdp_media *m;
- m = sdp_get_media(sdp, media);
- if(!m)
- return -1;
-
- for(i = 0; i < count && i < m->fmt.count; i++)
- {
- if(i < N_MEDIA_FORMAT)
- formats[i] = sdp_media_format_value(m->fmt.formats[i]);
- else
- formats[i] = sdp_media_format_value(m->fmt.ptr[i-N_MEDIA_FORMAT]);
- }
-
- return (int)m->fmt.count;
- }
-
- int sdp_media_get_connection(sdp_t* sdp, int media, const char** network, const char** addrtype, const char** address)
- {
- struct sdp_media *m;
- struct sdp_connection *conn;
-
- m = sdp_get_media(sdp, media);
- if(m && m->c.count > 0)
- conn = &m->c.connections[0];
- else
- conn = &sdp->c;
-
- if(conn && conn->network && conn->addrtype && conn->address)
- {
- *network = conn->network;
- *addrtype = conn->addrtype;
- *address = conn->address;
- return 0;
- }
-
- return -1;
- }
-
- int sdp_media_get_connection_address(struct sdp_t* sdp, int media, char* ip, int bytes)
- {
- const char* p;
- struct sdp_media *m;
- struct sdp_connection *conn;
-
- m = sdp_get_media(sdp, media);
- if(m && m->c.count > 0)
- conn = &m->c.connections[0];
- else
- conn = &sdp->c;
-
- if(conn->address && bytes > 0)
- {
- p = conn->address;
- while(*p && '/' != *p && bytes > 1)
- {
- *ip++ = *p;
- --bytes;
- }
-
- if(0 == *p || '/' == *p)
- {
- *ip = '\0';
- return 0;
- }
- }
- return -1;
- }
-
- int sdp_media_get_connection_network(struct sdp_t* sdp, int media)
- {
- struct sdp_media *m;
- struct sdp_connection *conn;
-
- m = sdp_get_media(sdp, media);
- if(m && m->c.count > 0)
- conn = &m->c.connections[0];
- else
- conn = &sdp->c;
-
- if(conn->network)
- {
- if(0 == strcasecmp("IN", conn->network))
- return SDP_C_NETWORK_IN;
- }
- return SDP_C_NETWORK_UNKNOWN;
- }
-
- int sdp_media_get_connection_addrtype(struct sdp_t* sdp, int media)
- {
- struct sdp_media *m;
- struct sdp_connection *conn;
-
- m = sdp_get_media(sdp, media);
- if(m && m->c.count > 0)
- conn = &m->c.connections[0];
- else
- conn = &sdp->c;
-
- if(conn->addrtype)
- {
- if(0 == strcasecmp("IP4", conn->addrtype))
- return SDP_C_ADDRESS_IP4;
- if(0 == strcasecmp("IP6", conn->addrtype))
- return SDP_C_ADDRESS_IP6;
- }
- return SDP_C_ADDRESS_UNKNOWN;
- }
-
- int sdp_media_bandwidth_count(struct sdp_t* sdp, int media)
- {
- struct sdp_media *m;
- m = sdp_get_media(sdp, media);
- if(!m)
- return 0;
- return m->b.count;
- }
-
- const char* sdp_media_bandwidth_get_type(struct sdp_t* sdp, int media, int idx)
- {
- struct sdp_media *m;
- m = sdp_get_media(sdp, media);
- if(!m)
- return NULL;
-
- if(idx >= (int)m->b.count || idx < 0)
- return NULL;
- return idx < N_BANDWIDTH ? m->b.bandwidths[idx].bwtype : m->b.ptr[idx - N_BANDWIDTH].bwtype;
- }
-
- int sdp_media_bandwidth_get_value(struct sdp_t* sdp, int media, int idx)
- {
- const char* b;
- struct sdp_media *m;
- m = sdp_get_media(sdp, media);
- if(!m)
- return -1;
-
- if(idx >= (int)m->b.count || idx < 0)
- return -1;
-
- b = idx < N_BANDWIDTH ? m->b.bandwidths[idx].bandwidth : m->b.ptr[idx - N_BANDWIDTH].bandwidth;
- return atoi(b);
- }
-
- int sdp_attribute_count(struct sdp_t* sdp)
- {
- return sdp->a.count;
- }
-
- int sdp_attribute_get(struct sdp_t* sdp, int idx, const char** name, const char** value)
- {
- struct sdp_attribute *attr;
- if(idx < 0 || idx > sdp->a.count)
- return -1; // not found
-
- if(idx < N_ATTRIBUTE)
- attr = sdp->a.attrs + idx;
- else
- attr = sdp->a.ptr + idx - N_ATTRIBUTE;
-
- *name = attr->name;
- *value = attr->value;
- return 0;
- }
-
- static const char* sdp_attribute_find_impl(const struct attributes* a, const char* name)
- {
- int i;
- const struct sdp_attribute* attr;
-
- for (i = 0; name && i < a->count; i++)
- {
- if (i < N_ATTRIBUTE)
- attr = a->attrs + i;
- else
- attr = a->ptr + i - N_ATTRIBUTE;
-
- if (attr->name && 0 == strcmp(attr->name, name))
- return attr->value;
- }
-
- return NULL;
- }
-
- static int sdp_attribute_list_impl(const struct attributes* a, const char* name, void (*onattr)(void* param, const char* name, const char* value), void* param)
- {
- int i;
- const struct sdp_attribute* attr;
-
- for (i = 0; i < a->count; i++)
- {
- if (i < N_ATTRIBUTE)
- attr = a->attrs + i;
- else
- attr = a->ptr + i - N_ATTRIBUTE;
-
- if (!name || (attr->name && 0 == strcmp(attr->name, name)))
- onattr(param, attr->name, attr->value);
- }
-
- return 0;
- }
-
- const char* sdp_media_attribute_find(struct sdp_t* sdp, int media, const char* name)
- {
- struct sdp_media* m;
- m = sdp_get_media(sdp, media);
- return m ? sdp_attribute_find_impl(&m->a, name) : NULL;
- }
-
- int sdp_media_attribute_list(struct sdp_t* sdp, int media, const char* name, void (*onattr)(void* param, const char* name, const char* value), void* param)
- {
- struct sdp_media* m;
- m = sdp_get_media(sdp, media);
- return m ? sdp_attribute_list_impl(&m->a, name, onattr, param) : -1;
- }
-
- const char* sdp_attribute_find(struct sdp_t* sdp, const char* name)
- {
- return sdp_attribute_find_impl(&sdp->a, name);
- }
-
- int sdp_attribute_list(struct sdp_t* sdp, const char* name, void (*onattr)(void* param, const char* name, const char* value), void* param)
- {
- return sdp_attribute_list_impl(&sdp->a, name, onattr, param);
- }
-
- static int sdp_attribute_mode(struct attributes* a)
- {
- static const int values[] = { SDP_A_SENDRECV, SDP_A_SENDONLY, SDP_A_RECVONLY, SDP_A_INACTIVE };
- static const char* strings[] = { "sendrecv", "sendonly", "recvonly", "inactive" };
-
- int i, j;
- const struct sdp_attribute *attr;
- for (i = 0; i < a->count; i++)
- {
- if (i < N_ATTRIBUTE)
- attr = a->attrs + i;
- else
- attr = a->ptr + i - N_ATTRIBUTE;
-
- for (j = 0; j < sizeof(values) / sizeof(values[0]); j++)
- {
- if (attr->name && 0 == strcmp(strings[j], attr->name))
- return values[j];
- }
- }
-
- return -1;
- }
-
- int sdp_media_mode(struct sdp_t* sdp, int media)
- {
- int mode;
- struct sdp_media *m;
- m = sdp_get_media(sdp, media);
- mode = m ? sdp_attribute_mode(&m->a) : -1;
- mode = -1 == mode ? sdp_attribute_mode(&sdp->a) : mode;
- return -1 == mode ? SDP_A_SENDRECV : mode; // default SDP_A_SENDRECV
- }
|