Asterisk - The Open Source Telephony Project  21.4.1
pjsip_session_caps.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2020, Sangoma Technologies Corporation
5  *
6  * Kevin Harwell <kharwell@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 #include "asterisk.h"
20 
21 #include "asterisk/astobj2.h"
22 #include "asterisk/channel.h"
23 #include "asterisk/format.h"
24 #include "asterisk/format_cap.h"
25 #include "asterisk/logger.h"
26 #include "asterisk/sorcery.h"
27 #include "asterisk/stream.h"
28 #include "asterisk/res_pjsip.h"
29 #include "asterisk/res_pjsip_session.h"
30 #include "asterisk/res_pjsip_session_caps.h"
31 
32 static void log_caps(int level, const char *file, int line, const char *function,
33  const struct ast_sip_session *session, enum ast_media_type media_type,
34  const struct ast_format_cap *local, const struct ast_format_cap *remote,
35  const struct ast_format_cap *joint)
36 {
37  struct ast_str *s1;
38  struct ast_str *s2;
39  struct ast_str *s3;
40  int outgoing = session->call_direction == AST_SIP_SESSION_OUTGOING_CALL;
41  struct ast_flags pref =
42  outgoing
45 
46  if (level == __LOG_DEBUG && !DEBUG_ATLEAST(3)) {
47  return;
48  }
49 
50  s1 = local ? ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN) : NULL;
51  s2 = remote ? ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN) : NULL;
52  s3 = joint ? ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN) : NULL;
53 
54  ast_log(level, file, line, function, "'%s' Caps for %s %s call with pref '%s' - remote: %s local: %s joint: %s\n",
55  session->channel ? ast_channel_name(session->channel) :
57  outgoing? "outgoing" : "incoming",
58  ast_codec_media_type2str(media_type),
59  ast_sip_call_codec_pref_to_str(pref),
60  s2 ? ast_format_cap_get_names(remote, &s2) : "(NONE)",
61  s1 ? ast_format_cap_get_names(local, &s1) : "(NONE)",
62  s3 ? ast_format_cap_get_names(joint, &s3) : "(NONE)");
63 }
64 
65 struct ast_format_cap *ast_sip_create_joint_call_cap(const struct ast_format_cap *remote,
66  struct ast_format_cap *local, enum ast_media_type media_type,
67  struct ast_flags codec_pref)
68 {
72 
73  if (!joint || !local_filtered || !remote_filtered) {
74  ast_log(LOG_ERROR, "Failed to allocate %s call offer capabilities\n",
75  ast_codec_media_type2str(media_type));
76  ao2_cleanup(joint);
77  ao2_cleanup(local_filtered);
78  ao2_cleanup(remote_filtered);
79  return NULL;
80  }
81 
82  ast_format_cap_append_from_cap(local_filtered, local, media_type);
83 
84  /* Remote should always be a subset of local, as local is what defines the underlying
85  * permitted formats.
86  */
87  ast_format_cap_get_compatible(remote, local_filtered, remote_filtered);
88 
89  if (ast_sip_call_codec_pref_test(codec_pref, LOCAL)) {
90  if (ast_sip_call_codec_pref_test(codec_pref, INTERSECT)) {
91  ast_format_cap_get_compatible(local_filtered, remote_filtered, joint); /* Get common, prefer local */
92  } else {
93  ast_format_cap_append_from_cap(joint, local_filtered, media_type); /* Add local */
94  ast_format_cap_append_from_cap(joint, remote_filtered, media_type); /* Then remote */
95  }
96  } else {
97  if (ast_sip_call_codec_pref_test(codec_pref, INTERSECT)) {
98  joint = remote_filtered; /* Get common, prefer remote - as was done when filtering initially */
99  remote_filtered = NULL;
100  } else {
101  ast_format_cap_append_from_cap(joint, remote_filtered, media_type); /* Add remote */
102  ast_format_cap_append_from_cap(joint, local_filtered, media_type); /* Then local */
103  }
104  }
105 
106  ao2_ref(local_filtered, -1);
107  ao2_cleanup(remote_filtered);
108 
109  if (ast_format_cap_empty(joint)) {
110  return joint;
111  }
112 
113  if (ast_sip_call_codec_pref_test(codec_pref, FIRST)) {
114  /*
115  * Save the most preferred one. Session capabilities are per stream and
116  * a stream only carries a single media type, so no reason to worry with
117  * the type here (i.e different or multiple types)
118  */
119  struct ast_format *single = ast_format_cap_get_format(joint, 0);
120  /* Remove all formats */
121  ast_format_cap_remove_by_type(joint, AST_MEDIA_TYPE_UNKNOWN);
122  /* Put the most preferred one back */
123  ast_format_cap_append(joint, single, 0);
124  ao2_ref(single, -1);
125  }
126 
127  return joint;
128 }
129 
130 struct ast_stream *ast_sip_session_create_joint_call_stream(const struct ast_sip_session *session,
131  struct ast_stream *remote_stream)
132 {
133  struct ast_stream *joint_stream = ast_stream_clone(remote_stream, NULL);
134  const struct ast_format_cap *remote = ast_stream_get_formats(remote_stream);
135  enum ast_media_type media_type = ast_stream_get_type(remote_stream);
136 
137  struct ast_format_cap *joint = ast_sip_create_joint_call_cap(remote,
138  session->endpoint->media.codecs, media_type,
139  session->call_direction == AST_SIP_SESSION_OUTGOING_CALL
142 
143  ast_stream_set_formats(joint_stream, joint);
144  ao2_cleanup(joint);
145 
146  log_caps(LOG_DEBUG, session, media_type, session->endpoint->media.codecs, remote, joint);
147 
148  return joint_stream;
149 }
150 
151 struct ast_format_cap *ast_sip_session_create_joint_call_cap(
152  const struct ast_sip_session *session, enum ast_media_type media_type,
153  const struct ast_format_cap *remote)
154 {
155  struct ast_format_cap *joint = ast_sip_create_joint_call_cap(remote,
156  session->endpoint->media.codecs, media_type,
157  session->call_direction == AST_SIP_SESSION_OUTGOING_CALL
160 
161  log_caps(LOG_DEBUG, session, media_type, session->endpoint->media.codecs, remote, joint);
162 
163  return joint;
164 }
struct ast_sip_endpoint * endpoint
Asterisk main include file. File version handling, generic pbx functions.
struct ast_flags outgoing_call_offer_pref
Definition: res_pjsip.h:935
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 AST_FORMAT_CAP_NAMES_LEN
Definition: format_cap.h:324
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
struct ast_format_cap * codecs
Definition: res_pjsip.h:907
Definition of a media format.
Definition: format.c:43
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
A structure describing a SIP session.
Media Stream API.
Media Format API.
struct ast_sip_endpoint_media_configuration media
Definition: res_pjsip.h:980
General Asterisk PBX channel definitions.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2317
struct ast_channel * channel
#define ast_format_cap_append(cap, format, framing)
Add format capability to capabilities structure.
Definition: format_cap.h:99
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
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition: format_cap.h:49
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
Format Capabilities API.
Support for dynamic strings.
Definition: strings.h:623
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
const char * ast_format_cap_get_names(const struct ast_format_cap *cap, struct ast_str **buf)
Get the names of codecs of a set of formats.
Definition: format_cap.c:734
Support for logging to various files, console and syslog Configuration in file logger.conf.
Structure used to handle boolean flags.
Definition: utils.h:199
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_sip_session_call_direction call_direction
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:744
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
struct ast_flags incoming_call_offer_pref
Definition: res_pjsip.h:933
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
Sorcery Data Access Layer API.