blob: dcb4ef08e84b89478b450b8c88aa9c034197db60 [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. */
113struct rtp_stream *rtp_stream_alloc(struct call_leg *parent_call_leg, enum rtp_direction dir,
114 uint32_t call_id, struct gsm_trans *for_trans)
115{
116 struct osmo_fsm_inst *fi;
117 struct rtp_stream *rtps;
118
119 fi = osmo_fsm_inst_alloc_child(&rtp_stream_fsm, parent_call_leg->fi, CALL_LEG_EV_RTP_STREAM_GONE);
120 OSMO_ASSERT(fi);
121
122 rtps = talloc(fi, struct rtp_stream);
123 OSMO_ASSERT(rtps);
124 fi->priv = rtps;
125 *rtps = (struct rtp_stream){
126 .fi = fi,
127 .parent_call_leg = parent_call_leg,
128 .call_id = call_id,
129 .for_trans = for_trans,
130 .dir = dir,
Pau Espin Pedrola3cdab42019-05-09 17:54:08 +0200131 .local_osmux_cid = -2,
132 .remote_osmux_cid = -2,
Andreas Eversberg58fe2e02023-06-21 12:37:18 +0200133 .crcx_conn_mode = MGCP_CONN_NONE, /* Use connection's default mode. */
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100134 };
135
136 rtp_stream_update_id(rtps);
137
138 return rtps;
139}
140
141static void check_established(struct rtp_stream *rtps)
142{
143 if (rtps->fi->state != RTP_STREAM_ST_ESTABLISHED
Neels Hofmeyr84ce2062019-10-05 05:15:25 +0200144 && osmo_sockaddr_str_is_nonzero(&rtps->local)
145 && osmo_sockaddr_str_is_nonzero(&rtps->remote)
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100146 && rtps->remote_sent_to_mgw
Pau Espin Pedrola3cdab42019-05-09 17:54:08 +0200147 && (!rtps->use_osmux || rtps->remote_osmux_cid_sent_to_mgw)
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100148 && rtps->codecs_known)
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100149 rtp_stream_state_chg(rtps, RTP_STREAM_ST_ESTABLISHED);
150}
151
152static void rtp_stream_fsm_establishing_established(struct osmo_fsm_inst *fi, uint32_t event, void *data)
153{
154 struct rtp_stream *rtps = fi->priv;
155 const struct mgcp_conn_peer *crcx_info;
156 switch (event) {
157 case RTP_STREAM_EV_CRCX_OK:
158 crcx_info = osmo_mgcpc_ep_ci_get_rtp_info(rtps->ci);
Vadim Yanitskiye0ef6d12019-05-11 04:04:59 +0700159 if (!crcx_info) {
160 LOG_RTPS(rtps, LOGL_ERROR, "osmo_mgcpc_ep_ci_get_rtp_info() has "
161 "failed, ignoring %s\n", osmo_fsm_event_name(fi->fsm, event));
162 return;
163 }
164
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100165 osmo_sockaddr_str_from_str(&rtps->local, crcx_info->addr, crcx_info->port);
Pau Espin Pedrola3cdab42019-05-09 17:54:08 +0200166 if (rtps->use_osmux != crcx_info->x_osmo_osmux_use) {
167 LOG_RTPS(rtps, LOGL_ERROR, "Osmux usage request and response don't match: %d vs %d",
168 rtps->use_osmux, crcx_info->x_osmo_osmux_use);
169 /* TODO: proper failure path */
170 OSMO_ASSERT(rtps->use_osmux != crcx_info->x_osmo_osmux_use);
171 }
172 if (crcx_info->x_osmo_osmux_use)
173 rtps->local_osmux_cid = crcx_info->x_osmo_osmux_cid;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100174 rtp_stream_update_id(rtps);
175 osmo_fsm_inst_dispatch(fi->proc.parent, CALL_LEG_EV_RTP_STREAM_ADDR_AVAILABLE, rtps);
176 check_established(rtps);
177
Andreas Eversberg58fe2e02023-06-21 12:37:18 +0200178 if ((!rtps->remote_sent_to_mgw || !rtps->codecs_sent_to_mgw || !rtps->mode_sent_to_mgw)
Neels Hofmeyr84ce2062019-10-05 05:15:25 +0200179 && osmo_sockaddr_str_is_nonzero(&rtps->remote)
Pau Espin Pedrola3cdab42019-05-09 17:54:08 +0200180 && (!rtps->use_osmux || rtps->remote_osmux_cid_sent_to_mgw)
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100181 && rtps->codecs_known) {
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100182 LOG_RTPS(rtps, LOGL_DEBUG,
Andreas Eversberg58fe2e02023-06-21 12:37:18 +0200183 "local ip:port set;%s%s%s%s triggering MDCX to send the new settings\n",
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100184 (!rtps->remote_sent_to_mgw) ? " remote ip:port not yet sent," : "",
185 (!rtps->codecs_sent_to_mgw) ? " codecs not yet sent," : "",
Andreas Eversberg58fe2e02023-06-21 12:37:18 +0200186 (!rtps->mode_sent_to_mgw) ? " mode not yet sent," : "",
Pau Espin Pedrola3cdab42019-05-09 17:54:08 +0200187 (rtps->use_osmux && !rtps->remote_osmux_cid_sent_to_mgw) ? "Osmux CID not yet sent,": "");
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100188 rtp_stream_do_mdcx(rtps);
189 }
190 return;
191
192 case RTP_STREAM_EV_MDCX_OK:
193 rtp_stream_update_id(rtps);
194 check_established(rtps);
195 return;
196
197 case RTP_STREAM_EV_CRCX_FAIL:
198 case RTP_STREAM_EV_MDCX_FAIL:
199 rtps->remote_sent_to_mgw = false;
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100200 rtps->codecs_sent_to_mgw = false;
Andreas Eversberg58fe2e02023-06-21 12:37:18 +0200201 rtps->mode_sent_to_mgw = false;
Pau Espin Pedrola3cdab42019-05-09 17:54:08 +0200202 rtps->remote_osmux_cid_sent_to_mgw = false;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100203 rtp_stream_update_id(rtps);
204 rtp_stream_state_chg(rtps, RTP_STREAM_ST_DISCARDING);
205 return;
206
207 default:
208 OSMO_ASSERT(false);
209 };
210}
211
212void rtp_stream_fsm_established_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
213{
214 struct rtp_stream *rtps = fi->priv;
215 osmo_fsm_inst_dispatch(fi->proc.parent, CALL_LEG_EV_RTP_STREAM_ESTABLISHED, rtps);
216}
217
218static int rtp_stream_fsm_timer_cb(struct osmo_fsm_inst *fi)
219{
220 struct rtp_stream *rtps = fi->priv;
221 rtp_stream_state_chg(rtps, RTP_STREAM_ST_DISCARDING);
222 return 0;
223}
224
225static void rtp_stream_fsm_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
226{
227 struct rtp_stream *rtps = fi->priv;
228 if (rtps->ci) {
Neels Hofmeyr523b92f2019-10-05 01:14:41 +0200229 osmo_mgcpc_ep_cancel_notify(osmo_mgcpc_ep_ci_ep(rtps->ci), fi);
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100230 osmo_mgcpc_ep_ci_dlcx(rtps->ci);
231 rtps->ci = NULL;
232 }
233}
234
235void rtp_stream_fsm_discarding_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
236{
237 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
238}
239
240static const struct value_string rtp_stream_fsm_event_names[] = {
241 OSMO_VALUE_STRING(RTP_STREAM_EV_CRCX_OK),
242 OSMO_VALUE_STRING(RTP_STREAM_EV_CRCX_FAIL),
243 OSMO_VALUE_STRING(RTP_STREAM_EV_MDCX_OK),
244 OSMO_VALUE_STRING(RTP_STREAM_EV_MDCX_FAIL),
245 {}
246};
247
248#define S(x) (1 << (x))
249
250static const struct osmo_fsm_state rtp_stream_fsm_states[] = {
251 [RTP_STREAM_ST_UNINITIALIZED] = {
252 .name = "UNINITIALIZED",
253 .out_state_mask = 0
254 | S(RTP_STREAM_ST_ESTABLISHING)
255 | S(RTP_STREAM_ST_DISCARDING)
256 ,
257 },
258 [RTP_STREAM_ST_ESTABLISHING] = {
259 .name = "ESTABLISHING",
260 .in_event_mask = 0
261 | S(RTP_STREAM_EV_CRCX_OK)
262 | S(RTP_STREAM_EV_CRCX_FAIL)
263 | S(RTP_STREAM_EV_MDCX_OK)
264 | S(RTP_STREAM_EV_MDCX_FAIL)
265 ,
266 .out_state_mask = 0
267 | S(RTP_STREAM_ST_ESTABLISHED)
268 | S(RTP_STREAM_ST_DISCARDING)
269 ,
270 .action = rtp_stream_fsm_establishing_established,
271 },
272 [RTP_STREAM_ST_ESTABLISHED] = {
273 .name = "ESTABLISHED",
274 .out_state_mask = 0
275 | S(RTP_STREAM_ST_ESTABLISHING)
276 | S(RTP_STREAM_ST_DISCARDING)
277 ,
278 .onenter = rtp_stream_fsm_established_onenter,
279 .action = rtp_stream_fsm_establishing_established,
280 },
281 [RTP_STREAM_ST_DISCARDING] = {
282 .name = "DISCARDING",
283 .onenter = rtp_stream_fsm_discarding_onenter,
284 .out_state_mask = 0
285 | S(RTP_STREAM_ST_DISCARDING)
286 ,
287 },
288};
289
290static struct osmo_fsm rtp_stream_fsm = {
291 .name = "rtp_stream",
292 .states = rtp_stream_fsm_states,
293 .num_states = ARRAY_SIZE(rtp_stream_fsm_states),
294 .log_subsys = DCC,
295 .event_names = rtp_stream_fsm_event_names,
296 .timer_cb = rtp_stream_fsm_timer_cb,
297 .cleanup = rtp_stream_fsm_cleanup,
298};
299
300static int rtp_stream_do_mgcp_verb(struct rtp_stream *rtps, enum mgcp_verb verb, uint32_t ok_event, uint32_t fail_event)
301{
302 struct mgcp_conn_peer verb_info;
303
304 if (!rtps->ci) {
305 LOG_RTPS(rtps, LOGL_ERROR, "Cannot send %s, no endpoint CI allocated\n", osmo_mgcp_verb_name(verb));
306 return -EINVAL;
307 }
308
309 verb_info = (struct mgcp_conn_peer){
310 .call_id = rtps->call_id,
311 .ptime = 20,
Pau Espin Pedrola3cdab42019-05-09 17:54:08 +0200312 .x_osmo_osmux_use = rtps->use_osmux,
313 .x_osmo_osmux_cid = rtps->remote_osmux_cid,
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100314 };
315
Andreas Eversberg58fe2e02023-06-21 12:37:18 +0200316 verb_info.conn_mode = rtps->crcx_conn_mode;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100317
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100318 if (rtps->codecs_known) {
319 /* Send the list of codecs to the MGW. Ideally we would just feed the SDP directly, but for legacy
320 * reasons we still need to translate to a struct mgcp_conn_peer representation to send it. */
321 struct sdp_audio_codec *codec;
322 int i = 0;
323 foreach_sdp_audio_codec(codec, &rtps->codecs) {
324 const struct codec_mapping *m = codec_mapping_by_subtype_name(codec->subtype_name);
325 if (!m) {
326 LOG_RTPS(rtps, LOGL_ERROR, "Cannot map codec '%s' to MGCP: codec is unknown\n",
327 codec->subtype_name);
328 continue;
329 }
330 verb_info.codecs[i] = m->mgcp;
331 verb_info.ptmap[i] = (struct ptmap){
332 .codec = m->mgcp,
333 .pt = codec->payload_type,
334 };
335 i++;
336 verb_info.codecs_len = i;
337 verb_info.ptmap_len = i;
338 }
339 rtps->codecs_sent_to_mgw = true;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100340 }
Neels Hofmeyr84ce2062019-10-05 05:15:25 +0200341 if (osmo_sockaddr_str_is_nonzero(&rtps->remote)) {
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100342 int rc = osmo_strlcpy(verb_info.addr, rtps->remote.ip, sizeof(verb_info.addr));
343 if (rc <= 0 || rc >= sizeof(verb_info.addr)) {
344 LOG_RTPS(rtps, LOGL_ERROR, "Failure to write IP address to MGCP message (rc=%d)\n", rc);
345 return -ENOSPC;
346 }
347 verb_info.port = rtps->remote.port;
348 rtps->remote_sent_to_mgw = true;
349 }
Andreas Eversberg58fe2e02023-06-21 12:37:18 +0200350 rtps->mode_sent_to_mgw = true;
Pau Espin Pedrolc0f94742023-03-15 12:53:13 +0100351 if (rtps->use_osmux && rtps->remote_osmux_cid >= 0)
352 rtps->remote_osmux_cid_sent_to_mgw = true;
Pau Espin Pedrola202cf42023-03-15 11:58:16 +0100353 rtp_stream_update_id(rtps);
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100354
355 osmo_mgcpc_ep_ci_request(rtps->ci, verb, &verb_info, rtps->fi, ok_event, fail_event, NULL);
356 return 0;
357}
358
359int rtp_stream_ensure_ci(struct rtp_stream *rtps, struct osmo_mgcpc_ep *at_endpoint)
360{
361 if (rtps->ci)
362 return rtp_stream_commit(rtps);
363
364 rtp_stream_state_chg(rtps, RTP_STREAM_ST_ESTABLISHING);
365
366 rtps->ci = osmo_mgcpc_ep_ci_add(at_endpoint, "%s", rtp_direction_name(rtps->dir));
367 if (!rtps->ci)
368 return -ENODEV;
369
370 return rtp_stream_do_mgcp_verb(rtps, MGCP_VERB_CRCX, RTP_STREAM_EV_CRCX_OK, RTP_STREAM_EV_CRCX_FAIL);
371}
372
373int rtp_stream_do_mdcx(struct rtp_stream *rtps)
374{
375 return rtp_stream_do_mgcp_verb(rtps, MGCP_VERB_MDCX, RTP_STREAM_EV_MDCX_OK, RTP_STREAM_EV_MDCX_FAIL);
376}
377
378void rtp_stream_release(struct rtp_stream *rtps)
379{
380 if (!rtps)
381 return;
382
383 rtp_stream_state_chg(rtps, RTP_STREAM_ST_DISCARDING);
384}
385
386/* After setting up a remote RTP address or a new codec, call this to trigger an MDCX.
Andreas Eversberg58fe2e02023-06-21 12:37:18 +0200387 * 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 +0100388 * least one of them has not yet been sent to the MGW in a previous CRCX or MDCX. */
389int rtp_stream_commit(struct rtp_stream *rtps)
390{
Neels Hofmeyr84ce2062019-10-05 05:15:25 +0200391 if (!osmo_sockaddr_str_is_nonzero(&rtps->remote)) {
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100392 LOG_RTPS(rtps, LOGL_DEBUG, "Not committing: no remote RTP address known\n");
393 return -1;
394 }
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100395 if (!rtps->codecs_known) {
396 LOG_RTPS(rtps, LOGL_DEBUG, "Not committing: no codecs known\n");
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100397 return -1;
398 }
Andreas Eversberg58fe2e02023-06-21 12:37:18 +0200399 if (rtps->remote_sent_to_mgw && rtps->codecs_sent_to_mgw && rtps->mode_sent_to_mgw) {
400 LOG_RTPS(rtps, LOGL_DEBUG,
401 "Not committing: remote RTP address, codecs and mode are already set up at MGW\n");
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100402 return 0;
403 }
Neels Hofmeyra899dea2022-10-31 18:15:32 +0100404 if (!rtps->ci) {
405 LOG_RTPS(rtps, LOGL_DEBUG, "Not committing: no MGW endpoint CI set up\n");
406 return -1;
407 }
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100408
Andreas Eversberg58fe2e02023-06-21 12:37:18 +0200409 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 +0100410 rtps->remote_sent_to_mgw ? "" : " remote-RTP-IP-port",
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100411 rtps->codecs_sent_to_mgw ? "" : " codecs",
Andreas Eversberg58fe2e02023-06-21 12:37:18 +0200412 rtps->mode_sent_to_mgw ? "" : " mode",
Pau Espin Pedrola3cdab42019-05-09 17:54:08 +0200413 (!rtps->use_osmux || rtps->remote_osmux_cid_sent_to_mgw) ? "" : " remote-Osmux-CID");
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100414 return rtp_stream_do_mdcx(rtps);
415}
416
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100417void rtp_stream_set_codecs(struct rtp_stream *rtps, const struct sdp_audio_codecs *codecs)
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100418{
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100419 if (!codecs || !codecs->count)
420 return;
421 if (sdp_audio_codecs_cmp(&rtps->codecs, codecs, false, true) == 0) {
422 LOG_RTPS(rtps, LOGL_DEBUG, "no change: codecs already set to %s\n",
423 sdp_audio_codecs_to_str(&rtps->codecs));
424 return;
425 }
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100426 if (rtps->fi->state == RTP_STREAM_ST_ESTABLISHED)
427 rtp_stream_state_chg(rtps, RTP_STREAM_ST_ESTABLISHING);
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100428 LOG_RTPS(rtps, LOGL_DEBUG, "setting codecs to %s\n", sdp_audio_codecs_to_str(codecs));
429 rtps->codecs = *codecs;
430 rtps->codecs_known = true;
431 rtps->codecs_sent_to_mgw = false;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100432 rtp_stream_update_id(rtps);
433}
434
Andreas Eversberg58fe2e02023-06-21 12:37:18 +0200435void rtp_stream_set_mode(struct rtp_stream *rtps, enum mgcp_connection_mode mode)
436{
437 if (rtps->crcx_conn_mode == mode)
438 return;
439 if (rtps->fi->state == RTP_STREAM_ST_ESTABLISHED)
440 rtp_stream_state_chg(rtps, RTP_STREAM_ST_ESTABLISHING);
441 LOG_RTPS(rtps, LOGL_DEBUG, "setting mode to %s\n", mgcp_client_cmode_name(mode));
442 rtps->mode_sent_to_mgw = false;
443 rtps->crcx_conn_mode = mode;
444 rtp_stream_update_id(rtps);
445}
446
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100447/* Convenience shortcut to call rtp_stream_set_codecs() with a list of only one sdp_audio_codec record. */
448void rtp_stream_set_one_codec(struct rtp_stream *rtps, const struct sdp_audio_codec *codec)
449{
450 struct sdp_audio_codecs codecs = {};
451 sdp_audio_codecs_add_copy(&codecs, codec);
452 rtp_stream_set_codecs(rtps, &codecs);
453}
454
455/* For legacy, rather use rtp_stream_set_codecs() with a full codecs list. */
456bool rtp_stream_set_codecs_from_mgcp_codec(struct rtp_stream *rtps, enum mgcp_codecs codec)
457{
458 struct sdp_audio_codecs codecs = {};
459 if (!sdp_audio_codecs_add_mgcp_codec(&codecs, codec))
460 return false;
461 rtp_stream_set_codecs(rtps, &codecs);
462 return true;
463}
464
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100465void rtp_stream_set_remote_addr(struct rtp_stream *rtps, const struct osmo_sockaddr_str *r)
466{
Neels Hofmeyr91c9c2f2022-10-31 18:21:16 +0100467 if (osmo_sockaddr_str_cmp(&rtps->remote, r) == 0) {
468 LOG_RTPS(rtps, LOGL_DEBUG, "remote addr already " OSMO_SOCKADDR_STR_FMT ", no change\n",
469 OSMO_SOCKADDR_STR_FMT_ARGS(r));
470 return;
471 }
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100472 if (rtps->fi->state == RTP_STREAM_ST_ESTABLISHED)
473 rtp_stream_state_chg(rtps, RTP_STREAM_ST_ESTABLISHING);
474 LOG_RTPS(rtps, LOGL_DEBUG, "setting remote addr to " OSMO_SOCKADDR_STR_FMT "\n", OSMO_SOCKADDR_STR_FMT_ARGS(r));
475 rtps->remote = *r;
476 rtps->remote_sent_to_mgw = false;
477 rtp_stream_update_id(rtps);
478}
479
Neels Hofmeyr8dd16462022-01-13 20:06:53 +0100480void rtp_stream_set_remote_addr_and_codecs(struct rtp_stream *rtps, const struct sdp_msg *sdp)
481{
482 rtp_stream_set_codecs(rtps, &sdp->audio_codecs);
483 if (osmo_sockaddr_str_is_nonzero(&sdp->rtp))
484 rtp_stream_set_remote_addr(rtps, &sdp->rtp);
485}
486
Pau Espin Pedrola3cdab42019-05-09 17:54:08 +0200487void rtp_stream_set_remote_osmux_cid(struct rtp_stream *rtps, uint8_t osmux_cid)
488{
489 if (rtps->fi->state == RTP_STREAM_ST_ESTABLISHED)
490 rtp_stream_state_chg(rtps, RTP_STREAM_ST_ESTABLISHING);
491 LOG_RTPS(rtps, LOGL_DEBUG, "setting remote Osmux CID to %u\n", osmux_cid);
492 rtps->remote_osmux_cid = osmux_cid;
493 rtps->remote_osmux_cid_sent_to_mgw = false;
494 rtp_stream_update_id(rtps);
495}
496
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100497bool rtp_stream_is_established(struct rtp_stream *rtps)
498{
499 if (!rtps)
500 return false;
501 if (!rtps->fi)
502 return false;
503 if (rtps->fi->state != RTP_STREAM_ST_ESTABLISHED)
504 return false;
505 if (!rtps->remote_sent_to_mgw
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100506 || !rtps->codecs_sent_to_mgw
Andreas Eversberg58fe2e02023-06-21 12:37:18 +0200507 || !rtps->mode_sent_to_mgw
Pau Espin Pedrola3cdab42019-05-09 17:54:08 +0200508 || (rtps->use_osmux && !rtps->remote_osmux_cid_sent_to_mgw))
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100509 return false;
510 return true;
511}