Asterisk - The Open Source Telephony Project  GIT-master-b91fb3c
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 
48  [CODEC_NEGOTIATION_PARAM_UNSPECIFIED] = "unspecified",
49  [CODEC_NEGOTIATION_PARAM_PREFER] = "prefer",
50  [CODEC_NEGOTIATION_PARAM_OPERATION] = "operation",
52  [CODEC_NEGOTIATION_PARAM_TRANSCODE] = "transcode",
53 };
54 
56  [CODEC_NEGOTIATION_PREFER_UNSPECIFIED] = "unspecified",
58  [CODEC_NEGOTIATION_PREFER_CONFIGURED] = "configured",
59 };
60 
65  [CODEC_NEGOTIATION_OPERATION_ONLY_PREFERRED] = "only_preferred",
66  [CODEC_NEGOTIATION_OPERATION_ONLY_NONPREFERRED] = "only_nonpreferred",
67 };
68 
70  [CODEC_NEGOTIATION_KEEP_UNSPECIFIED] = "unspecified",
72  [CODEC_NEGOTIATION_KEEP_FIRST] = "first",
73 };
74 
79 };
80 
81 struct 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  */
127  AST_VECTOR(, struct ast_stream *) streams;
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 
181 int 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 
223 const 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 
257 struct 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 
292 void 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 
309 const 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 
330 const 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 
337 const 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]);
353  ast_format_cap_append_names(stream->formats, buf);
354 
355  return ast_str_buffer(*buf);
356 }
357 
358 int ast_stream_get_format_count(const struct ast_stream *stream)
359 {
360  ast_assert(stream != NULL);
361 
362  return stream->formats ? ast_format_cap_count(stream->formats) : 0;
363 }
364 
365 void 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 
423 const 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) {
450  ast_variables_destroy(vout);
451  return NULL;
452  }
453 
454  ast_variable_list_append(&vout, vt);
455  }
456 
457  return vout;
458 }
459 
460 int 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 
495  ast_variable_list_append(&stream->metadata, v);
496 
497  return 0;
498 }
499 
500 int 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 
514 void 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 
525 struct 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  }
556  ast_format_cap_set_framing(joint_caps, ast_format_cap_get_framing(pending_stream->formats));
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: ");
631  ast_stream_codec_prefs_to_str(prefs, &buf);
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 
641 static void stream_topology_destroy(void *data)
642 {
643  struct ast_stream_topology *topology = data;
644 
645  AST_VECTOR_CALLBACK_VOID(&topology->streams, ast_stream_free);
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 
659  if (AST_VECTOR_INIT(&topology->streams, TOPOLOGY_INITIAL_STREAM_COUNT)) {
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 
690  ast_stream_set_group(stream, ast_stream_get_group(existing));
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 
859  for (type = AST_MEDIA_TYPE_UNKNOWN + 1; type < AST_MEDIA_TYPE_END; type++) {
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 
936 const 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 
985 void ast_stream_topology_map(const struct ast_stream_topology *topology,
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);
1007  enum ast_media_type type = ast_stream_get_type(stream);
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 
1077 int ast_stream_get_group(const struct ast_stream *stream)
1078 {
1079  ast_assert(stream != NULL);
1080 
1081  return stream->group;
1082 }
1083 
1084 void ast_stream_set_group(struct ast_stream *stream, int group)
1085 {
1086  ast_assert(stream != NULL);
1087 
1088  stream->group = group;
1089 }
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
struct ast_variable * next
struct ast_stream_topology * ast_stream_topology_alloc(void)
Create a stream topology.
Definition: stream.c:650
static const char type[]
Definition: chan_ooh323.c:109
enum sip_cc_notify_state state
Definition: chan_sip.c:957
struct ast_rtp_codecs * rtp_codecs
The rtp_codecs used by the stream.
Definition: stream.c:115
const char * ast_stream_codec_negotiation_prefer_map[]
"prefer" enum to string map
Definition: stream.c:55
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
#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:698
Asterisk main include file. File version handling, generic pbx functions.
unsigned int ast_format_cap_get_framing(const struct ast_format_cap *cap)
Get the global framing.
Definition: format_cap.c:438
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
enum ast_stream_state ast_stream_str2state(const char *str)
Convert a string to a stream state.
Definition: stream.c:406
String manipulation functions.
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1263
media_type
Media types generate different "dummy answers" for not accepting the offer of a media stream...
Definition: sip.h:489
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 char * ast_stream_codec_negotiation_keep_map[]
"keep" enum to string map
Definition: stream.c:69
void ast_stream_topology_free(struct ast_stream_topology *topology)
Unreference and destroy a stream topology.
Definition: stream.c:743
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define AST_VECTOR_ELEM_DEFAULT_CMP(elem, value)
Default comparator for AST_VECTOR_REMOVE_ELEM_UNORDERED()
Definition: vector.h:564
#define AST_STREAM_MAX_CODEC_PREFS_LENGTH
Define for allocating buffer space for to_str() functions.
Definition: stream.h:307
#define AST_FORMAT_CAP_NAMES_LEN
Definition: format_cap.h:326
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
const char * ast_stream_state_map[]
Stream state enum to string map.
Definition: stream.c:223
enum ast_stream_codec_negotiation_prefs_operation_values operation
Definition: stream.h:296
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:347
struct ast_format_cap * formats
Current formats negotiated on the stream.
Definition: stream.c:95
Structure for variables, used for configurations and for channel variables.
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
Set when the stream has been removed/declined.
Definition: stream.h:78
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
int value_start
Definition: stream.c:43
#define ast_trace(level,...)
Definition: logger.h:876
static void stream_topology_destroy(void *data)
Definition: stream.c:641
Definition of a media format.
Definition: format.c:43
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:1091
enum ast_stream_codec_negotiation_prefs_prefer_values prefer
Definition: stream.h:294
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
#define MIN_STREAM_NAME_LEN
Definition: stream.c:231
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:406
#define ast_assert(a)
Definition: utils.h:650
Set when the stream is not sending OR receiving media.
Definition: stream.h:94
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&#39;s streams to the given types.
Definition: stream.c:985
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
const char * str
Definition: app_jack.c:147
ast_stream_state
States that a stream may be in.
Definition: stream.h:74
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
void ast_format_cap_set_framing(struct ast_format_cap *cap, unsigned int framing)
Set the global framing.
Definition: format_cap.c:136
#define NULL
Definition: resample.c:96
int value
Definition: syslog.c:37
const char * ast_stream_codec_negotiation_params_map[]
Preference enum to string map.
Definition: stream.c:47
Definition: stream.c:41
Media Stream API.
enum ast_stream_state state
The current state of the stream.
Definition: stream.c:100
Media Format API.
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
void ast_stream_free(struct ast_stream *stream)
Destroy a media stream representation.
Definition: stream.c:292
enum ast_stream_state ast_stream_get_state(const struct ast_stream *stream)
Get the current state of a stream.
Definition: stream.c:373
char name[0]
Name for the stream within the context of the channel it is on.
Definition: stream.c:120
struct ast_stream * ast_stream_alloc(const char *name, enum ast_media_type type)
Create a new media stream representation.
Definition: stream.c:233
#define ao2_bump(obj)
Definition: astobj2.h:491
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
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:1065
Configuration File Parser.
int group
The group that the stream is part of.
Definition: stream.c:110
#define ast_str_tmp(init_len, __expr)
Definition: strings.h:1136
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
#define ast_stream_codec_operation_to_str(value)
Safely get the name of an "operation" parameter value.
Definition: stream.h:264
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
void ast_stream_set_group(struct ast_stream *stream, int group)
Set the stream group for a stream.
Definition: stream.c:1084
#define MAX(a, b)
Definition: utils.h:228
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
enum ast_media_type type
The type of media the stream is handling.
Definition: stream.c:85
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
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
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#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:85
const char * ast_stream_codec_negotiation_operation_map[]
"operation" enum to string map
Definition: stream.c:61
#define AST_VECTOR_REMOVE_ORDERED(vec, idx)
Remove an element from a vector by index while maintaining order.
Definition: vector.h:448
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
#define ast_format_cap_append(cap, format, framing)
Definition: format_cap.h:103
#define AST_VECTOR(name, type)
Define a vector structure.
Definition: vector.h:44
#define ast_variable_new(name, value, filename)
#define TOPOLOGY_INITIAL_STREAM_COUNT
Definition: stream.c:649
#define ast_format_cap_alloc(flags)
Definition: format_cap.h:52
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
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
enum ast_stream_codec_negotiation_prefs_keep_values keep
Definition: stream.h:298
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:525
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
Format Capabilities API.
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
const char * ast_stream_codec_negotiation_transcode_map[]
"transcode" state enum to string map
Definition: stream.c:75
Set when the stream is sending and receiving media.
Definition: stream.h:82
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
int ast_stream_topology_get_count(const struct ast_stream_topology *topology)
Get the number of streams in a topology.
Definition: stream.c:765
struct ast_variable * ast_stream_get_metadata_list(const struct ast_stream *stream)
Get all stream metadata keys.
Definition: stream.c:439
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
#define ast_stream_codec_keep_to_str(value)
Safely get the name of a "keep" parameter value.
Definition: stream.h:274
#define ast_strlen_zero(a)
Definition: muted.c:73
#define ast_stream_codec_transcode_to_str(value)
Safely get the name of a "transcode" parameter value.
Definition: stream.h:284
Set when the stream is sending media only.
Definition: stream.h:86
static const char name[]
Definition: cdr_mysql.c:74
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
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_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:689
#define SCOPE_ENTER(level,...)
Definition: logger.h:885
Vector container support.
#define TRACE_ATLEAST(level)
Definition: logger.h:624
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
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:974
Support for logging to various files, console and syslog Configuration in file logger.conf.
enum ast_media_type ast_stream_get_type(const struct ast_stream *stream)
Get the media type of a stream.
Definition: stream.c:316
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
Definition: logger.h:904
int ast_stream_get_position(const struct ast_stream *stream)
Get the position of the stream in the topology.
Definition: stream.c:500
const char * ast_stream_state2str(enum ast_stream_state state)
Convert the state of a stream into a string.
Definition: stream.c:388
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
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
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
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
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
char name_value[0]
Definition: stream.c:44
enum ast_stream_codec_negotiation_prefs_transcode_values transcode
Definition: stream.h:300
#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_assert_return(a,...)
Definition: utils.h:651
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
#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_param_to_str(value)
Safely get the name of a preference parameter.
Definition: stream.h:244
const char * ast_stream_get_name(const struct ast_stream *stream)
Get the name of a stream.
Definition: stream.c:309
ast_media_type
Types of media.
Definition: codec.h:30
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:746
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
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
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
Pluggable RTP Architecture.
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
void ast_stream_set_state(struct ast_stream *stream, enum ast_stream_state state)
Set the state of a stream.
Definition: stream.c:380
#define set_pref_value(_name, _value, _prefs, _UC, _lc, _error_message)
Definition: stream.c:159
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
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:630
Set when the stream is receiving media only.
Definition: stream.h:90
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611
struct ast_variable * metadata
Stream metadata vector.
Definition: stream.c:105
unsigned int position
The position of the stream in the topology.
Definition: stream.c:90
#define ast_variable_list_append(head, new_var)
const char * ast_stream_get_metadata(const struct ast_stream *stream, const char *m_key)
Get a stream metadata value.
Definition: stream.c:423
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:615
#define AST_VECTOR_CALLBACK_VOID(vec, callback,...)
Execute a callback on every element in a vector disregarding callback return.
Definition: vector.h:865
size_t length
Definition: stream.c:42
int ast_stream_get_group(const struct ast_stream *stream)
Get the stream group that a stream is part of.
Definition: stream.c:1077
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620
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:741