blob: 1f885c5f3e7dd536cdfdd2b0fa4257600dcc8c1a [file] [log] [blame]
Neels Hofmeyrc4628a32018-12-07 14:47:34 +01001/*
Vadim Yanitskiy999a5932023-05-18 17:22:26 +07002 * (C) 2019 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
Neels Hofmeyrc4628a32018-12-07 14:47:34 +01003 * All Rights Reserved
4 *
5 * SPDX-License-Identifier: AGPL-3.0+
6 *
7 * Author: Neels Hofmeyr
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Affero General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Affero General Public License for more details.
18 *
19 * You should have received a copy of the GNU Affero General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#include <osmocom/core/fsm.h>
24
25#include <osmocom/mgcp_client/mgcp_client_endpoint_fsm.h>
26
27#include <osmocom/msc/debug.h>
28#include <osmocom/msc/transaction.h>
29#include <osmocom/msc/call_leg.h>
30#include <osmocom/msc/rtp_stream.h>
Neels Hofmeyr62bfa372022-10-31 18:51:07 +010031#include <osmocom/msc/codec_mapping.h>
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010032
33#define LOG_RTPS(rtps, level, fmt, args...) \
34 LOGPFSML(rtps->fi, level, fmt, ##args)
35
36enum rtp_stream_event {
37 RTP_STREAM_EV_CRCX_OK,
38 RTP_STREAM_EV_CRCX_FAIL,
39 RTP_STREAM_EV_MDCX_OK,
40 RTP_STREAM_EV_MDCX_FAIL,
41};
42
43enum rtp_stream_state {
44 RTP_STREAM_ST_UNINITIALIZED,
45 RTP_STREAM_ST_ESTABLISHING,
46 RTP_STREAM_ST_ESTABLISHED,
47 RTP_STREAM_ST_DISCARDING,
48};
49
50static struct osmo_fsm rtp_stream_fsm;
51
52static struct osmo_tdef_state_timeout rtp_stream_fsm_timeouts[32] = {
53 [RTP_STREAM_ST_ESTABLISHING] = { .T = -2 },
54};
55
56#define rtp_stream_state_chg(rtps, state) \
57 osmo_tdef_fsm_inst_state_chg((rtps)->fi, state, rtp_stream_fsm_timeouts, g_mgw_tdefs, 5)
58
59static __attribute__((constructor)) void rtp_stream_init()
60{
61 OSMO_ASSERT(osmo_fsm_register(&rtp_stream_fsm) == 0);
62}
63
64void rtp_stream_update_id(struct rtp_stream *rtps)
65{
66 char buf[256];
67 char *p;
68 struct osmo_strbuf sb = { .buf = buf, .len = sizeof(buf) };
69 OSMO_STRBUF_PRINTF(sb, "%s", rtps->fi->proc.parent->id);
70 if (rtps->for_trans)
71 OSMO_STRBUF_PRINTF(sb, ":trans-%u", rtps->for_trans->transaction_id);
72 OSMO_STRBUF_PRINTF(sb, ":call-%u", rtps->call_id);
73 OSMO_STRBUF_PRINTF(sb, ":%s", rtp_direction_name(rtps->dir));
74 if (!osmo_mgcpc_ep_ci_id(rtps->ci)) {
75 OSMO_STRBUF_PRINTF(sb, ":no-CI");
76 } else {
77 OSMO_STRBUF_PRINTF(sb, ":CI-%s", osmo_mgcpc_ep_ci_id(rtps->ci));
Neels Hofmeyr84ce2062019-10-05 05:15:25 +020078 if (!osmo_sockaddr_str_is_nonzero(&rtps->remote))
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010079 OSMO_STRBUF_PRINTF(sb, ":no-remote-port");
80 else if (!rtps->remote_sent_to_mgw)
81 OSMO_STRBUF_PRINTF(sb, ":remote-port-not-sent");
Neels Hofmeyr62bfa372022-10-31 18:51:07 +010082 if (!rtps->codecs_known)
83 OSMO_STRBUF_PRINTF(sb, ":no-codecs");
84 else if (!rtps->codecs_sent_to_mgw)
85 OSMO_STRBUF_PRINTF(sb, ":codecs-not-sent");
Andreas Eversberg58fe2e02023-06-21 12:37:18 +020086 if (!rtps->codecs_sent_to_mgw)
87 OSMO_STRBUF_PRINTF(sb, ":mode-not-sent");
Pau Espin Pedrola3cdab42019-05-09 17:54:08 +020088 if (rtps->use_osmux) {
89 if (rtps->remote_osmux_cid < 0)
90 OSMO_STRBUF_PRINTF(sb, ":no-remote-osmux-cid");
91 else if (!rtps->remote_osmux_cid_sent_to_mgw)
92 OSMO_STRBUF_PRINTF(sb, ":remote-osmux-cid-not-sent");
93 }
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010094 }
Neels Hofmeyr84ce2062019-10-05 05:15:25 +020095 if (osmo_sockaddr_str_is_nonzero(&rtps->local))
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010096 OSMO_STRBUF_PRINTF(sb, ":local-%s-%u", rtps->local.ip, rtps->local.port);
Neels Hofmeyr84ce2062019-10-05 05:15:25 +020097 if (osmo_sockaddr_str_is_nonzero(&rtps->remote))
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010098 OSMO_STRBUF_PRINTF(sb, ":remote-%s-%u", rtps->remote.ip, rtps->remote.port);
Pau Espin Pedrola3cdab42019-05-09 17:54:08 +020099 if (rtps->use_osmux)
100 OSMO_STRBUF_PRINTF(sb, ":osmux-%d-%d", rtps->local_osmux_cid, rtps->remote_osmux_cid);
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100101
102 /* Replace any dots in the IP address, dots not allowed as FSM instance name */
103 for (p = buf; *p; p++)
104 if (*p == '.')
105 *p = '-';
106
107 osmo_fsm_inst_update_id_f(rtps->fi, "%s", buf);
108}
109
110/* Allocate RTP stream under a call leg. This is one RTP connection from some remote entity with address and port to a
111 * local RTP address and port. call_id is stored for sending in MGCP transactions and as logging context. for_trans is
112 * optional, merely stored for reference by callers, and appears as log context if not NULL. */
Andreas Eversbergbcb4d6b2023-07-05 15:03:19 +0200113struct rtp_stream *rtp_stream_alloc(struct osmo_fsm_inst *parent_fi, uint32_t event_gone, uint32_t event_avail,
114 uint32_t event_estab, enum rtp_direction dir, uint32_t call_id,
115 struct gsm_trans *for_trans)
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100116{
117 struct osmo_fsm_inst *fi;
118 struct rtp_stream *rtps;
119
Andreas Eversbergbcb4d6b2023-07-05 15:03:19 +0200120 fi = osmo_fsm_inst_alloc_child(&rtp_stream_fsm, parent_fi, event_gone);
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100121 OSMO_ASSERT(fi);
122
123 rtps = talloc(fi, struct rtp_stream);
124 OSMO_ASSERT(rtps);
125 fi->priv = rtps;
126 *rtps = (struct rtp_stream){
127 .fi = fi,
Andreas Eversbergbcb4d6b2023-07-05 15:03:19 +0200128 .event_avail = event_avail,
129 .event_estab = event_estab,
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100130 .call_id = call_id,
131 .for_trans = for_trans,
132 .dir = dir,
Pau Espin Pedrola3cdab42019-05-09 17:54:08 +0200133 .local_osmux_cid = -2,
134 .remote_osmux_cid = -2,
Andreas Eversberg58fe2e02023-06-21 12:37:18 +0200135 .crcx_conn_mode = MGCP_CONN_NONE, /* Use connection's default mode. */
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100136 };
137
138 rtp_stream_update_id(rtps);
139
140 return rtps;
141}
142
143static void check_established(struct rtp_stream *rtps)
144{
145 if (rtps->fi->state != RTP_STREAM_ST_ESTABLISHED
Neels Hofmeyr84ce2062019-10-05 05:15:25 +0200146 && osmo_sockaddr_str_is_nonzero(&rtps->local)
147 && osmo_sockaddr_str_is_nonzero(&rtps->remote)
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100148 && rtps->remote_sent_to_mgw
Pau Espin Pedrola3cdab42019-05-09 17:54:08 +0200149 && (!rtps->use_osmux || rtps->remote_osmux_cid_sent_to_mgw)
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100150 && rtps->codecs_known)
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100151 rtp_stream_state_chg(rtps, RTP_STREAM_ST_ESTABLISHED);
152}
153
154static void rtp_stream_fsm_establishing_established(struct osmo_fsm_inst *fi, uint32_t event, void *data)
155{
156 struct rtp_stream *rtps = fi->priv;
157 const struct mgcp_conn_peer *crcx_info;
158 switch (event) {
159 case RTP_STREAM_EV_CRCX_OK:
160 crcx_info = osmo_mgcpc_ep_ci_get_rtp_info(rtps->ci);
Vadim Yanitskiye0ef6d12019-05-11 04:04:59 +0700161 if (!crcx_info) {
162 LOG_RTPS(rtps, LOGL_ERROR, "osmo_mgcpc_ep_ci_get_rtp_info() has "
163 "failed, ignoring %s\n", osmo_fsm_event_name(fi->fsm, event));
164 return;
165 }
166
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100167 osmo_sockaddr_str_from_str(&rtps->local, crcx_info->addr, crcx_info->port);
Pau Espin Pedrola3cdab42019-05-09 17:54:08 +0200168 if (rtps->use_osmux != crcx_info->x_osmo_osmux_use) {
169 LOG_RTPS(rtps, LOGL_ERROR, "Osmux usage request and response don't match: %d vs %d",
170 rtps->use_osmux, crcx_info->x_osmo_osmux_use);
171 /* TODO: proper failure path */
172 OSMO_ASSERT(rtps->use_osmux != crcx_info->x_osmo_osmux_use);
173 }
174 if (crcx_info->x_osmo_osmux_use)
175 rtps->local_osmux_cid = crcx_info->x_osmo_osmux_cid;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100176 rtp_stream_update_id(rtps);
Andreas Eversbergbcb4d6b2023-07-05 15:03:19 +0200177 osmo_fsm_inst_dispatch(fi->proc.parent, rtps->event_avail, rtps);
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100178 check_established(rtps);
179
Andreas Eversberg58fe2e02023-06-21 12:37:18 +0200180 if ((!rtps->remote_sent_to_mgw || !rtps->codecs_sent_to_mgw || !rtps->mode_sent_to_mgw)
Neels Hofmeyr84ce2062019-10-05 05:15:25 +0200181 && osmo_sockaddr_str_is_nonzero(&rtps->remote)
Pau Espin Pedrola3cdab42019-05-09 17:54:08 +0200182 && (!rtps->use_osmux || rtps->remote_osmux_cid_sent_to_mgw)
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100183 && rtps->codecs_known) {
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100184 LOG_RTPS(rtps, LOGL_DEBUG,
Andreas Eversberg58fe2e02023-06-21 12:37:18 +0200185 "local ip:port set;%s%s%s%s triggering MDCX to send the new settings\n",
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100186 (!rtps->remote_sent_to_mgw) ? " remote ip:port not yet sent," : "",
187 (!rtps->codecs_sent_to_mgw) ? " codecs not yet sent," : "",
Andreas Eversberg58fe2e02023-06-21 12:37:18 +0200188 (!rtps->mode_sent_to_mgw) ? " mode not yet sent," : "",
Pau Espin Pedrola3cdab42019-05-09 17:54:08 +0200189 (rtps->use_osmux && !rtps->remote_osmux_cid_sent_to_mgw) ? "Osmux CID not yet sent,": "");
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100190 rtp_stream_do_mdcx(rtps);
191 }
192 return;
193
194 case RTP_STREAM_EV_MDCX_OK:
195 rtp_stream_update_id(rtps);
196 check_established(rtps);
197 return;
198
199 case RTP_STREAM_EV_CRCX_FAIL:
200 case RTP_STREAM_EV_MDCX_FAIL:
201 rtps->remote_sent_to_mgw = false;
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100202 rtps->codecs_sent_to_mgw = false;
Andreas Eversberg58fe2e02023-06-21 12:37:18 +0200203 rtps->mode_sent_to_mgw = false;
Pau Espin Pedrola3cdab42019-05-09 17:54:08 +0200204 rtps->remote_osmux_cid_sent_to_mgw = false;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100205 rtp_stream_update_id(rtps);
206 rtp_stream_state_chg(rtps, RTP_STREAM_ST_DISCARDING);
207 return;
208
209 default:
210 OSMO_ASSERT(false);
211 };
212}
213
214void rtp_stream_fsm_established_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
215{
216 struct rtp_stream *rtps = fi->priv;
Andreas Eversbergbcb4d6b2023-07-05 15:03:19 +0200217 osmo_fsm_inst_dispatch(fi->proc.parent, rtps->event_estab, rtps);
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100218}
219
220static int rtp_stream_fsm_timer_cb(struct osmo_fsm_inst *fi)
221{
222 struct rtp_stream *rtps = fi->priv;
223 rtp_stream_state_chg(rtps, RTP_STREAM_ST_DISCARDING);
224 return 0;
225}
226
227static void rtp_stream_fsm_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
228{
229 struct rtp_stream *rtps = fi->priv;
230 if (rtps->ci) {
Neels Hofmeyr523b92f2019-10-05 01:14:41 +0200231 osmo_mgcpc_ep_cancel_notify(osmo_mgcpc_ep_ci_ep(rtps->ci), fi);
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100232 osmo_mgcpc_ep_ci_dlcx(rtps->ci);
233 rtps->ci = NULL;
234 }
235}
236
237void rtp_stream_fsm_discarding_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
238{
239 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
240}
241
242static const struct value_string rtp_stream_fsm_event_names[] = {
243 OSMO_VALUE_STRING(RTP_STREAM_EV_CRCX_OK),
244 OSMO_VALUE_STRING(RTP_STREAM_EV_CRCX_FAIL),
245 OSMO_VALUE_STRING(RTP_STREAM_EV_MDCX_OK),
246 OSMO_VALUE_STRING(RTP_STREAM_EV_MDCX_FAIL),
247 {}
248};
249
250#define S(x) (1 << (x))
251
252static const struct osmo_fsm_state rtp_stream_fsm_states[] = {
253 [RTP_STREAM_ST_UNINITIALIZED] = {
254 .name = "UNINITIALIZED",
255 .out_state_mask = 0
256 | S(RTP_STREAM_ST_ESTABLISHING)
257 | S(RTP_STREAM_ST_DISCARDING)
258 ,
259 },
260 [RTP_STREAM_ST_ESTABLISHING] = {
261 .name = "ESTABLISHING",
262 .in_event_mask = 0
263 | S(RTP_STREAM_EV_CRCX_OK)
264 | S(RTP_STREAM_EV_CRCX_FAIL)
265 | S(RTP_STREAM_EV_MDCX_OK)
266 | S(RTP_STREAM_EV_MDCX_FAIL)
267 ,
268 .out_state_mask = 0
269 | S(RTP_STREAM_ST_ESTABLISHED)
270 | S(RTP_STREAM_ST_DISCARDING)
271 ,
272 .action = rtp_stream_fsm_establishing_established,
273 },
274 [RTP_STREAM_ST_ESTABLISHED] = {
275 .name = "ESTABLISHED",
276 .out_state_mask = 0
277 | S(RTP_STREAM_ST_ESTABLISHING)
278 | S(RTP_STREAM_ST_DISCARDING)
279 ,
280 .onenter = rtp_stream_fsm_established_onenter,
281 .action = rtp_stream_fsm_establishing_established,
282 },
283 [RTP_STREAM_ST_DISCARDING] = {
284 .name = "DISCARDING",
285 .onenter = rtp_stream_fsm_discarding_onenter,
286 .out_state_mask = 0
287 | S(RTP_STREAM_ST_DISCARDING)
288 ,
289 },
290};
291
292static struct osmo_fsm rtp_stream_fsm = {
293 .name = "rtp_stream",
294 .states = rtp_stream_fsm_states,
295 .num_states = ARRAY_SIZE(rtp_stream_fsm_states),
296 .log_subsys = DCC,
297 .event_names = rtp_stream_fsm_event_names,
298 .timer_cb = rtp_stream_fsm_timer_cb,
299 .cleanup = rtp_stream_fsm_cleanup,
300};
301
302static int rtp_stream_do_mgcp_verb(struct rtp_stream *rtps, enum mgcp_verb verb, uint32_t ok_event, uint32_t fail_event)
303{
304 struct mgcp_conn_peer verb_info;
305
306 if (!rtps->ci) {
307 LOG_RTPS(rtps, LOGL_ERROR, "Cannot send %s, no endpoint CI allocated\n", osmo_mgcp_verb_name(verb));
308 return -EINVAL;
309 }
310
311 verb_info = (struct mgcp_conn_peer){
312 .call_id = rtps->call_id,
313 .ptime = 20,
Pau Espin Pedrola3cdab42019-05-09 17:54:08 +0200314 .x_osmo_osmux_use = rtps->use_osmux,
315 .x_osmo_osmux_cid = rtps->remote_osmux_cid,
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100316 };
317
Andreas Eversberg58fe2e02023-06-21 12:37:18 +0200318 verb_info.conn_mode = rtps->crcx_conn_mode;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100319
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100320 if (rtps->codecs_known) {
321 /* Send the list of codecs to the MGW. Ideally we would just feed the SDP directly, but for legacy
322 * reasons we still need to translate to a struct mgcp_conn_peer representation to send it. */
323 struct sdp_audio_codec *codec;
324 int i = 0;
325 foreach_sdp_audio_codec(codec, &rtps->codecs) {
326 const struct codec_mapping *m = codec_mapping_by_subtype_name(codec->subtype_name);
327 if (!m) {
328 LOG_RTPS(rtps, LOGL_ERROR, "Cannot map codec '%s' to MGCP: codec is unknown\n",
329 codec->subtype_name);
330 continue;
331 }
332 verb_info.codecs[i] = m->mgcp;
333 verb_info.ptmap[i] = (struct ptmap){
334 .codec = m->mgcp,
335 .pt = codec->payload_type,
336 };
337 i++;
338 verb_info.codecs_len = i;
339 verb_info.ptmap_len = i;
340 }
341 rtps->codecs_sent_to_mgw = true;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100342 }
Neels Hofmeyr84ce2062019-10-05 05:15:25 +0200343 if (osmo_sockaddr_str_is_nonzero(&rtps->remote)) {
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100344 int rc = osmo_strlcpy(verb_info.addr, rtps->remote.ip, sizeof(verb_info.addr));
345 if (rc <= 0 || rc >= sizeof(verb_info.addr)) {
346 LOG_RTPS(rtps, LOGL_ERROR, "Failure to write IP address to MGCP message (rc=%d)\n", rc);
347 return -ENOSPC;
348 }
349 verb_info.port = rtps->remote.port;
350 rtps->remote_sent_to_mgw = true;
351 }
Andreas Eversberg58fe2e02023-06-21 12:37:18 +0200352 rtps->mode_sent_to_mgw = true;
Pau Espin Pedrolc0f94742023-03-15 12:53:13 +0100353 if (rtps->use_osmux && rtps->remote_osmux_cid >= 0)
354 rtps->remote_osmux_cid_sent_to_mgw = true;
Pau Espin Pedrola202cf42023-03-15 11:58:16 +0100355 rtp_stream_update_id(rtps);
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100356
357 osmo_mgcpc_ep_ci_request(rtps->ci, verb, &verb_info, rtps->fi, ok_event, fail_event, NULL);
358 return 0;
359}
360
361int rtp_stream_ensure_ci(struct rtp_stream *rtps, struct osmo_mgcpc_ep *at_endpoint)
362{
363 if (rtps->ci)
364 return rtp_stream_commit(rtps);
365
366 rtp_stream_state_chg(rtps, RTP_STREAM_ST_ESTABLISHING);
367
368 rtps->ci = osmo_mgcpc_ep_ci_add(at_endpoint, "%s", rtp_direction_name(rtps->dir));
369 if (!rtps->ci)
370 return -ENODEV;
371
372 return rtp_stream_do_mgcp_verb(rtps, MGCP_VERB_CRCX, RTP_STREAM_EV_CRCX_OK, RTP_STREAM_EV_CRCX_FAIL);
373}
374
375int rtp_stream_do_mdcx(struct rtp_stream *rtps)
376{
377 return rtp_stream_do_mgcp_verb(rtps, MGCP_VERB_MDCX, RTP_STREAM_EV_MDCX_OK, RTP_STREAM_EV_MDCX_FAIL);
378}
379
380void rtp_stream_release(struct rtp_stream *rtps)
381{
382 if (!rtps)
383 return;
384
385 rtp_stream_state_chg(rtps, RTP_STREAM_ST_DISCARDING);
386}
387
388/* After setting up a remote RTP address or a new codec, call this to trigger an MDCX.
Andreas Eversberg58fe2e02023-06-21 12:37:18 +0200389 * The MDCX will only trigger if all data needed by an endpoint is available (RTP address, codecs and mode) and if at
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100390 * least one of them has not yet been sent to the MGW in a previous CRCX or MDCX. */
391int rtp_stream_commit(struct rtp_stream *rtps)
392{
Neels Hofmeyr84ce2062019-10-05 05:15:25 +0200393 if (!osmo_sockaddr_str_is_nonzero(&rtps->remote)) {
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100394 LOG_RTPS(rtps, LOGL_DEBUG, "Not committing: no remote RTP address known\n");
395 return -1;
396 }
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100397 if (!rtps->codecs_known) {
398 LOG_RTPS(rtps, LOGL_DEBUG, "Not committing: no codecs known\n");
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100399 return -1;
400 }
Andreas Eversberg58fe2e02023-06-21 12:37:18 +0200401 if (rtps->remote_sent_to_mgw && rtps->codecs_sent_to_mgw && rtps->mode_sent_to_mgw) {
402 LOG_RTPS(rtps, LOGL_DEBUG,
403 "Not committing: remote RTP address, codecs and mode are already set up at MGW\n");
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100404 return 0;
405 }
Neels Hofmeyra899dea2022-10-31 18:15:32 +0100406 if (!rtps->ci) {
407 LOG_RTPS(rtps, LOGL_DEBUG, "Not committing: no MGW endpoint CI set up\n");
408 return -1;
409 }
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100410
Andreas Eversberg58fe2e02023-06-21 12:37:18 +0200411 LOG_RTPS(rtps, LOGL_DEBUG, "Committing: Tx MDCX to update the MGW: updating%s%s%s%s\n",
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100412 rtps->remote_sent_to_mgw ? "" : " remote-RTP-IP-port",
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100413 rtps->codecs_sent_to_mgw ? "" : " codecs",
Andreas Eversberg58fe2e02023-06-21 12:37:18 +0200414 rtps->mode_sent_to_mgw ? "" : " mode",
Pau Espin Pedrola3cdab42019-05-09 17:54:08 +0200415 (!rtps->use_osmux || rtps->remote_osmux_cid_sent_to_mgw) ? "" : " remote-Osmux-CID");
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100416 return rtp_stream_do_mdcx(rtps);
417}
418
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100419void rtp_stream_set_codecs(struct rtp_stream *rtps, const struct sdp_audio_codecs *codecs)
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100420{
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100421 if (!codecs || !codecs->count)
422 return;
423 if (sdp_audio_codecs_cmp(&rtps->codecs, codecs, false, true) == 0) {
424 LOG_RTPS(rtps, LOGL_DEBUG, "no change: codecs already set to %s\n",
425 sdp_audio_codecs_to_str(&rtps->codecs));
426 return;
427 }
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100428 if (rtps->fi->state == RTP_STREAM_ST_ESTABLISHED)
429 rtp_stream_state_chg(rtps, RTP_STREAM_ST_ESTABLISHING);
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100430 LOG_RTPS(rtps, LOGL_DEBUG, "setting codecs to %s\n", sdp_audio_codecs_to_str(codecs));
431 rtps->codecs = *codecs;
432 rtps->codecs_known = true;
433 rtps->codecs_sent_to_mgw = false;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100434 rtp_stream_update_id(rtps);
435}
436
Andreas Eversberg58fe2e02023-06-21 12:37:18 +0200437void rtp_stream_set_mode(struct rtp_stream *rtps, enum mgcp_connection_mode mode)
438{
439 if (rtps->crcx_conn_mode == mode)
440 return;
441 if (rtps->fi->state == RTP_STREAM_ST_ESTABLISHED)
442 rtp_stream_state_chg(rtps, RTP_STREAM_ST_ESTABLISHING);
443 LOG_RTPS(rtps, LOGL_DEBUG, "setting mode to %s\n", mgcp_client_cmode_name(mode));
444 rtps->mode_sent_to_mgw = false;
445 rtps->crcx_conn_mode = mode;
446 rtp_stream_update_id(rtps);
447}
448
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100449/* Convenience shortcut to call rtp_stream_set_codecs() with a list of only one sdp_audio_codec record. */
450void rtp_stream_set_one_codec(struct rtp_stream *rtps, const struct sdp_audio_codec *codec)
451{
452 struct sdp_audio_codecs codecs = {};
453 sdp_audio_codecs_add_copy(&codecs, codec);
454 rtp_stream_set_codecs(rtps, &codecs);
455}
456
457/* For legacy, rather use rtp_stream_set_codecs() with a full codecs list. */
458bool rtp_stream_set_codecs_from_mgcp_codec(struct rtp_stream *rtps, enum mgcp_codecs codec)
459{
460 struct sdp_audio_codecs codecs = {};
461 if (!sdp_audio_codecs_add_mgcp_codec(&codecs, codec))
462 return false;
463 rtp_stream_set_codecs(rtps, &codecs);
464 return true;
465}
466
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100467void rtp_stream_set_remote_addr(struct rtp_stream *rtps, const struct osmo_sockaddr_str *r)
468{
Neels Hofmeyr91c9c2f2022-10-31 18:21:16 +0100469 if (osmo_sockaddr_str_cmp(&rtps->remote, r) == 0) {
470 LOG_RTPS(rtps, LOGL_DEBUG, "remote addr already " OSMO_SOCKADDR_STR_FMT ", no change\n",
471 OSMO_SOCKADDR_STR_FMT_ARGS(r));
472 return;
473 }
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100474 if (rtps->fi->state == RTP_STREAM_ST_ESTABLISHED)
475 rtp_stream_state_chg(rtps, RTP_STREAM_ST_ESTABLISHING);
476 LOG_RTPS(rtps, LOGL_DEBUG, "setting remote addr to " OSMO_SOCKADDR_STR_FMT "\n", OSMO_SOCKADDR_STR_FMT_ARGS(r));
477 rtps->remote = *r;
478 rtps->remote_sent_to_mgw = false;
479 rtp_stream_update_id(rtps);
480}
481
Neels Hofmeyr8dd16462022-01-13 20:06:53 +0100482void rtp_stream_set_remote_addr_and_codecs(struct rtp_stream *rtps, const struct sdp_msg *sdp)
483{
484 rtp_stream_set_codecs(rtps, &sdp->audio_codecs);
485 if (osmo_sockaddr_str_is_nonzero(&sdp->rtp))
486 rtp_stream_set_remote_addr(rtps, &sdp->rtp);
487}
488
Pau Espin Pedrola3cdab42019-05-09 17:54:08 +0200489void rtp_stream_set_remote_osmux_cid(struct rtp_stream *rtps, uint8_t osmux_cid)
490{
491 if (rtps->fi->state == RTP_STREAM_ST_ESTABLISHED)
492 rtp_stream_state_chg(rtps, RTP_STREAM_ST_ESTABLISHING);
493 LOG_RTPS(rtps, LOGL_DEBUG, "setting remote Osmux CID to %u\n", osmux_cid);
494 rtps->remote_osmux_cid = osmux_cid;
495 rtps->remote_osmux_cid_sent_to_mgw = false;
496 rtp_stream_update_id(rtps);
497}
498
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100499bool rtp_stream_is_established(struct rtp_stream *rtps)
500{
501 if (!rtps)
502 return false;
503 if (!rtps->fi)
504 return false;
505 if (rtps->fi->state != RTP_STREAM_ST_ESTABLISHED)
506 return false;
507 if (!rtps->remote_sent_to_mgw
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100508 || !rtps->codecs_sent_to_mgw
Andreas Eversberg58fe2e02023-06-21 12:37:18 +0200509 || !rtps->mode_sent_to_mgw
Pau Espin Pedrola3cdab42019-05-09 17:54:08 +0200510 || (rtps->use_osmux && !rtps->remote_osmux_cid_sent_to_mgw))
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100511 return false;
512 return true;
513}