core: Fix unused variable error in handle_show_sysinfo.
[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 The group that the stream is part of
71          */
72         int group;
73
74         /*!
75          * \brief Name for the stream within the context of the channel it is on
76          */
77         char name[0];
78 };
79
80 struct ast_stream_topology {
81         /*!
82          * \brief A vector of all the streams in this topology
83          */
84         AST_VECTOR(, struct ast_stream *) streams;
85 };
86
87 struct ast_stream *ast_stream_alloc(const char *name, enum ast_media_type type)
88 {
89         struct ast_stream *stream;
90
91         stream = ast_calloc(1, sizeof(*stream) + strlen(S_OR(name, "")) + 1);
92         if (!stream) {
93                 return NULL;
94         }
95
96         stream->type = type;
97         stream->state = AST_STREAM_STATE_INACTIVE;
98         stream->group = -1;
99         strcpy(stream->name, S_OR(name, "")); /* Safe */
100
101         return stream;
102 }
103
104 struct ast_stream *ast_stream_clone(const struct ast_stream *stream, const char *name)
105 {
106         struct ast_stream *new_stream;
107         size_t stream_size;
108         int idx;
109         const char *stream_name;
110
111         if (!stream) {
112                 return NULL;
113         }
114
115         stream_name = name ?: stream->name;
116         stream_size = sizeof(*stream) + strlen(stream_name) + 1;
117         new_stream = ast_calloc(1, stream_size);
118         if (!new_stream) {
119                 return NULL;
120         }
121
122         memcpy(new_stream, stream, sizeof(*new_stream));
123         strcpy(new_stream->name, stream_name); /* Safe */
124         new_stream->group = -1;
125         if (new_stream->formats) {
126                 ao2_ref(new_stream->formats, +1);
127         }
128
129         /* We cannot clone the opaque data because we don't know how. */
130         for (idx = 0; idx < AST_STREAM_DATA_SLOT_MAX; ++idx) {
131                 new_stream->data[idx] = NULL;
132                 new_stream->data_free_fn[idx] = NULL;
133         }
134
135         return new_stream;
136 }
137
138 void ast_stream_free(struct ast_stream *stream)
139 {
140         int i;
141
142         if (!stream) {
143                 return;
144         }
145
146         for (i = 0; i < AST_STREAM_DATA_SLOT_MAX; i++) {
147                 if (stream->data_free_fn[i]) {
148                         stream->data_free_fn[i](stream->data[i]);
149                 }
150         }
151
152         ao2_cleanup(stream->formats);
153         ast_free(stream);
154 }
155
156 const char *ast_stream_get_name(const struct ast_stream *stream)
157 {
158         ast_assert(stream != NULL);
159
160         return stream->name;
161 }
162
163 enum ast_media_type ast_stream_get_type(const struct ast_stream *stream)
164 {
165         ast_assert(stream != NULL);
166
167         return stream->type;
168 }
169
170 void ast_stream_set_type(struct ast_stream *stream, enum ast_media_type type)
171 {
172         ast_assert(stream != NULL);
173
174         stream->type = type;
175 }
176
177 struct ast_format_cap *ast_stream_get_formats(const struct ast_stream *stream)
178 {
179         ast_assert(stream != NULL);
180
181         return stream->formats;
182 }
183
184 void ast_stream_set_formats(struct ast_stream *stream, struct ast_format_cap *caps)
185 {
186         ast_assert(stream != NULL);
187
188         ao2_cleanup(stream->formats);
189         stream->formats = ao2_bump(caps);
190 }
191
192 enum ast_stream_state ast_stream_get_state(const struct ast_stream *stream)
193 {
194         ast_assert(stream != NULL);
195
196         return stream->state;
197 }
198
199 void ast_stream_set_state(struct ast_stream *stream, enum ast_stream_state state)
200 {
201         ast_assert(stream != NULL);
202
203         stream->state = state;
204 }
205
206 const char *ast_stream_state2str(enum ast_stream_state state)
207 {
208         switch (state) {
209         case AST_STREAM_STATE_REMOVED:
210                 return "removed";
211         case AST_STREAM_STATE_SENDRECV:
212                 return "sendrecv";
213         case AST_STREAM_STATE_SENDONLY:
214                 return "sendonly";
215         case AST_STREAM_STATE_RECVONLY:
216                 return "recvonly";
217         case AST_STREAM_STATE_INACTIVE:
218                 return "inactive";
219         default:
220                 return "<unknown>";
221         }
222 }
223
224 enum ast_stream_state ast_stream_str2state(const char *str)
225 {
226         if (!strcmp("sendrecv", str)) {
227                 return AST_STREAM_STATE_SENDRECV;
228         }
229         if (!strcmp("sendonly", str)) {
230                 return AST_STREAM_STATE_SENDONLY;
231         }
232         if (!strcmp("recvonly", str)) {
233                 return AST_STREAM_STATE_RECVONLY;
234         }
235         if (!strcmp("inactive", str)) {
236                 return AST_STREAM_STATE_INACTIVE;
237         }
238         return AST_STREAM_STATE_REMOVED;
239 }
240
241 void *ast_stream_get_data(struct ast_stream *stream, enum ast_stream_data_slot slot)
242 {
243         ast_assert(stream != NULL);
244
245         return stream->data[slot];
246 }
247
248 void *ast_stream_set_data(struct ast_stream *stream, enum ast_stream_data_slot slot,
249         void *data, ast_stream_data_free_fn data_free_fn)
250 {
251         ast_assert(stream != NULL);
252
253         stream->data[slot] = data;
254         stream->data_free_fn[slot] = data_free_fn;
255
256         return data;
257 }
258
259 int ast_stream_get_position(const struct ast_stream *stream)
260 {
261         ast_assert(stream != NULL);
262
263         return stream->position;
264 }
265
266 #define TOPOLOGY_INITIAL_STREAM_COUNT 2
267 struct ast_stream_topology *ast_stream_topology_alloc(void)
268 {
269         struct ast_stream_topology *topology;
270
271         topology = ast_calloc(1, sizeof(*topology));
272         if (!topology) {
273                 return NULL;
274         }
275
276         if (AST_VECTOR_INIT(&topology->streams, TOPOLOGY_INITIAL_STREAM_COUNT)) {
277                 ast_free(topology);
278                 topology = NULL;
279         }
280
281         return topology;
282 }
283
284 struct ast_stream_topology *ast_stream_topology_clone(
285         const struct ast_stream_topology *topology)
286 {
287         struct ast_stream_topology *new_topology;
288         int i;
289
290         ast_assert(topology != NULL);
291
292         new_topology = ast_stream_topology_alloc();
293         if (!new_topology) {
294                 return NULL;
295         }
296
297         for (i = 0; i < AST_VECTOR_SIZE(&topology->streams); i++) {
298                 struct ast_stream *existing = AST_VECTOR_GET(&topology->streams, i);
299                 struct ast_stream *stream = ast_stream_clone(existing, NULL);
300
301                 if (!stream || AST_VECTOR_APPEND(&new_topology->streams, stream)) {
302                         ast_stream_free(stream);
303                         ast_stream_topology_free(new_topology);
304                         return NULL;
305                 }
306
307                 ast_stream_set_group(stream, ast_stream_get_group(existing));
308         }
309
310         return new_topology;
311 }
312
313 int ast_stream_topology_equal(const struct ast_stream_topology *left,
314         const struct ast_stream_topology *right)
315 {
316         int index;
317
318         ast_assert(left != NULL);
319         ast_assert(right != NULL);
320
321         if (ast_stream_topology_get_count(left) != ast_stream_topology_get_count(right)) {
322                 return 0;
323         }
324
325         for (index = 0; index < ast_stream_topology_get_count(left); ++index) {
326                 const struct ast_stream *left_stream = ast_stream_topology_get_stream(left, index);
327                 const struct ast_stream *right_stream = ast_stream_topology_get_stream(right, index);
328
329                 if (ast_stream_get_type(left_stream) != ast_stream_get_type(right_stream)) {
330                         return 0;
331                 }
332
333                 if (ast_stream_get_state(left_stream) != ast_stream_get_state(right_stream)) {
334                         return 0;
335                 }
336
337                 if (!ast_stream_get_formats(left_stream) && ast_stream_get_formats(right_stream) &&
338                         ast_format_cap_count(ast_stream_get_formats(right_stream))) {
339                         /* A NULL format capabilities and an empty format capabilities are the same, as they have
340                          * no formats inside. If one does though... they are not equal.
341                          */
342                         return 0;
343                 } else if (!ast_stream_get_formats(right_stream) && ast_stream_get_formats(left_stream) &&
344                         ast_format_cap_count(ast_stream_get_formats(left_stream))) {
345                         return 0;
346                 } else if (ast_stream_get_formats(left_stream) && ast_stream_get_formats(right_stream) &&
347                         !ast_format_cap_identical(ast_stream_get_formats(left_stream), ast_stream_get_formats(right_stream))) {
348                         /* But if both are actually present we need to do an actual identical check. */
349                         return 0;
350                 }
351
352                 if (strcmp(ast_stream_get_name(left_stream), ast_stream_get_name(right_stream))) {
353                         return 0;
354                 }
355         }
356
357         return 1;
358 }
359
360 void ast_stream_topology_free(struct ast_stream_topology *topology)
361 {
362         if (!topology) {
363                 return;
364         }
365
366         AST_VECTOR_CALLBACK_VOID(&topology->streams, ast_stream_free);
367         AST_VECTOR_FREE(&topology->streams);
368         ast_free(topology);
369 }
370
371 int ast_stream_topology_append_stream(struct ast_stream_topology *topology, struct ast_stream *stream)
372 {
373         ast_assert(topology && stream);
374
375         if (AST_VECTOR_APPEND(&topology->streams, stream)) {
376                 return -1;
377         }
378
379         stream->position = AST_VECTOR_SIZE(&topology->streams) - 1;
380
381         return AST_VECTOR_SIZE(&topology->streams) - 1;
382 }
383
384 int ast_stream_topology_get_count(const struct ast_stream_topology *topology)
385 {
386         ast_assert(topology != NULL);
387
388         return AST_VECTOR_SIZE(&topology->streams);
389 }
390
391 struct ast_stream *ast_stream_topology_get_stream(
392         const struct ast_stream_topology *topology, unsigned int stream_num)
393 {
394         ast_assert(topology != NULL);
395
396         return AST_VECTOR_GET(&topology->streams, stream_num);
397 }
398
399 int ast_stream_topology_set_stream(struct ast_stream_topology *topology,
400         unsigned int position, struct ast_stream *stream)
401 {
402         struct ast_stream *existing_stream;
403
404         ast_assert(topology && stream);
405
406         if (position > AST_VECTOR_SIZE(&topology->streams)) {
407                 return -1;
408         }
409
410         if (position < AST_VECTOR_SIZE(&topology->streams)) {
411                 existing_stream = AST_VECTOR_GET(&topology->streams, position);
412                 ast_stream_free(existing_stream);
413         }
414
415         stream->position = position;
416
417         if (position == AST_VECTOR_SIZE(&topology->streams)) {
418                 return AST_VECTOR_APPEND(&topology->streams, stream);
419         }
420
421         return AST_VECTOR_REPLACE(&topology->streams, position, stream);
422 }
423
424 int ast_stream_topology_del_stream(struct ast_stream_topology *topology,
425         unsigned int position)
426 {
427         struct ast_stream *stream;
428
429         ast_assert(topology != NULL);
430
431         if (AST_VECTOR_SIZE(&topology->streams) <= position) {
432                 return -1;
433         }
434
435         stream = AST_VECTOR_REMOVE_ORDERED(&topology->streams, position);
436         ast_stream_free(stream);
437
438         /* Fix up higher stream position indices */
439         for (; position < AST_VECTOR_SIZE(&topology->streams); ++position) {
440                 stream = AST_VECTOR_GET(&topology->streams, position);
441                 stream->position = position;
442         }
443
444         return 0;
445 }
446
447 struct ast_stream_topology *ast_stream_topology_create_from_format_cap(
448         struct ast_format_cap *cap)
449 {
450         struct ast_stream_topology *topology;
451         enum ast_media_type type;
452
453         topology = ast_stream_topology_alloc();
454         if (!topology || !cap || !ast_format_cap_count(cap)) {
455                 return topology;
456         }
457
458         for (type = AST_MEDIA_TYPE_UNKNOWN + 1; type < AST_MEDIA_TYPE_END; type++) {
459                 struct ast_format_cap *new_cap;
460                 struct ast_stream *stream;
461
462                 if (!ast_format_cap_has_type(cap, type)) {
463                         continue;
464                 }
465
466                 new_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
467                 if (!new_cap) {
468                         ast_stream_topology_free(topology);
469                         return NULL;
470                 }
471
472                 ast_format_cap_set_framing(new_cap, ast_format_cap_get_framing(cap));
473                 if (ast_format_cap_append_from_cap(new_cap, cap, type)) {
474                         ao2_cleanup(new_cap);
475                         ast_stream_topology_free(topology);
476                         return NULL;
477                 }
478
479                 stream = ast_stream_alloc(ast_codec_media_type2str(type), type);
480                 if (!stream) {
481                         ao2_cleanup(new_cap);
482                         ast_stream_topology_free(topology);
483                         return NULL;
484                 }
485                 /* We're transferring the initial ref so no bump needed */
486                 stream->formats = new_cap;
487                 stream->state = AST_STREAM_STATE_SENDRECV;
488                 if (ast_stream_topology_append_stream(topology, stream) == -1) {
489                         ast_stream_free(stream);
490                         ast_stream_topology_free(topology);
491                         return NULL;
492                 }
493         }
494
495         return topology;
496 }
497
498 struct ast_format_cap *ast_format_cap_from_stream_topology(
499     struct ast_stream_topology *topology)
500 {
501         struct ast_format_cap *caps;
502         int i;
503
504         ast_assert(topology != NULL);
505
506         caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
507         if (!caps) {
508                 return NULL;
509         }
510
511         for (i = 0; i < AST_VECTOR_SIZE(&topology->streams); i++) {
512                 struct ast_stream *stream;
513
514                 stream = AST_VECTOR_GET(&topology->streams, i);
515                 if (!stream->formats
516                         || stream->state == AST_STREAM_STATE_REMOVED) {
517                         continue;
518                 }
519
520                 ast_format_cap_append_from_cap(caps, stream->formats, AST_MEDIA_TYPE_UNKNOWN);
521         }
522
523         return caps;
524 }
525
526 struct ast_stream *ast_stream_topology_get_first_stream_by_type(
527         const struct ast_stream_topology *topology,
528         enum ast_media_type type)
529 {
530         int i;
531
532         ast_assert(topology != NULL);
533
534         for (i = 0; i < AST_VECTOR_SIZE(&topology->streams); i++) {
535                 struct ast_stream *stream;
536
537                 stream = AST_VECTOR_GET(&topology->streams, i);
538                 if (stream->type == type
539                         && stream->state != AST_STREAM_STATE_REMOVED) {
540                         return stream;
541                 }
542         }
543
544         return NULL;
545 }
546
547 void ast_stream_topology_map(const struct ast_stream_topology *topology,
548         struct ast_vector_int *types, struct ast_vector_int *v0, struct ast_vector_int *v1)
549 {
550         int i;
551         int nths[AST_MEDIA_TYPE_END] = {0};
552         int size = ast_stream_topology_get_count(topology);
553
554         /*
555          * Clear out any old mappings and initialize the new ones
556          */
557         AST_VECTOR_FREE(v0);
558         AST_VECTOR_FREE(v1);
559
560         /*
561          * Both vectors are sized to the topology. The media types vector is always
562          * guaranteed to be the size of the given topology or greater.
563          */
564         AST_VECTOR_INIT(v0, size);
565         AST_VECTOR_INIT(v1, size);
566
567         for (i = 0; i < size; ++i) {
568                 struct ast_stream *stream = ast_stream_topology_get_stream(topology, i);
569                 enum ast_media_type type = ast_stream_get_type(stream);
570                 int index = AST_VECTOR_GET_INDEX_NTH(types, ++nths[type],
571                         type, AST_VECTOR_ELEM_DEFAULT_CMP);
572
573                 if (index == -1) {
574                         /*
575                          * If a given type is not found for an index level then update the
576                          * media types vector with that type. This keeps the media types
577                          * vector always at the max topology size.
578                          */
579                         AST_VECTOR_APPEND(types, type);
580                         index = AST_VECTOR_SIZE(types) - 1;
581                 }
582
583                 /*
584                  * The mapping is reflexive in the sense that if it maps in one direction
585                  * then the reverse direction maps back to the other's index.
586                  */
587                 AST_VECTOR_REPLACE(v0, i, index);
588                 AST_VECTOR_REPLACE(v1, index, i);
589         }
590 }
591
592 int ast_stream_get_group(const struct ast_stream *stream)
593 {
594         ast_assert(stream != NULL);
595
596         return stream->group;
597 }
598
599 void ast_stream_set_group(struct ast_stream *stream, int group)
600 {
601         ast_assert(stream != NULL);
602
603         stream->group = group;
604 }