Do not crash to assertion failure on unknown audio codec
[deb_shairplay.git] / src / lib / sdp.c
1 /**
2 * Copyright (C) 2011-2012 Juho Vähä-Herttua
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 */
14
15 #include <stdlib.h>
16 #include <string.h>
17 #include <assert.h>
18
19 #include "sdp.h"
20
21 struct sdp_s {
22 char *data;
23
24 /* Actual SDP records */
25 const char *version;
26 const char *origin;
27 const char *connection;
28 const char *session;
29 const char *time;
30 const char *media;
31
32 /* Additional SDP records */
33 const char *rtpmap;
34 const char *fmtp;
35 const char *rsaaeskey;
36 const char *aesiv;
37 const char *min_latency;
38 };
39
40 static void
41 parse_sdp_line(sdp_t *sdp, char *line)
42 {
43 int len = strlen(line);
44 if (len < 2 || line[1] != '=') {
45 return;
46 }
47
48 switch (line[0]) {
49 case 'v':
50 sdp->version = &line[2];
51 break;
52 case 'o':
53 sdp->origin = &line[2];
54 break;
55 case 's':
56 sdp->session = &line[2];
57 break;
58 case 'c':
59 sdp->connection = &line[2];
60 break;
61 case 't':
62 sdp->time = &line[2];
63 break;
64 case 'm':
65 sdp->media = &line[2];
66 break;
67 case 'a':
68 {
69 char *key;
70 char *value;
71
72 /* Parse key and value */
73 key = &line[2];
74 value = strstr(line, ":");
75 if (!value) break;
76 *(value++) = '\0';
77
78 if (!strcmp(key, "rtpmap") && !sdp->rtpmap) {
79 sdp->rtpmap = value;
80 } else if (!strcmp(key, "fmtp") && !sdp->fmtp) {
81 sdp->fmtp = value;
82 } else if (!strcmp(key, "rsaaeskey")) {
83 sdp->rsaaeskey = value;
84 } else if (!strcmp(key, "aesiv")) {
85 sdp->aesiv = value;
86 } else if (!strcmp(key, "min-latency")) {
87 sdp->min_latency = value;
88 }
89 break;
90 }
91 }
92 }
93
94 static void
95 parse_sdp_data(sdp_t *sdp)
96 {
97 int pos, len;
98
99 pos = 0;
100 len = strlen(sdp->data);
101 while (pos < len) {
102 int lfpos;
103
104 /* Find newline in string */
105 for (lfpos=pos; sdp->data[lfpos]; lfpos++) {
106 if (sdp->data[lfpos] == '\n') {
107 break;
108 }
109 }
110 if (sdp->data[lfpos] != '\n') {
111 break;
112 }
113
114 /* Replace newline with '\0' and parse line */
115 sdp->data[lfpos] = '\0';
116 if (lfpos > pos && sdp->data[lfpos-1] == '\r') {
117 sdp->data[lfpos-1] = '\0';
118 }
119 parse_sdp_line(sdp, sdp->data+pos);
120 pos = lfpos+1;
121 }
122 }
123
124 sdp_t *
125 sdp_init(const char *sdpdata, int sdpdatalen)
126 {
127 sdp_t *sdp;
128
129 sdp = calloc(1, sizeof(sdp_t));
130 if (!sdp) {
131 return NULL;
132 }
133
134 /* Allocate data buffer */
135 sdp->data = malloc(sdpdatalen+1);
136 if (!sdp->data) {
137 free(sdp);
138 return NULL;
139 }
140 memcpy(sdp->data, sdpdata, sdpdatalen);
141 sdp->data[sdpdatalen] = '\0';
142 parse_sdp_data(sdp);
143 return sdp;
144 }
145
146 void
147 sdp_destroy(sdp_t *sdp)
148 {
149 if (sdp) {
150 free(sdp->data);
151 free(sdp);
152 }
153 }
154
155 const char *
156 sdp_get_version(sdp_t *sdp)
157 {
158 assert(sdp);
159
160 return sdp->version;
161 }
162
163 const char *
164 sdp_get_origin(sdp_t *sdp)
165 {
166 assert(sdp);
167
168 return sdp->origin;
169 }
170
171 const char *
172 sdp_get_session(sdp_t *sdp)
173 {
174 assert(sdp);
175
176 return sdp->session;
177 }
178
179 const char *
180 sdp_get_connection(sdp_t *sdp)
181 {
182 assert(sdp);
183
184 return sdp->connection;
185 }
186
187 const char *
188 sdp_get_time(sdp_t *sdp)
189 {
190 assert(sdp);
191
192 return sdp->time;
193 }
194
195 const char *
196 sdp_get_media(sdp_t *sdp)
197 {
198 assert(sdp);
199
200 return sdp->media;
201 }
202
203 const char *
204 sdp_get_rtpmap(sdp_t *sdp)
205 {
206 assert(sdp);
207
208 return sdp->rtpmap;
209 }
210
211 const char *
212 sdp_get_fmtp(sdp_t *sdp)
213 {
214 assert(sdp);
215
216 return sdp->fmtp;
217 }
218
219 const char *
220 sdp_get_rsaaeskey(sdp_t *sdp)
221 {
222 assert(sdp);
223
224 return sdp->rsaaeskey;
225 }
226
227 const char *
228 sdp_get_aesiv(sdp_t *sdp)
229 {
230 assert(sdp);
231
232 return sdp->aesiv;
233 }
234
235 const char *
236 sdp_get_min_latency(sdp_t *sdp)
237 {
238 assert(sdp);
239
240 return sdp->min_latency;
241 }
242