0f2393359002736ce285d7fc0af25fda5422ebea
[asterisk/asterisk.git] / main / stream.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2017, Digium, Inc.
5  *
6  * Joshua Colp <jcolp@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Media Stream API
22  *
23  * \author Joshua Colp <jcolp@digium.com>
24  */
25
26 /*** MODULEINFO
27         <support_level>core</support_level>
28  ***/
29
30 #include "asterisk.h"
31
32 #include "asterisk/logger.h"
33 #include "asterisk/stream.h"
34 #include "asterisk/strings.h"
35 #include "asterisk/format.h"
36 #include "asterisk/format_cap.h"
37
38 struct ast_stream {
39         /*!
40          * \brief The type of media the stream is handling
41          */
42         enum ast_media_type type;
43
44         /*!
45          * \brief The position of the stream in the topology
46          */
47         unsigned int position;
48
49         /*!
50          * \brief Current formats negotiated on the stream
51          */
52         struct ast_format_cap *formats;
53
54         /*!
55          * \brief The current state of the stream
56          */
57         enum ast_stream_state state;
58
59         /*!
60          * \brief Opaque stream data
61          */
62         void *data[AST_STREAM_DATA_SLOT_MAX];
63
64         /*!
65          * \brief What to do with data when the stream is freed
66          */
67         ast_stream_data_free_fn data_free_fn[AST_STREAM_DATA_SLOT_MAX];
68
69         /*!
70          * \brief Name for the stream within the context of the channel it is on
71          */
72         char name[0];
73 };
74
75 struct ast_stream_topology {
76         /*!
77          * \brief A vector of all the streams in this topology
78          */
79         AST_VECTOR(, struct ast_stream *) streams;
80 };
81
82 struct ast_stream *ast_stream_alloc(const char *name, enum ast_media_type type)
83 {
84         struct ast_stream *stream;
85
86         stream = ast_calloc(1, sizeof(*stream) + strlen(S_OR(name, "")) + 1);
87         if (!stream) {
88                 return NULL;
89         }
90
91         stream->type = type;
92         stream->state = AST_STREAM_STATE_INACTIVE;
93         strcpy(stream->name, S_OR(name, "")); /* Safe */
94
95         return stream;
96 }
97
98 struct ast_stream *ast_stream_clone(const struct ast_stream *stream)
99 {
100         struct ast_stream *new_stream;
101         size_t stream_size;
102
103         if (!stream) {
104                 return NULL;
105         }
106
107         stream_size = sizeof(*stream) + strlen(stream->name) + 1;
108         new_stream = ast_calloc(1, stream_size);
109         if (!new_stream) {
110                 return NULL;
111         }
112
113         memcpy(new_stream, stream, stream_size);
114         if (new_stream->formats) {
115                 ao2_ref(new_stream->formats, +1);
116         }
117
118         return new_stream;
119 }
120
121 void ast_stream_free(struct ast_stream *stream)
122 {
123         int i;
124
125         if (!stream) {
126                 return;
127         }
128
129         for (i = 0; i < AST_STREAM_DATA_SLOT_MAX; i++) {
130                 if (stream->data_free_fn[i]) {
131                         stream->data_free_fn[i](stream->data[i]);
132                 }
133         }
134
135         ao2_cleanup(stream->formats);
136         ast_free(stream);
137 }
138
139 const char *ast_stream_get_name(const struct ast_stream *stream)
140 {
141         ast_assert(stream != NULL);
142
143         return stream->name;
144 }
145
146 enum ast_media_type ast_stream_get_type(const struct ast_stream *stream)
147 {
148         ast_assert(stream != NULL);
149
150         return stream->type;
151 }
152
153 void ast_stream_set_type(struct ast_stream *stream, enum ast_media_type type)
154 {
155         ast_assert(stream != NULL);
156
157         stream->type = type;
158 }
159
160 struct ast_format_cap *ast_stream_get_formats(const struct ast_stream *stream)
161 {
162         ast_assert(stream != NULL);
163
164         return stream->formats;
165 }
166
167 void ast_stream_set_formats(struct ast_stream *stream, struct ast_format_cap *caps)
168 {
169         ast_assert(stream != NULL);
170
171         ao2_cleanup(stream->formats);
172         stream->formats = ao2_bump(caps);
173 }
174
175 enum ast_stream_state ast_stream_get_state(const struct ast_stream *stream)
176 {
177         ast_assert(stream != NULL);
178
179         return stream->state;
180 }
181
182 void ast_stream_set_state(struct ast_stream *stream, enum ast_stream_state state)
183 {
184         ast_assert(stream != NULL);
185
186         stream->state = state;
187 }
188
189 const char *ast_stream_state2str(enum ast_stream_state state)
190 {
191         switch (state) {
192         case AST_STREAM_STATE_REMOVED:
193                 return "removed";
194         case AST_STREAM_STATE_SENDRECV:
195                 return "sendrecv";
196         case AST_STREAM_STATE_SENDONLY:
197                 return "sendonly";
198         case AST_STREAM_STATE_RECVONLY:
199                 return "recvonly";
200         case AST_STREAM_STATE_INACTIVE:
201                 return "inactive";
202         default:
203                 return "<unknown>";
204         }
205 }
206
207 void *ast_stream_get_data(struct ast_stream *stream, enum ast_stream_data_slot slot)
208 {
209         ast_assert(stream != NULL);
210
211         return stream->data[slot];
212 }
213
214 void *ast_stream_set_data(struct ast_stream *stream, enum ast_stream_data_slot slot,
215         void *data, ast_stream_data_free_fn data_free_fn)
216 {
217         ast_assert(stream != NULL);
218
219         stream->data[slot] = data;
220         stream->data_free_fn[slot] = data_free_fn;
221
222         return data;
223 }
224
225 int ast_stream_get_position(const struct ast_stream *stream)
226 {
227         ast_assert(stream != NULL);
228
229         return stream->position;
230 }
231
232 #define TOPOLOGY_INITIAL_STREAM_COUNT 2
233 struct ast_stream_topology *ast_stream_topology_alloc(void)
234 {
235         struct ast_stream_topology *topology;
236
237         topology = ast_calloc(1, sizeof(*topology));
238         if (!topology) {
239                 return NULL;
240         }
241
242         if (AST_VECTOR_INIT(&topology->streams, TOPOLOGY_INITIAL_STREAM_COUNT)) {
243                 ast_free(topology);
244                 topology = NULL;
245         }
246
247         return topology;
248 }
249
250 struct ast_stream_topology *ast_stream_topology_clone(
251         const struct ast_stream_topology *topology)
252 {
253         struct ast_stream_topology *new_topology;
254         int i;
255
256         ast_assert(topology != NULL);
257
258         new_topology = ast_stream_topology_alloc();
259         if (!new_topology) {
260                 return NULL;
261         }
262
263         for (i = 0; i < AST_VECTOR_SIZE(&topology->streams); i++) {
264                 struct ast_stream *stream =
265                         ast_stream_clone(AST_VECTOR_GET(&topology->streams, i));
266
267                 if (!stream || AST_VECTOR_APPEND(&new_topology->streams, stream)) {
268                         ast_stream_free(stream);
269                         ast_stream_topology_free(new_topology);
270                         return NULL;
271                 }
272         }
273
274         return new_topology;
275 }
276
277 void ast_stream_topology_free(struct ast_stream_topology *topology)
278 {
279         if (!topology) {
280                 return;
281         }
282
283         AST_VECTOR_CALLBACK_VOID(&topology->streams, ast_stream_free);
284         AST_VECTOR_FREE(&topology->streams);
285         ast_free(topology);
286 }
287
288 int ast_stream_topology_append_stream(struct ast_stream_topology *topology, struct ast_stream *stream)
289 {
290         ast_assert(topology && stream);
291
292         if (AST_VECTOR_APPEND(&topology->streams, stream)) {
293                 return -1;
294         }
295
296         stream->position = AST_VECTOR_SIZE(&topology->streams) - 1;
297
298         return AST_VECTOR_SIZE(&topology->streams) - 1;
299 }
300
301 int ast_stream_topology_get_count(const struct ast_stream_topology *topology)
302 {
303         ast_assert(topology != NULL);
304
305         return AST_VECTOR_SIZE(&topology->streams);
306 }
307
308 struct ast_stream *ast_stream_topology_get_stream(
309         const struct ast_stream_topology *topology, unsigned int stream_num)
310 {
311         ast_assert(topology != NULL);
312
313         return AST_VECTOR_GET(&topology->streams, stream_num);
314 }
315
316 int ast_stream_topology_set_stream(struct ast_stream_topology *topology,
317         unsigned int position, struct ast_stream *stream)
318 {
319         struct ast_stream *existing_stream;
320
321         ast_assert(topology && stream);
322
323         if (position > AST_VECTOR_SIZE(&topology->streams)) {
324                 return -1;
325         }
326
327         if (position < AST_VECTOR_SIZE(&topology->streams)) {
328                 existing_stream = AST_VECTOR_GET(&topology->streams, position);
329                 ast_stream_free(existing_stream);
330         }
331
332         stream->position = position;
333
334         if (position == AST_VECTOR_SIZE(&topology->streams)) {
335                 AST_VECTOR_APPEND(&topology->streams, stream);
336                 return 0;
337         }
338
339         return AST_VECTOR_REPLACE(&topology->streams, position, stream);
340 }
341
342 struct ast_stream_topology *ast_stream_topology_create_from_format_cap(
343         struct ast_format_cap *cap)
344 {
345         struct ast_stream_topology *topology;
346         enum ast_media_type type;
347
348         topology = ast_stream_topology_alloc();
349         if (!topology || !cap || !ast_format_cap_count(cap)) {
350                 return topology;
351         }
352
353         for (type = AST_MEDIA_TYPE_UNKNOWN + 1; type < AST_MEDIA_TYPE_END; type++) {
354                 struct ast_format_cap *new_cap;
355                 struct ast_stream *stream;
356
357                 if (!ast_format_cap_has_type(cap, type)) {
358                         continue;
359                 }
360
361                 new_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
362                 if (!new_cap) {
363                         ast_stream_topology_free(topology);
364                         return NULL;
365                 }
366
367                 ast_format_cap_set_framing(new_cap, ast_format_cap_get_framing(cap));
368                 if (ast_format_cap_append_from_cap(new_cap, cap, type)) {
369                         ao2_cleanup(new_cap);
370                         ast_stream_topology_free(topology);
371                         return NULL;
372                 }
373
374                 stream = ast_stream_alloc(ast_codec_media_type2str(type), type);
375                 if (!stream) {
376                         ao2_cleanup(new_cap);
377                         ast_stream_topology_free(topology);
378                         return NULL;
379                 }
380                 /* We're transferring the initial ref so no bump needed */
381                 stream->formats = new_cap;
382                 stream->state = AST_STREAM_STATE_SENDRECV;
383                 if (ast_stream_topology_append_stream(topology, stream) == -1) {
384                         ast_stream_free(stream);
385                         ast_stream_topology_free(topology);
386                         return NULL;
387                 }
388         }
389
390         return topology;
391 }
392
393 struct ast_format_cap *ast_format_cap_from_stream_topology(
394     struct ast_stream_topology *topology)
395 {
396         struct ast_format_cap *caps;
397         int i;
398
399         ast_assert(topology != NULL);
400
401         caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
402         if (!caps) {
403                 return NULL;
404         }
405
406         for (i = 0; i < AST_VECTOR_SIZE(&topology->streams); i++) {
407                 struct ast_stream *stream = AST_VECTOR_GET(&topology->streams, i);
408
409                 if (!stream->formats) {
410                         continue;
411                 }
412
413                 ast_format_cap_append_from_cap(caps, stream->formats, AST_MEDIA_TYPE_UNKNOWN);
414         }
415
416         return caps;
417 }
418
419 struct ast_stream *ast_stream_topology_get_first_stream_by_type(
420         const struct ast_stream_topology *topology,
421         enum ast_media_type type)
422 {
423         int i;
424
425         ast_assert(topology != NULL);
426
427         for (i = 0; i < AST_VECTOR_SIZE(&topology->streams); i++) {
428                 struct ast_stream *stream = AST_VECTOR_GET(&topology->streams, i);
429
430                 if (stream->type == type) {
431                         return stream;
432                 }
433         }
434
435         return NULL;
436 }
437
438 void ast_stream_topology_map(const struct ast_stream_topology *topology,
439         struct ast_vector_int *types, struct ast_vector_int *v0, struct ast_vector_int *v1)
440 {
441         int i;
442         int nths[AST_MEDIA_TYPE_END] = {0};
443         int size = ast_stream_topology_get_count(topology);
444
445         /*
446          * Clear out any old mappings and initialize the new ones
447          */
448         AST_VECTOR_FREE(v0);
449         AST_VECTOR_FREE(v1);
450
451         /*
452          * Both vectors are sized to the topology. The media types vector is always
453          * guaranteed to be the size of the given topology or greater.
454          */
455         AST_VECTOR_INIT(v0, size);
456         AST_VECTOR_INIT(v1, size);
457
458         for (i = 0; i < size; ++i) {
459                 struct ast_stream *stream = ast_stream_topology_get_stream(topology, i);
460                 enum ast_media_type type = ast_stream_get_type(stream);
461                 int index = AST_VECTOR_GET_INDEX_NTH(types, ++nths[type],
462                         type, AST_VECTOR_ELEM_DEFAULT_CMP);
463
464                 if (index == -1) {
465                         /*
466                          * If a given type is not found for an index level then update the
467                          * media types vector with that type. This keeps the media types
468                          * vector always at the max topology size.
469                          */
470                         AST_VECTOR_APPEND(types, type);
471                         index = AST_VECTOR_SIZE(types) - 1;
472                 }
473
474                 /*
475                  * The mapping is reflexive in the sense that if it maps in one direction
476                  * then the reverse direction maps back to the other's index.
477                  */
478                 AST_VECTOR_REPLACE(v0, i, index);
479                 AST_VECTOR_REPLACE(v1, index, i);
480         }
481 }