Asterisk - The Open Source Telephony Project GIT-master-3dee037
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 SCOPE_ENTER(4, "Topology: %p: %s\n", topology, ast_str_tmp(128, ast_stream_topology_to_str(topology, &STR_TMP)));
645
647 AST_VECTOR_FREE(&topology->streams);
648 SCOPE_EXIT_RTN("Destroyed: %p\n", topology);
649}
650
651#define TOPOLOGY_INITIAL_STREAM_COUNT 2
653{
654 struct ast_stream_topology *topology;
655 SCOPE_ENTER(4, "Topology Create\n");
656
658 if (!topology) {
659 SCOPE_EXIT_RTN_VALUE(NULL, "Allocation failed\n");
660 }
661
663 ao2_ref(topology, -1);
664 SCOPE_EXIT_RTN_VALUE(NULL, "Vector init failed\n");
665 }
666
667 SCOPE_EXIT_RTN_VALUE(topology, "Created: %p\n", topology);
668}
669
671 const struct ast_stream_topology *topology)
672{
673 struct ast_stream_topology *new_topology;
674 int i;
675
676 ast_assert(topology != NULL);
677
678 new_topology = ast_stream_topology_alloc();
679 if (!new_topology) {
680 return NULL;
681 }
682
683 for (i = 0; i < AST_VECTOR_SIZE(&topology->streams); i++) {
684 struct ast_stream *existing = AST_VECTOR_GET(&topology->streams, i);
685 struct ast_stream *stream = ast_stream_clone(existing, NULL);
686
687 if (!stream || AST_VECTOR_APPEND(&new_topology->streams, stream)) {
688 ast_stream_free(stream);
689 ast_stream_topology_free(new_topology);
690 return NULL;
691 }
692
694 }
695
696 return new_topology;
697}
698
700 const struct ast_stream_topology *right)
701{
702 int index;
703
704 ast_assert(left != NULL);
705 ast_assert(right != NULL);
706
708 return 0;
709 }
710
711 for (index = 0; index < ast_stream_topology_get_count(left); ++index) {
712 const struct ast_stream *left_stream = ast_stream_topology_get_stream(left, index);
713 const struct ast_stream *right_stream = ast_stream_topology_get_stream(right, index);
714
715 if (ast_stream_get_type(left_stream) != ast_stream_get_type(right_stream)) {
716 return 0;
717 }
718
719 if (ast_stream_get_state(left_stream) != ast_stream_get_state(right_stream)) {
720 return 0;
721 }
722
723 if (!ast_stream_get_formats(left_stream) && ast_stream_get_formats(right_stream) &&
725 /* A NULL format capabilities and an empty format capabilities are the same, as they have
726 * no formats inside. If one does though... they are not equal.
727 */
728 return 0;
729 } else if (!ast_stream_get_formats(right_stream) && ast_stream_get_formats(left_stream) &&
731 return 0;
732 } else if (ast_stream_get_formats(left_stream) && ast_stream_get_formats(right_stream) &&
734 /* But if both are actually present we need to do an actual identical check. */
735 return 0;
736 }
737
738 if (strcmp(ast_stream_get_name(left_stream), ast_stream_get_name(right_stream))) {
739 return 0;
740 }
741 }
742
743 return 1;
744}
745
747{
748 ao2_cleanup(topology);
749}
750
752{
753 ast_assert(topology && stream);
754
755 if (AST_VECTOR_APPEND(&topology->streams, stream)) {
756 return -1;
757 }
758
759 stream->position = AST_VECTOR_SIZE(&topology->streams) - 1;
760
761 if (ast_strlen_zero(stream->name)) {
762 snprintf(stream->name, MIN_STREAM_NAME_LEN, "%s-%d", ast_codec_media_type2str(stream->type), stream->position);
763 }
764
765 return AST_VECTOR_SIZE(&topology->streams) - 1;
766}
767
769{
770 ast_assert(topology != NULL);
771
772 return AST_VECTOR_SIZE(&topology->streams);
773}
774
776{
777 int i;
778 int count = 0;
779 ast_assert(topology != NULL);
780
781 for (i = 0; i < AST_VECTOR_SIZE(&topology->streams); i++) {
782 struct ast_stream *stream = AST_VECTOR_GET(&topology->streams, i);
783 if (stream->state != AST_STREAM_STATE_REMOVED) {
784 count++;
785 }
786 }
787
788 return count;
789}
790
792 const struct ast_stream_topology *topology, unsigned int stream_num)
793{
794 ast_assert(topology != NULL);
795
796 return AST_VECTOR_GET(&topology->streams, stream_num);
797}
798
800 unsigned int position, struct ast_stream *stream)
801{
802 struct ast_stream *existing_stream;
803
804 ast_assert(topology && stream);
805
806 if (position > AST_VECTOR_SIZE(&topology->streams)) {
807 return -1;
808 }
809
810 if (position < AST_VECTOR_SIZE(&topology->streams)) {
811 existing_stream = AST_VECTOR_GET(&topology->streams, position);
812 ast_stream_free(existing_stream);
813 }
814
815 stream->position = position;
816
817 if (position == AST_VECTOR_SIZE(&topology->streams)) {
818 return AST_VECTOR_APPEND(&topology->streams, stream);
819 }
820
821 if (ast_strlen_zero(stream->name)) {
822 snprintf(stream->name, MIN_STREAM_NAME_LEN, "%s-%d", ast_codec_media_type2str(stream->type), stream->position);
823 }
824
825 return AST_VECTOR_REPLACE(&topology->streams, position, stream);
826}
827
829 unsigned int position)
830{
831 struct ast_stream *stream;
832
833 ast_assert(topology != NULL);
834
835 if (AST_VECTOR_SIZE(&topology->streams) <= position) {
836 return -1;
837 }
838
839 stream = AST_VECTOR_REMOVE_ORDERED(&topology->streams, position);
840 ast_stream_free(stream);
841
842 /* Fix up higher stream position indices */
843 for (; position < AST_VECTOR_SIZE(&topology->streams); ++position) {
844 stream = AST_VECTOR_GET(&topology->streams, position);
845 stream->position = position;
846 }
847
848 return 0;
849}
850
852 struct ast_format_cap *cap)
853{
854 struct ast_stream_topology *topology;
855 enum ast_media_type type;
856
857 topology = ast_stream_topology_alloc();
858 if (!topology || !cap || !ast_format_cap_count(cap)) {
859 return topology;
860 }
861
863 struct ast_format_cap *new_cap;
864 struct ast_stream *stream;
865
866 if (!ast_format_cap_has_type(cap, type)) {
867 continue;
868 }
869
871 if (!new_cap) {
872 ast_stream_topology_free(topology);
873 return NULL;
874 }
875
877 if (ast_format_cap_append_from_cap(new_cap, cap, type)) {
878 ao2_cleanup(new_cap);
879 ast_stream_topology_free(topology);
880 return NULL;
881 }
882
883 stream = ast_stream_alloc(NULL, type);
884 if (!stream) {
885 ao2_cleanup(new_cap);
886 ast_stream_topology_free(topology);
887 return NULL;
888 }
889
890 ast_stream_set_formats(stream, new_cap);
891 ao2_ref(new_cap, -1);
893 if (ast_stream_topology_append_stream(topology, stream) == -1) {
894 ast_stream_free(stream);
895 ast_stream_topology_free(topology);
896 return NULL;
897 }
898
899 snprintf(stream->name, MIN_STREAM_NAME_LEN, "%s-%d", ast_codec_media_type2str(stream->type), stream->position);
900 }
901
902 return topology;
903}
904
906 struct ast_stream_topology *topology, enum ast_media_type type)
907{
908 struct ast_format_cap *caps;
909 int i;
910
911 ast_assert(topology != NULL);
912
914 if (!caps) {
915 return NULL;
916 }
917
918 for (i = 0; i < AST_VECTOR_SIZE(&topology->streams); i++) {
919 struct ast_stream *stream;
920
921 stream = AST_VECTOR_GET(&topology->streams, i);
922 if (!stream->formats || stream->state == AST_STREAM_STATE_REMOVED) {
923 continue;
924 }
925 if (type == AST_MEDIA_TYPE_UNKNOWN || type == stream->type) {
927 }
928 }
929
930 return caps;
931}
932
934 struct ast_stream_topology *topology)
935{
937}
938
939const char *ast_stream_topology_to_str(const struct ast_stream_topology *topology,
940 struct ast_str **buf)
941{
942 int i;
943
944 if (!buf ||!*buf) {
945 return "";
946 }
947
948 if (!topology) {
949 ast_str_append(buf, 0, "(null topology)");
950 return ast_str_buffer(*buf);
951 }
952
953 ast_str_append(buf, 0, "%s", S_COR(topology->final, "final", ""));
954
955 for (i = 0; i < AST_VECTOR_SIZE(&topology->streams); i++) {
956 struct ast_stream *stream;
957
958 stream = AST_VECTOR_GET(&topology->streams, i);
959 ast_str_append(buf, 0, " <");
960 ast_stream_to_str(stream, buf);
961 ast_str_append(buf, 0, ">");
962 }
963
964 return ast_str_buffer(*buf);
965}
966
968 const struct ast_stream_topology *topology,
969 enum ast_media_type type)
970{
971 int i;
972
973 ast_assert(topology != NULL);
974
975 for (i = 0; i < AST_VECTOR_SIZE(&topology->streams); i++) {
976 struct ast_stream *stream;
977
978 stream = AST_VECTOR_GET(&topology->streams, i);
979 if (stream->type == type
980 && stream->state != AST_STREAM_STATE_REMOVED) {
981 return stream;
982 }
983 }
984
985 return NULL;
986}
987
989 struct ast_vector_int *types, struct ast_vector_int *v0, struct ast_vector_int *v1)
990{
991 int i;
992 int nths[AST_MEDIA_TYPE_END] = {0};
993 int size = ast_stream_topology_get_count(topology);
994
995 /*
996 * Clear out any old mappings and initialize the new ones
997 */
998 AST_VECTOR_FREE(v0);
999 AST_VECTOR_FREE(v1);
1000
1001 /*
1002 * Both vectors are sized to the topology. The media types vector is always
1003 * guaranteed to be the size of the given topology or greater.
1004 */
1005 AST_VECTOR_INIT(v0, size);
1006 AST_VECTOR_INIT(v1, size);
1007
1008 for (i = 0; i < size; ++i) {
1009 struct ast_stream *stream = ast_stream_topology_get_stream(topology, i);
1011 int index = AST_VECTOR_GET_INDEX_NTH(types, ++nths[type],
1013
1014 if (index == -1) {
1015 /*
1016 * If a given type is not found for an index level then update the
1017 * media types vector with that type. This keeps the media types
1018 * vector always at the max topology size.
1019 */
1020 AST_VECTOR_APPEND(types, type);
1021 index = AST_VECTOR_SIZE(types) - 1;
1022 }
1023
1024 /*
1025 * The mapping is reflexive in the sense that if it maps in one direction
1026 * then the reverse direction maps back to the other's index.
1027 */
1028 AST_VECTOR_REPLACE(v0, i, index);
1029 AST_VECTOR_REPLACE(v1, index, i);
1030 }
1031}
1032
1034 struct ast_stream_topology *pending_topology, struct ast_stream_topology *configured_topology,
1035 struct ast_stream_codec_negotiation_prefs *prefs, struct ast_str**error_message)
1036{
1037 struct ast_stream_topology *joint_topology = ast_stream_topology_alloc();
1038 int res = 0;
1039 int i;
1040
1041 if (!pending_topology || !configured_topology || !joint_topology) {
1042 ao2_cleanup(joint_topology);
1043 return NULL;
1044 }
1045
1046 for (i = 0; i < AST_VECTOR_SIZE(&pending_topology->streams); i++) {
1047 struct ast_stream *pending_stream = AST_VECTOR_GET(&pending_topology->streams, i);
1048 struct ast_stream *configured_stream =
1049 ast_stream_topology_get_first_stream_by_type(configured_topology, pending_stream->type);
1050 struct ast_stream *joint_stream;
1051
1052 if (!configured_stream) {
1053 joint_stream = ast_stream_clone(pending_stream, NULL);
1054 if (!joint_stream) {
1055 ao2_cleanup(joint_topology);
1056 return NULL;
1057 }
1059 } else {
1060 joint_stream = ast_stream_create_resolved(pending_stream, configured_stream, prefs, error_message);
1061 if (!joint_stream) {
1062 ao2_cleanup(joint_topology);
1063 return NULL;
1064 } else if (ast_stream_get_format_count(joint_stream) == 0) {
1066 }
1067 }
1068
1069 res = ast_stream_topology_append_stream(joint_topology, joint_stream);
1070 if (res < 0) {
1071 ast_stream_free(joint_stream);
1072 ao2_cleanup(joint_topology);
1073 return NULL;
1074 }
1075 }
1076
1077 return joint_topology;
1078}
1079
1080int ast_stream_get_group(const struct ast_stream *stream)
1081{
1082 ast_assert(stream != NULL);
1083
1084 return stream->group;
1085}
1086
1087void ast_stream_set_group(struct ast_stream *stream, int group)
1088{
1089 ast_assert(stream != NULL);
1090
1091 stream->group = group;
1092}
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 SCOPE_EXIT_RTN(...)
#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:996
struct ast_stream_topology * ast_stream_topology_alloc(void)
Create a stream topology.
Definition: stream.c:652
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:791
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:799
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:905
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:751
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:939
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:768
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:828
int ast_stream_get_group(const struct ast_stream *stream)
Get the stream group that a stream is part of.
Definition: stream.c:1080
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:746
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:775
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:851
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:651
#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:933
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:1087
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:988
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:699
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:1033
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:670
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:967
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