Asterisk - The Open Source Telephony Project GIT-master-7921072
stream.c
Go to the documentation of this file.
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#include "asterisk/vector.h"
38#include "asterisk/config.h"
39#include "asterisk/rtp_engine.h"
40
42 size_t length;
44 char name_value[0];
45};
46
53};
54
59};
60
67};
68
70 [CODEC_NEGOTIATION_KEEP_UNSPECIFIED] = "unspecified",
73};
74
79};
80
81struct ast_stream {
82 /*!
83 * \brief The type of media the stream is handling
84 */
86
87 /*!
88 * \brief The position of the stream in the topology
89 */
90 unsigned int position;
91
92 /*!
93 * \brief Current formats negotiated on the stream
94 */
96
97 /*!
98 * \brief The current state of the stream
99 */
101
102 /*!
103 * \brief Stream metadata vector
104 */
106
107 /*!
108 * \brief The group that the stream is part of
109 */
110 int group;
111
112 /*!
113 * \brief The rtp_codecs used by the stream
114 */
116
117 /*!
118 * \brief Name for the stream within the context of the channel it is on
119 */
120 char name[0];
121};
122
124 /*!
125 * \brief A vector of all the streams in this topology
126 */
128 /*! Indicates that this topology should not have further operations applied to it. */
129 int final;
130};
131
133{
134 if (!prefs || !buf || !*buf) {
135 return "";
136 }
137
138 ast_str_append(buf, 0, "%s:%s, %s:%s, %s:%s, %s:%s",
147 );
148
149 return ast_str_buffer(*buf);
150}
151
152/*!
153 * \internal
154 * \brief Sets a codec prefs member based on a the preference name and string value
155 *
156 * \warning This macro will cause the calling function to return if a preference name
157 * is matched but the value isn't valid for this preference.
158 */
159#define set_pref_value(_name, _value, _prefs, _UC, _lc, _error_message) \
160({ \
161 int _res = 0; \
162 if (strcmp(_name, ast_stream_codec_negotiation_params_map[CODEC_NEGOTIATION_PARAM_ ## _UC]) == 0) { \
163 int i; \
164 for (i = CODEC_NEGOTIATION_ ## _UC ## _UNSPECIFIED + 1; i < CODEC_NEGOTIATION_ ## _UC ## _END; i++) { \
165 if (strcmp(value, ast_stream_codec_negotiation_ ## _lc ## _map[i]) == 0) { \
166 prefs->_lc = i; \
167 } \
168 } \
169 if ( prefs->_lc == CODEC_NEGOTIATION_ ## _UC ## _UNSPECIFIED) { \
170 _res = -1; \
171 if (_error_message) { \
172 ast_str_append(_error_message, 0, "Codec preference '%s' has invalid value '%s'", name, value); \
173 } \
174 } \
175 } \
176 if (_res < 0) { \
177 return _res; \
178 } \
179})
180
181int ast_stream_codec_prefs_parse(const char *pref_string, struct ast_stream_codec_negotiation_prefs *prefs,
182 struct ast_str **error_message)
183{
184 char *initial_value = ast_strdupa(pref_string);
185 char *current_value;
186 char *pref;
187 char *saveptr1;
188 char *saveptr2;
189 char *name;
190 char *value;
191
192 if (!prefs) {
193 return -1;
194 }
195
200
201 for (current_value = initial_value; (pref = strtok_r(current_value, ",", &saveptr1)) != NULL; ) {
202 name = strtok_r(pref, ": ", &saveptr2);
203 value = strtok_r(NULL, ": ", &saveptr2);
204
205 if (!name || !value) {
206 if (error_message) {
207 ast_str_append(error_message, 0, "Codec preference '%s' is invalid", pref);
208 }
209 return -1;
210 }
211
212 set_pref_value(name, value, prefs, OPERATION, operation, error_message);
213 set_pref_value(name, value, prefs, PREFER, prefer, error_message);
214 set_pref_value(name, value, prefs, KEEP, keep, error_message);
215 set_pref_value(name, value, prefs, TRANSCODE, transcode, error_message);
216
217 current_value = NULL;
218 }
219
220 return 0;
221}
222
223const char *ast_stream_state_map[] = {
224 [AST_STREAM_STATE_REMOVED] = "removed",
225 [AST_STREAM_STATE_SENDRECV] = "sendrecv",
226 [AST_STREAM_STATE_SENDONLY] = "sendonly",
227 [AST_STREAM_STATE_RECVONLY] = "recvonly",
228 [AST_STREAM_STATE_INACTIVE] = "inactive",
229};
230
231#define MIN_STREAM_NAME_LEN 16
232
234{
235 struct ast_stream *stream;
236 size_t name_len = MAX(strlen(S_OR(name, "")), MIN_STREAM_NAME_LEN); /* Ensure there is enough room for 'removed' or a type-position */
237
238 stream = ast_calloc(1, sizeof(*stream) + name_len + 1);
239 if (!stream) {
240 return NULL;
241 }
242
243 stream->type = type;
245 stream->group = -1;
246 strcpy(stream->name, S_OR(name, "")); /* Safe */
247
249 if (!stream->formats) {
250 ast_free(stream);
251 return NULL;
252 }
253
254 return stream;
255}
256
257struct ast_stream *ast_stream_clone(const struct ast_stream *stream, const char *name)
258{
259 struct ast_stream *new_stream;
260 const char *stream_name;
261 size_t name_len;
262
263 if (!stream) {
264 return NULL;
265 }
266
267 stream_name = name ?: stream->name;
268 name_len = MAX(strlen(S_OR(stream_name, "")), MIN_STREAM_NAME_LEN); /* Ensure there is enough room for 'removed' or a type-position */
269 new_stream = ast_calloc(1, sizeof(*stream) + name_len + 1);
270 if (!new_stream) {
271 return NULL;
272 }
273
274 memcpy(new_stream, stream, sizeof(*new_stream));
275 strcpy(new_stream->name, stream_name); /* Safe */
276 new_stream->group = -1;
277
279 if (!new_stream->formats) {
280 ast_free(new_stream);
281 return NULL;
282 }
284
285 new_stream->metadata = ast_stream_get_metadata_list(stream);
286
287 /* rtp_codecs aren't cloned */
288
289 return new_stream;
290}
291
292void ast_stream_free(struct ast_stream *stream)
293{
294 if (!stream) {
295 return;
296 }
297
299
300 if (stream->rtp_codecs) {
302 }
303
304 ao2_cleanup(stream->formats);
305
306 ast_free(stream);
307}
308
309const char *ast_stream_get_name(const struct ast_stream *stream)
310{
311 ast_assert(stream != NULL);
312
313 return stream->name;
314}
315
317{
318 ast_assert(stream != NULL);
319
320 return stream->type;
321}
322
324{
325 ast_assert(stream != NULL);
326
327 stream->type = type;
328}
329
330const struct ast_format_cap *ast_stream_get_formats(const struct ast_stream *stream)
331{
332 ast_assert(stream != NULL);
333
334 return stream->formats;
335}
336
337const char *ast_stream_to_str(const struct ast_stream *stream, struct ast_str **buf)
338{
339 if (!buf || !*buf) {
340 return "";
341 }
342
343 if (!stream) {
344 ast_str_append(buf, 0, "(null stream)");
345 return ast_str_buffer(*buf);
346 }
347
348 ast_str_append(buf, 0, "%d:%s:%s:%s ",
349 stream->position,
350 S_OR(stream->name, "noname"),
352 ast_stream_state_map[stream->state]);
354
355 return ast_str_buffer(*buf);
356}
357
359{
360 ast_assert(stream != NULL);
361
362 return stream->formats ? ast_format_cap_count(stream->formats) : 0;
363}
364
365void ast_stream_set_formats(struct ast_stream *stream, struct ast_format_cap *caps)
366{
367 ast_assert(stream != NULL);
368
369 ao2_cleanup(stream->formats);
370 stream->formats = ao2_bump(caps);
371}
372
374{
375 ast_assert(stream != NULL);
376
377 return stream->state;
378}
379
381{
382 ast_assert(stream != NULL);
383
384 stream->state = state;
385
386}
387
389{
390 switch (state) {
392 return "removed";
394 return "sendrecv";
396 return "sendonly";
398 return "recvonly";
400 return "inactive";
401 default:
402 return "<unknown>";
403 }
404}
405
407{
408 if (!strcmp("sendrecv", str)) {
410 }
411 if (!strcmp("sendonly", str)) {
413 }
414 if (!strcmp("recvonly", str)) {
416 }
417 if (!strcmp("inactive", str)) {
419 }
421}
422
423const char *ast_stream_get_metadata(const struct ast_stream *stream, const char *m_key)
424{
425 struct ast_variable *v;
426
427 ast_assert_return(stream != NULL, NULL);
428 ast_assert_return(m_key != NULL, NULL);
429
430 for (v = stream->metadata; v; v = v->next) {
431 if (strcmp(v->name, m_key) == 0) {
432 return v->value;
433 }
434 }
435
436 return NULL;
437}
438
440{
441 struct ast_variable *v;
442 struct ast_variable *vout = NULL;
443
444 ast_assert_return(stream != NULL, NULL);
445
446 for (v = stream->metadata; v; v = v->next) {
447 struct ast_variable *vt = ast_variable_new(v->name, v->value, "");
448
449 if (!vt) {
451 return NULL;
452 }
453
454 ast_variable_list_append(&vout, vt);
455 }
456
457 return vout;
458}
459
460int ast_stream_set_metadata(struct ast_stream *stream, const char *m_key, const char *value)
461{
462 struct ast_variable *v;
463 struct ast_variable *prev;
464
465 ast_assert_return(stream != NULL, -1);
466 ast_assert_return(m_key != NULL, -1);
467
468 prev = NULL;
469 v = stream->metadata;
470 while(v) {
471 struct ast_variable *next = v->next;
472 if (strcmp(v->name, m_key) == 0) {
473 if (prev) {
474 prev->next = next;
475 } else {
476 stream->metadata = next;
477 }
478 ast_free(v);
479 break;
480 } else {
481 prev = v;
482 }
483 v = next;
484 }
485
486 if (!value) {
487 return 0;
488 }
489
490 v = ast_variable_new(m_key, value, "");
491 if (!v) {
492 return -1;
493 }
494
496
497 return 0;
498}
499
500int ast_stream_get_position(const struct ast_stream *stream)
501{
502 ast_assert(stream != NULL);
503
504 return stream->position;
505}
506
508{
509 ast_assert(stream != NULL);
510
511 return stream->rtp_codecs;
512}
513
514void ast_stream_set_rtp_codecs(struct ast_stream *stream, struct ast_rtp_codecs *rtp_codecs)
515{
516 ast_assert(stream != NULL);
517
518 if (stream->rtp_codecs) {
520 }
521
522 stream->rtp_codecs = rtp_codecs;
523}
524
525struct ast_stream *ast_stream_create_resolved(struct ast_stream *pending_stream,
526 struct ast_stream *validation_stream, struct ast_stream_codec_negotiation_prefs *prefs,
527 struct ast_str **error_message)
528{
529 struct ast_format_cap *preferred_caps = NULL;
530 struct ast_format_cap *nonpreferred_caps = NULL;
532 struct ast_stream *joint_stream;
533 enum ast_media_type media_type = pending_stream ? pending_stream->type : AST_MEDIA_TYPE_UNKNOWN;
534 int res = 0;
535 SCOPE_ENTER(4, "Pending: %s Validation: %s Prefs: %s\n",
536 ast_str_tmp(128, ast_stream_to_str(pending_stream, &STR_TMP)),
537 ast_str_tmp(128, ast_stream_to_str(validation_stream, &STR_TMP)),
538 ast_str_tmp(128, ast_stream_codec_prefs_to_str(prefs, &STR_TMP)));
539
540 if (!pending_stream || !validation_stream || !prefs || !joint_caps
541 || media_type == AST_MEDIA_TYPE_UNKNOWN) {
542 if (error_message) {
543 ast_str_append(error_message, 0, "Invalid arguments");
544 }
545 ao2_cleanup(joint_caps);
546 SCOPE_EXIT_RTN_VALUE(NULL, "Invalid arguments\n");
547 }
548
550 preferred_caps = pending_stream->formats;
551 nonpreferred_caps = validation_stream->formats;
552 } else {
553 preferred_caps = validation_stream->formats;
554 nonpreferred_caps = pending_stream->formats;
555 }
557
558 switch(prefs->operation) {
560 res = ast_format_cap_append_from_cap(joint_caps, preferred_caps, media_type);
561 break;
563 res = ast_format_cap_append_from_cap(joint_caps, nonpreferred_caps, media_type);
564 break;
566 res = ast_format_cap_get_compatible(preferred_caps, nonpreferred_caps, joint_caps);
567 break;
569 res = ast_format_cap_append_from_cap(joint_caps, preferred_caps, media_type);
570 if (res == 0) {
571 res = ast_format_cap_append_from_cap(joint_caps, nonpreferred_caps, media_type);
572 }
573 break;
574 default:
575 break;
576 }
577
578 if (res) {
579 if (error_message) {
580 ast_str_append(error_message, 0, "No common formats available for media type '%s' ",
581 ast_codec_media_type2str(pending_stream->type));
582 ast_format_cap_append_names(preferred_caps, error_message);
583 ast_str_append(error_message, 0, "<>");
584 ast_format_cap_append_names(nonpreferred_caps, error_message);
585 ast_str_append(error_message, 0, " with prefs: ");
586 ast_stream_codec_prefs_to_str(prefs, error_message);
587 }
588
589 ao2_cleanup(joint_caps);
590 SCOPE_EXIT_RTN_VALUE(NULL, "No common formats available\n");
591 }
592
593 if (!ast_format_cap_empty(joint_caps)) {
594 if (prefs->keep == CODEC_NEGOTIATION_KEEP_FIRST) {
595 struct ast_format *single = ast_format_cap_get_format(joint_caps, 0);
597 ast_format_cap_append(joint_caps, single, 0);
598 ao2_ref(single, -1);
599 }
600 } else {
601 if (error_message) {
602 ast_str_append(error_message, 0, "No common formats available for media type '%s' ",
603 ast_codec_media_type2str(pending_stream->type));
604 ast_format_cap_append_names(preferred_caps, error_message);
605 ast_str_append(error_message, 0, "<>");
606 ast_format_cap_append_names(nonpreferred_caps, error_message);
607 ast_str_append(error_message, 0, " with prefs: ");
608 ast_stream_codec_prefs_to_str(prefs, error_message);
609 }
610 }
611
612 joint_stream = ast_stream_clone(pending_stream, NULL);
613 if (!joint_stream) {
614 ao2_cleanup(joint_caps);
615 return NULL;
616 }
617
618 /* ref to joint_caps will be transferred to the stream */
619 ast_stream_set_formats(joint_stream, joint_caps);
620
621 if (TRACE_ATLEAST(3)) {
623 if (buf) {
624 ast_str_set(&buf, 0, "Resolved '%s' stream ", ast_codec_media_type2str(pending_stream->type));
625 ast_format_cap_append_names(preferred_caps, &buf);
626 ast_str_append(&buf, 0, "<>");
627 ast_format_cap_append_names(nonpreferred_caps, &buf);
628 ast_str_append(&buf, 0, " to ");
629 ast_format_cap_append_names(joint_caps, &buf);
630 ast_str_append(&buf, 0, " with prefs: ");
632 ast_trace(1, "%s\n", ast_str_buffer(buf));
633 ast_free(buf);
634 }
635 }
636
637 ao2_cleanup(joint_caps);
638 SCOPE_EXIT_RTN_VALUE(joint_stream, "Joint stream: %s\n", ast_str_tmp(128, ast_stream_to_str(joint_stream, &STR_TMP)));
639}
640
641static void stream_topology_destroy(void *data)
642{
643 struct ast_stream_topology *topology = data;
644
646 AST_VECTOR_FREE(&topology->streams);
647}
648
649#define TOPOLOGY_INITIAL_STREAM_COUNT 2
651{
652 struct ast_stream_topology *topology;
653
655 if (!topology) {
656 return NULL;
657 }
658
660 ao2_ref(topology, -1);
661 topology = NULL;
662 }
663
664 return topology;
665}
666
668 const struct ast_stream_topology *topology)
669{
670 struct ast_stream_topology *new_topology;
671 int i;
672
673 ast_assert(topology != NULL);
674
675 new_topology = ast_stream_topology_alloc();
676 if (!new_topology) {
677 return NULL;
678 }
679
680 for (i = 0; i < AST_VECTOR_SIZE(&topology->streams); i++) {
681 struct ast_stream *existing = AST_VECTOR_GET(&topology->streams, i);
682 struct ast_stream *stream = ast_stream_clone(existing, NULL);
683
684 if (!stream || AST_VECTOR_APPEND(&new_topology->streams, stream)) {
685 ast_stream_free(stream);
686 ast_stream_topology_free(new_topology);
687 return NULL;
688 }
689
691 }
692
693 return new_topology;
694}
695
697 const struct ast_stream_topology *right)
698{
699 int index;
700
701 ast_assert(left != NULL);
702 ast_assert(right != NULL);
703
705 return 0;
706 }
707
708 for (index = 0; index < ast_stream_topology_get_count(left); ++index) {
709 const struct ast_stream *left_stream = ast_stream_topology_get_stream(left, index);
710 const struct ast_stream *right_stream = ast_stream_topology_get_stream(right, index);
711
712 if (ast_stream_get_type(left_stream) != ast_stream_get_type(right_stream)) {
713 return 0;
714 }
715
716 if (ast_stream_get_state(left_stream) != ast_stream_get_state(right_stream)) {
717 return 0;
718 }
719
720 if (!ast_stream_get_formats(left_stream) && ast_stream_get_formats(right_stream) &&
722 /* A NULL format capabilities and an empty format capabilities are the same, as they have
723 * no formats inside. If one does though... they are not equal.
724 */
725 return 0;
726 } else if (!ast_stream_get_formats(right_stream) && ast_stream_get_formats(left_stream) &&
728 return 0;
729 } else if (ast_stream_get_formats(left_stream) && ast_stream_get_formats(right_stream) &&
731 /* But if both are actually present we need to do an actual identical check. */
732 return 0;
733 }
734
735 if (strcmp(ast_stream_get_name(left_stream), ast_stream_get_name(right_stream))) {
736 return 0;
737 }
738 }
739
740 return 1;
741}
742
744{
745 ao2_cleanup(topology);
746}
747
749{
750 ast_assert(topology && stream);
751
752 if (AST_VECTOR_APPEND(&topology->streams, stream)) {
753 return -1;
754 }
755
756 stream->position = AST_VECTOR_SIZE(&topology->streams) - 1;
757
758 if (ast_strlen_zero(stream->name)) {
759 snprintf(stream->name, MIN_STREAM_NAME_LEN, "%s-%d", ast_codec_media_type2str(stream->type), stream->position);
760 }
761
762 return AST_VECTOR_SIZE(&topology->streams) - 1;
763}
764
766{
767 ast_assert(topology != NULL);
768
769 return AST_VECTOR_SIZE(&topology->streams);
770}
771
773{
774 int i;
775 int count = 0;
776 ast_assert(topology != NULL);
777
778 for (i = 0; i < AST_VECTOR_SIZE(&topology->streams); i++) {
779 struct ast_stream *stream = AST_VECTOR_GET(&topology->streams, i);
780 if (stream->state != AST_STREAM_STATE_REMOVED) {
781 count++;
782 }
783 }
784
785 return count;
786}
787
789 const struct ast_stream_topology *topology, unsigned int stream_num)
790{
791 ast_assert(topology != NULL);
792
793 return AST_VECTOR_GET(&topology->streams, stream_num);
794}
795
797 unsigned int position, struct ast_stream *stream)
798{
799 struct ast_stream *existing_stream;
800
801 ast_assert(topology && stream);
802
803 if (position > AST_VECTOR_SIZE(&topology->streams)) {
804 return -1;
805 }
806
807 if (position < AST_VECTOR_SIZE(&topology->streams)) {
808 existing_stream = AST_VECTOR_GET(&topology->streams, position);
809 ast_stream_free(existing_stream);
810 }
811
812 stream->position = position;
813
814 if (position == AST_VECTOR_SIZE(&topology->streams)) {
815 return AST_VECTOR_APPEND(&topology->streams, stream);
816 }
817
818 if (ast_strlen_zero(stream->name)) {
819 snprintf(stream->name, MIN_STREAM_NAME_LEN, "%s-%d", ast_codec_media_type2str(stream->type), stream->position);
820 }
821
822 return AST_VECTOR_REPLACE(&topology->streams, position, stream);
823}
824
826 unsigned int position)
827{
828 struct ast_stream *stream;
829
830 ast_assert(topology != NULL);
831
832 if (AST_VECTOR_SIZE(&topology->streams) <= position) {
833 return -1;
834 }
835
836 stream = AST_VECTOR_REMOVE_ORDERED(&topology->streams, position);
837 ast_stream_free(stream);
838
839 /* Fix up higher stream position indices */
840 for (; position < AST_VECTOR_SIZE(&topology->streams); ++position) {
841 stream = AST_VECTOR_GET(&topology->streams, position);
842 stream->position = position;
843 }
844
845 return 0;
846}
847
849 struct ast_format_cap *cap)
850{
851 struct ast_stream_topology *topology;
852 enum ast_media_type type;
853
854 topology = ast_stream_topology_alloc();
855 if (!topology || !cap || !ast_format_cap_count(cap)) {
856 return topology;
857 }
858
860 struct ast_format_cap *new_cap;
861 struct ast_stream *stream;
862
863 if (!ast_format_cap_has_type(cap, type)) {
864 continue;
865 }
866
868 if (!new_cap) {
869 ast_stream_topology_free(topology);
870 return NULL;
871 }
872
874 if (ast_format_cap_append_from_cap(new_cap, cap, type)) {
875 ao2_cleanup(new_cap);
876 ast_stream_topology_free(topology);
877 return NULL;
878 }
879
880 stream = ast_stream_alloc(NULL, type);
881 if (!stream) {
882 ao2_cleanup(new_cap);
883 ast_stream_topology_free(topology);
884 return NULL;
885 }
886
887 ast_stream_set_formats(stream, new_cap);
888 ao2_ref(new_cap, -1);
890 if (ast_stream_topology_append_stream(topology, stream) == -1) {
891 ast_stream_free(stream);
892 ast_stream_topology_free(topology);
893 return NULL;
894 }
895
896 snprintf(stream->name, MIN_STREAM_NAME_LEN, "%s-%d", ast_codec_media_type2str(stream->type), stream->position);
897 }
898
899 return topology;
900}
901
903 struct ast_stream_topology *topology, enum ast_media_type type)
904{
905 struct ast_format_cap *caps;
906 int i;
907
908 ast_assert(topology != NULL);
909
911 if (!caps) {
912 return NULL;
913 }
914
915 for (i = 0; i < AST_VECTOR_SIZE(&topology->streams); i++) {
916 struct ast_stream *stream;
917
918 stream = AST_VECTOR_GET(&topology->streams, i);
919 if (!stream->formats || stream->state == AST_STREAM_STATE_REMOVED) {
920 continue;
921 }
922 if (type == AST_MEDIA_TYPE_UNKNOWN || type == stream->type) {
924 }
925 }
926
927 return caps;
928}
929
931 struct ast_stream_topology *topology)
932{
934}
935
936const char *ast_stream_topology_to_str(const struct ast_stream_topology *topology,
937 struct ast_str **buf)
938{
939 int i;
940
941 if (!buf ||!*buf) {
942 return "";
943 }
944
945 if (!topology) {
946 ast_str_append(buf, 0, "(null topology)");
947 return ast_str_buffer(*buf);
948 }
949
950 ast_str_append(buf, 0, "%s", S_COR(topology->final, "final", ""));
951
952 for (i = 0; i < AST_VECTOR_SIZE(&topology->streams); i++) {
953 struct ast_stream *stream;
954
955 stream = AST_VECTOR_GET(&topology->streams, i);
956 ast_str_append(buf, 0, " <");
957 ast_stream_to_str(stream, buf);
958 ast_str_append(buf, 0, ">");
959 }
960
961 return ast_str_buffer(*buf);
962}
963
965 const struct ast_stream_topology *topology,
966 enum ast_media_type type)
967{
968 int i;
969
970 ast_assert(topology != NULL);
971
972 for (i = 0; i < AST_VECTOR_SIZE(&topology->streams); i++) {
973 struct ast_stream *stream;
974
975 stream = AST_VECTOR_GET(&topology->streams, i);
976 if (stream->type == type
977 && stream->state != AST_STREAM_STATE_REMOVED) {
978 return stream;
979 }
980 }
981
982 return NULL;
983}
984
986 struct ast_vector_int *types, struct ast_vector_int *v0, struct ast_vector_int *v1)
987{
988 int i;
989 int nths[AST_MEDIA_TYPE_END] = {0};
990 int size = ast_stream_topology_get_count(topology);
991
992 /*
993 * Clear out any old mappings and initialize the new ones
994 */
995 AST_VECTOR_FREE(v0);
996 AST_VECTOR_FREE(v1);
997
998 /*
999 * Both vectors are sized to the topology. The media types vector is always
1000 * guaranteed to be the size of the given topology or greater.
1001 */
1002 AST_VECTOR_INIT(v0, size);
1003 AST_VECTOR_INIT(v1, size);
1004
1005 for (i = 0; i < size; ++i) {
1006 struct ast_stream *stream = ast_stream_topology_get_stream(topology, i);
1008 int index = AST_VECTOR_GET_INDEX_NTH(types, ++nths[type],
1010
1011 if (index == -1) {
1012 /*
1013 * If a given type is not found for an index level then update the
1014 * media types vector with that type. This keeps the media types
1015 * vector always at the max topology size.
1016 */
1017 AST_VECTOR_APPEND(types, type);
1018 index = AST_VECTOR_SIZE(types) - 1;
1019 }
1020
1021 /*
1022 * The mapping is reflexive in the sense that if it maps in one direction
1023 * then the reverse direction maps back to the other's index.
1024 */
1025 AST_VECTOR_REPLACE(v0, i, index);
1026 AST_VECTOR_REPLACE(v1, index, i);
1027 }
1028}
1029
1031 struct ast_stream_topology *pending_topology, struct ast_stream_topology *configured_topology,
1032 struct ast_stream_codec_negotiation_prefs *prefs, struct ast_str**error_message)
1033{
1034 struct ast_stream_topology *joint_topology = ast_stream_topology_alloc();
1035 int res = 0;
1036 int i;
1037
1038 if (!pending_topology || !configured_topology || !joint_topology) {
1039 ao2_cleanup(joint_topology);
1040 return NULL;
1041 }
1042
1043 for (i = 0; i < AST_VECTOR_SIZE(&pending_topology->streams); i++) {
1044 struct ast_stream *pending_stream = AST_VECTOR_GET(&pending_topology->streams, i);
1045 struct ast_stream *configured_stream =
1046 ast_stream_topology_get_first_stream_by_type(configured_topology, pending_stream->type);
1047 struct ast_stream *joint_stream;
1048
1049 if (!configured_stream) {
1050 joint_stream = ast_stream_clone(pending_stream, NULL);
1051 if (!joint_stream) {
1052 ao2_cleanup(joint_topology);
1053 return NULL;
1054 }
1056 } else {
1057 joint_stream = ast_stream_create_resolved(pending_stream, configured_stream, prefs, error_message);
1058 if (!joint_stream) {
1059 ao2_cleanup(joint_topology);
1060 return NULL;
1061 } else if (ast_stream_get_format_count(joint_stream) == 0) {
1063 }
1064 }
1065
1066 res = ast_stream_topology_append_stream(joint_topology, joint_stream);
1067 if (res < 0) {
1068 ast_stream_free(joint_stream);
1069 ao2_cleanup(joint_topology);
1070 return NULL;
1071 }
1072 }
1073
1074 return joint_topology;
1075}
1076
1077int ast_stream_get_group(const struct ast_stream *stream)
1078{
1079 ast_assert(stream != NULL);
1080
1081 return stream->group;
1082}
1083
1084void ast_stream_set_group(struct ast_stream *stream, int group)
1085{
1086 ast_assert(stream != NULL);
1087
1088 stream->group = group;
1089}
const char * str
Definition: app_jack.c:147
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:404
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
enum cc_state state
Definition: ccss.c:393
static const char type[]
Definition: chan_ooh323.c:109
ast_media_type
Types of media.
Definition: codec.h:30
@ AST_MEDIA_TYPE_UNKNOWN
Definition: codec.h:31
@ AST_MEDIA_TYPE_END
Definition: codec.h:36
const char * ast_codec_media_type2str(enum ast_media_type type)
Conversion function to take a media type and turn it into a string.
Definition: codec.c:348
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
Media Format API.
Format Capabilities API.
#define AST_FORMAT_CAP_NAMES_LEN
Definition: format_cap.h:324
int ast_format_cap_empty(const struct ast_format_cap *cap)
Determine if a format cap has no formats in it.
Definition: format_cap.c:744
struct ast_format * ast_format_cap_get_format(const struct ast_format_cap *cap, int position)
Get the format at a specific index.
Definition: format_cap.c:400
unsigned int ast_format_cap_get_framing(const struct ast_format_cap *cap)
Get the global framing.
Definition: format_cap.c:438
int ast_format_cap_get_compatible(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2, struct ast_format_cap *result)
Find the compatible formats between two capabilities structures.
Definition: format_cap.c:628
const char * ast_format_cap_append_names(const struct ast_format_cap *cap, struct ast_str **buf)
Append the names of codecs of a set of formats to an ast_str buffer.
Definition: format_cap.c:739
void ast_format_cap_remove_by_type(struct ast_format_cap *cap, enum ast_media_type type)
Remove all formats matching a specific format type.
Definition: format_cap.c:523
@ AST_FORMAT_CAP_FLAG_DEFAULT
Definition: format_cap.h:38
int ast_format_cap_append_from_cap(struct ast_format_cap *dst, const struct ast_format_cap *src, enum ast_media_type type)
Append the formats of provided type in src to dst.
Definition: format_cap.c:269
int ast_format_cap_identical(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
Determine if two capabilities structures are identical.
Definition: format_cap.c:687
int ast_format_cap_has_type(const struct ast_format_cap *cap, enum ast_media_type type)
Find out if the capabilities structure has any formats of a specific type.
Definition: format_cap.c:613
#define ast_format_cap_append(cap, format, framing)
Add format capability to capabilities structure.
Definition: format_cap.h:99
void ast_format_cap_set_framing(struct ast_format_cap *cap, unsigned int framing)
Set the global framing.
Definition: format_cap.c:136
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition: format_cap.h:49
size_t ast_format_cap_count(const struct ast_format_cap *cap)
Get the number of formats present within the capabilities structure.
Definition: format_cap.c:395
static const char name[]
Definition: format_mp3.c:68
#define TRACE_ATLEAST(level)
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
#define SCOPE_ENTER(level,...)
#define ast_trace(level,...)
Configuration File Parser.
#define ast_variable_new(name, value, filename)
#define ast_variable_list_append(head, new_var)
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
Support for logging to various files, console and syslog Configuration in file logger....
#define NULL
Definition: resample.c:96
Pluggable RTP Architecture.
void ast_rtp_codecs_payloads_destroy(struct ast_rtp_codecs *codecs)
Destroy the contents of an RTP codecs structure (but not the structure itself)
Definition: rtp_engine.c:995
struct ast_stream_topology * ast_stream_topology_alloc(void)
Create a stream topology.
Definition: stream.c:650
struct ast_rtp_codecs * ast_stream_get_rtp_codecs(const struct ast_stream *stream)
Get rtp_codecs associated with the stream.
Definition: stream.c:507
void ast_stream_set_rtp_codecs(struct ast_stream *stream, struct ast_rtp_codecs *rtp_codecs)
Set rtp_codecs associated with the stream.
Definition: stream.c:514
struct ast_stream * ast_stream_topology_get_stream(const struct ast_stream_topology *topology, unsigned int stream_num)
Get a specific stream from the topology.
Definition: stream.c:788
const char * ast_stream_to_str(const struct ast_stream *stream, struct ast_str **buf)
Get a string representing the stream for debugging/display purposes.
Definition: stream.c:337
struct ast_stream * ast_stream_alloc(const char *name, enum ast_media_type type)
Create a new media stream representation.
Definition: stream.c:233
int ast_stream_topology_set_stream(struct ast_stream_topology *topology, unsigned int position, struct ast_stream *stream)
Set a specific position in a topology.
Definition: stream.c:796
const char * ast_stream_get_metadata(const struct ast_stream *stream, const char *m_key)
Get a stream metadata value.
Definition: stream.c:423
struct ast_format_cap * ast_stream_topology_get_formats_by_type(struct ast_stream_topology *topology, enum ast_media_type type)
Create a format capabilities structure containing all the formats from all the streams of a particula...
Definition: stream.c:902
const char * ast_stream_get_name(const struct ast_stream *stream)
Get the name of a stream.
Definition: stream.c:309
int ast_stream_set_metadata(struct ast_stream *stream, const char *m_key, const char *value)
Set a stream metadata value.
Definition: stream.c:460
int ast_stream_get_position(const struct ast_stream *stream)
Get the position of the stream in the topology.
Definition: stream.c:500
static void stream_topology_destroy(void *data)
Definition: stream.c:641
const char * ast_stream_state2str(enum ast_stream_state state)
Convert the state of a stream into a string.
Definition: stream.c:388
void ast_stream_set_state(struct ast_stream *stream, enum ast_stream_state state)
Set the state of a stream.
Definition: stream.c:380
int ast_stream_topology_append_stream(struct ast_stream_topology *topology, struct ast_stream *stream)
Append a stream to the topology.
Definition: stream.c:748
const char * ast_stream_topology_to_str(const struct ast_stream_topology *topology, struct ast_str **buf)
Get a string representing the topology for debugging/display purposes.
Definition: stream.c:936
struct ast_stream * ast_stream_clone(const struct ast_stream *stream, const char *name)
Create a deep clone of an existing stream.
Definition: stream.c:257
enum ast_stream_state ast_stream_str2state(const char *str)
Convert a string to a stream state.
Definition: stream.c:406
int ast_stream_codec_prefs_parse(const char *pref_string, struct ast_stream_codec_negotiation_prefs *prefs, struct ast_str **error_message)
Parses a string representing the codec prefs into a ast_stream_codec_negotiation_pref structure.
Definition: stream.c:181
int ast_stream_topology_get_count(const struct ast_stream_topology *topology)
Get the number of streams in a topology.
Definition: stream.c:765
int ast_stream_get_format_count(const struct ast_stream *stream)
Get the count of the current negotiated formats of a stream.
Definition: stream.c:358
enum ast_stream_state ast_stream_get_state(const struct ast_stream *stream)
Get the current state of a stream.
Definition: stream.c:373
int ast_stream_topology_del_stream(struct ast_stream_topology *topology, unsigned int position)
Delete a specified stream from the given topology.
Definition: stream.c:825
int ast_stream_get_group(const struct ast_stream *stream)
Get the stream group that a stream is part of.
Definition: stream.c:1077
enum ast_media_type ast_stream_get_type(const struct ast_stream *stream)
Get the media type of a stream.
Definition: stream.c:316
void ast_stream_topology_free(struct ast_stream_topology *topology)
Unreference and destroy a stream topology.
Definition: stream.c:743
void ast_stream_set_formats(struct ast_stream *stream, struct ast_format_cap *caps)
Set the current negotiated formats of a stream.
Definition: stream.c:365
const char * ast_stream_codec_negotiation_transcode_map[]
"transcode" state enum to string map
Definition: stream.c:75
int ast_stream_topology_get_active_count(const struct ast_stream_topology *topology)
Get the number of active (non-REMOVED) streams in a topology.
Definition: stream.c:772
void ast_stream_set_type(struct ast_stream *stream, enum ast_media_type type)
Change the media type of a stream.
Definition: stream.c:323
const char * ast_stream_codec_negotiation_params_map[]
Preference enum to string map.
Definition: stream.c:47
const char * ast_stream_codec_prefs_to_str(const struct ast_stream_codec_negotiation_prefs *prefs, struct ast_str **buf)
Return a string representing the codec preferences.
Definition: stream.c:132
const char * ast_stream_codec_negotiation_keep_map[]
"keep" enum to string map
Definition: stream.c:69
struct ast_stream_topology * ast_stream_topology_create_from_format_cap(struct ast_format_cap *cap)
A helper function that, given a format capabilities structure, creates a topology and separates the m...
Definition: stream.c:848
struct ast_variable * ast_stream_get_metadata_list(const struct ast_stream *stream)
Get all stream metadata keys.
Definition: stream.c:439
#define TOPOLOGY_INITIAL_STREAM_COUNT
Definition: stream.c:649
#define MIN_STREAM_NAME_LEN
Definition: stream.c:231
struct ast_format_cap * ast_stream_topology_get_formats(struct ast_stream_topology *topology)
Create a format capabilities structure representing the topology.
Definition: stream.c:930
const char * ast_stream_state_map[]
Stream state enum to string map.
Definition: stream.c:223
void ast_stream_free(struct ast_stream *stream)
Destroy a media stream representation.
Definition: stream.c:292
const char * ast_stream_codec_negotiation_prefer_map[]
"prefer" enum to string map
Definition: stream.c:55
#define set_pref_value(_name, _value, _prefs, _UC, _lc, _error_message)
Definition: stream.c:159
void ast_stream_set_group(struct ast_stream *stream, int group)
Set the stream group for a stream.
Definition: stream.c:1084
void ast_stream_topology_map(const struct ast_stream_topology *topology, struct ast_vector_int *types, struct ast_vector_int *v0, struct ast_vector_int *v1)
Map a given topology's streams to the given types.
Definition: stream.c:985
struct ast_stream * ast_stream_create_resolved(struct ast_stream *pending_stream, struct ast_stream *validation_stream, struct ast_stream_codec_negotiation_prefs *prefs, struct ast_str **error_message)
Create a resolved stream from 2 streams.
Definition: stream.c:525
const struct ast_format_cap * ast_stream_get_formats(const struct ast_stream *stream)
Get the current negotiated formats of a stream.
Definition: stream.c:330
int ast_stream_topology_equal(const struct ast_stream_topology *left, const struct ast_stream_topology *right)
Compare two stream topologies to see if they are equal.
Definition: stream.c:696
struct ast_stream_topology * ast_stream_topology_create_resolved(struct ast_stream_topology *pending_topology, struct ast_stream_topology *configured_topology, struct ast_stream_codec_negotiation_prefs *prefs, struct ast_str **error_message)
Create a resolved stream topology from 2 topologies.
Definition: stream.c:1030
struct ast_stream_topology * ast_stream_topology_clone(const struct ast_stream_topology *topology)
Create a deep clone of an existing stream topology.
Definition: stream.c:667
struct ast_stream * ast_stream_topology_get_first_stream_by_type(const struct ast_stream_topology *topology, enum ast_media_type type)
Gets the first active stream of a specific type from the topology.
Definition: stream.c:964
const char * ast_stream_codec_negotiation_operation_map[]
"operation" enum to string map
Definition: stream.c:61
Media Stream API.
#define AST_STREAM_MAX_CODEC_PREFS_LENGTH
Define for allocating buffer space for to_str() functions.
Definition: stream.h:307
@ CODEC_NEGOTIATION_OPERATION_ONLY_PREFERRED
Definition: stream.h:166
@ CODEC_NEGOTIATION_OPERATION_UNSPECIFIED
Definition: stream.h:160
@ CODEC_NEGOTIATION_OPERATION_ONLY_NONPREFERRED
Definition: stream.h:168
@ CODEC_NEGOTIATION_OPERATION_UNION
Definition: stream.h:164
@ CODEC_NEGOTIATION_OPERATION_INTERSECT
Definition: stream.h:162
ast_stream_state
States that a stream may be in.
Definition: stream.h:74
@ AST_STREAM_STATE_RECVONLY
Set when the stream is receiving media only.
Definition: stream.h:90
@ AST_STREAM_STATE_INACTIVE
Set when the stream is not sending OR receiving media.
Definition: stream.h:94
@ AST_STREAM_STATE_REMOVED
Set when the stream has been removed/declined.
Definition: stream.h:78
@ AST_STREAM_STATE_SENDRECV
Set when the stream is sending and receiving media.
Definition: stream.h:82
@ AST_STREAM_STATE_SENDONLY
Set when the stream is sending media only.
Definition: stream.h:86
@ CODEC_NEGOTIATION_KEEP_FIRST
Definition: stream.h:182
@ CODEC_NEGOTIATION_KEEP_UNSPECIFIED
Definition: stream.h:178
@ CODEC_NEGOTIATION_KEEP_ALL
Definition: stream.h:180
#define ast_stream_codec_operation_to_str(value)
Safely get the name of an "operation" parameter value.
Definition: stream.h:264
#define ast_stream_codec_transcode_to_str(value)
Safely get the name of a "transcode" parameter value.
Definition: stream.h:284
@ CODEC_NEGOTIATION_TRANSCODE_UNSPECIFIED
Definition: stream.h:192
@ CODEC_NEGOTIATION_TRANSCODE_PREVENT
Definition: stream.h:196
@ CODEC_NEGOTIATION_TRANSCODE_ALLOW
Definition: stream.h:194
@ CODEC_NEGOTIATION_PARAM_PREFER
Definition: stream.h:130
@ CODEC_NEGOTIATION_PARAM_TRANSCODE
Definition: stream.h:136
@ CODEC_NEGOTIATION_PARAM_KEEP
Definition: stream.h:134
@ CODEC_NEGOTIATION_PARAM_OPERATION
Definition: stream.h:132
@ CODEC_NEGOTIATION_PARAM_UNSPECIFIED
Definition: stream.h:128
@ CODEC_NEGOTIATION_PREFER_CONFIGURED
Definition: stream.h:150
@ CODEC_NEGOTIATION_PREFER_UNSPECIFIED
Definition: stream.h:146
@ CODEC_NEGOTIATION_PREFER_PENDING
Definition: stream.h:148
#define ast_stream_codec_param_to_str(value)
Safely get the name of a preference parameter.
Definition: stream.h:244
#define ast_stream_codec_prefer_to_str(value)
Safely get the name of a "prefer" parameter value.
Definition: stream.h:254
#define ast_stream_codec_keep_to_str(value)
Safely get the name of a "keep" parameter value.
Definition: stream.h:274
String manipulation functions.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:87
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
#define ast_str_tmp(init_len, __expr)
Provides a temporary ast_str and returns a copy of its buffer.
Definition: strings.h:1189
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
Definition of a media format.
Definition: format.c:43
Support for dynamic strings.
Definition: strings.h:623
enum ast_stream_codec_negotiation_prefs_transcode_values transcode
Definition: stream.h:300
enum ast_stream_codec_negotiation_prefs_operation_values operation
Definition: stream.h:296
enum ast_stream_codec_negotiation_prefs_keep_values keep
Definition: stream.h:298
enum ast_stream_codec_negotiation_prefs_prefer_values prefer
Definition: stream.h:294
Definition: stream.c:41
int value_start
Definition: stream.c:43
char name_value[0]
Definition: stream.c:44
size_t length
Definition: stream.c:42
struct ast_stream_topology::@402 streams
A vector of all the streams in this topology.
int group
The group that the stream is part of.
Definition: stream.c:110
struct ast_format_cap * formats
Current formats negotiated on the stream.
Definition: stream.c:95
unsigned int position
The position of the stream in the topology.
Definition: stream.c:90
struct ast_rtp_codecs * rtp_codecs
The rtp_codecs used by the stream.
Definition: stream.c:115
enum ast_media_type type
The type of media the stream is handling.
Definition: stream.c:85
struct ast_variable * metadata
Stream metadata vector.
Definition: stream.c:105
enum ast_stream_state state
The current state of the stream.
Definition: stream.c:100
char name[0]
Name for the stream within the context of the channel it is on.
Definition: stream.c:120
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
Integer vector definition.
Definition: vector.h:52
int value
Definition: syslog.c:37
#define ast_assert(a)
Definition: utils.h:739
#define ast_assert_return(a,...)
Definition: utils.h:740
#define MAX(a, b)
Definition: utils.h:233
Vector container support.
#define AST_VECTOR_REMOVE_ORDERED(vec, idx)
Remove an element from a vector by index while maintaining order.
Definition: vector.h:448
#define AST_VECTOR_REPLACE(vec, idx, elem)
Replace an element at a specific position in a vector, growing the vector if needed.
Definition: vector.h:284
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
#define AST_VECTOR_GET_INDEX_NTH(vec, nth, value, cmp)
Get the nth index from a vector that matches the given comparison.
Definition: vector.h:696
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
#define AST_VECTOR_ELEM_DEFAULT_CMP(elem, value)
Default comparator for AST_VECTOR_REMOVE_ELEM_UNORDERED()
Definition: vector.h:564
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
#define AST_VECTOR_CALLBACK_VOID(vec, callback,...)
Execute a callback on every element in a vector disregarding callback return.
Definition: vector.h:862
#define AST_VECTOR(name, type)
Define a vector structure.
Definition: vector.h:44
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680