blob: 6c408affc9c9ba31d19feed7adbf7dfdf80cac2c [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");
Pau Espin Pedrola3cdab42019-05-09 17:54:08 +020086 if (rtps->use_osmux) {
87 if (rtps->remote_osmux_cid < 0)
88 OSMO_STRBUF_PRINTF(sb, ":no-remote-osmux-cid");
89 else if (!rtps->remote_osmux_cid_sent_to_mgw)
90 OSMO_STRBUF_PRINTF(sb, ":remote-osmux-cid-not-sent");
91 }
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010092 }
Neels Hofmeyr84ce2062019-10-05 05:15:25 +020093 if (osmo_sockaddr_str_is_nonzero(&rtps->local))
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010094 OSMO_STRBUF_PRINTF(sb, ":local-%s-%u", rtps->local.ip, rtps->local.port);
Neels Hofmeyr84ce2062019-10-05 05:15:25 +020095 if (osmo_sockaddr_str_is_nonzero(&rtps->remote))
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010096 OSMO_STRBUF_PRINTF(sb, ":remote-%s-%u", rtps->remote.ip, rtps->remote.port);
Pau Espin Pedrola3cdab42019-05-09 17:54:08 +020097 if (rtps->use_osmux)
98 OSMO_STRBUF_PRINTF(sb, ":osmux-%d-%d", rtps->local_osmux_cid, rtps->remote_osmux_cid);
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010099
100 /* Replace any dots in the IP address, dots not allowed as FSM instance name */
101 for (p = buf; *p; p++)
102 if (*p == '.')
103 *p = '-';
104
105 osmo_fsm_inst_update_id_f(rtps->fi, "%s", buf);
106}
107
108/* Allocate RTP stream under a call leg. This is one RTP connection from some remote entity with address and port to a
109 * local RTP address and port. call_id is stored for sending in MGCP transactions and as logging context. for_trans is
110 * optional, merely stored for reference by callers, and appears as log context if not NULL. */
111struct rtp_stream *rtp_stream_alloc(struct call_leg *parent_call_leg, enum rtp_direction dir,
112 uint32_t call_id, struct gsm_trans *for_trans)
113{
114 struct osmo_fsm_inst *fi;
115 struct rtp_stream *rtps;
116
117 fi = osmo_fsm_inst_alloc_child(&rtp_stream_fsm, parent_call_leg->fi, CALL_LEG_EV_RTP_STREAM_GONE);
118 OSMO_ASSERT(fi);
119
120 rtps = talloc(fi, struct rtp_stream);
121 OSMO_ASSERT(rtps);
122 fi->priv = rtps;
123 *rtps = (struct rtp_stream){
124 .fi = fi,
125 .parent_call_leg = parent_call_leg,
126 .call_id = call_id,
127 .for_trans = for_trans,
128 .dir = dir,
Pau Espin Pedrola3cdab42019-05-09 17:54:08 +0200129 .local_osmux_cid = -2,
130 .remote_osmux_cid = -2,
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100131 };
132
133 rtp_stream_update_id(rtps);
134
135 return rtps;
136}
137
138static void check_established(struct rtp_stream *rtps)
139{
140 if (rtps->fi->state != RTP_STREAM_ST_ESTABLISHED
Neels Hofmeyr84ce2062019-10-05 05:15:25 +0200141 && osmo_sockaddr_str_is_nonzero(&rtps->local)
142 && osmo_sockaddr_str_is_nonzero(&rtps->remote)
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100143 && rtps->remote_sent_to_mgw
Pau Espin Pedrola3cdab42019-05-09 17:54:08 +0200144 && (!rtps->use_osmux || rtps->remote_osmux_cid_sent_to_mgw)
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100145 && rtps->codecs_known)
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100146 rtp_stream_state_chg(rtps, RTP_STREAM_ST_ESTABLISHED);
147}
148
149static void rtp_stream_fsm_establishing_established(struct osmo_fsm_inst *fi, uint32_t event, void *data)
150{
151 struct rtp_stream *rtps = fi->priv;
152 const struct mgcp_conn_peer *crcx_info;
153 switch (event) {
154 case RTP_STREAM_EV_CRCX_OK:
155 crcx_info = osmo_mgcpc_ep_ci_get_rtp_info(rtps->ci);
Vadim Yanitskiye0ef6d12019-05-11 04:04:59 +0700156 if (!crcx_info) {
157 LOG_RTPS(rtps, LOGL_ERROR, "osmo_mgcpc_ep_ci_get_rtp_info() has "
158 "failed, ignoring %s\n", osmo_fsm_event_name(fi->fsm, event));
159 return;
160 }
161
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100162 osmo_sockaddr_str_from_str(&rtps->local, crcx_info->addr, crcx_info->port);
Pau Espin Pedrola3cdab42019-05-09 17:54:08 +0200163 if (rtps->use_osmux != crcx_info->x_osmo_osmux_use) {
164 LOG_RTPS(rtps, LOGL_ERROR, "Osmux usage request and response don't match: %d vs %d",
165 rtps->use_osmux, crcx_info->x_osmo_osmux_use);
166 /* TODO: proper failure path */
167 OSMO_ASSERT(rtps->use_osmux != crcx_info->x_osmo_osmux_use);
168 }
169 if (crcx_info->x_osmo_osmux_use)
170 rtps->local_osmux_cid = crcx_info->x_osmo_osmux_cid;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100171 rtp_stream_update_id(rtps);
172 osmo_fsm_inst_dispatch(fi->proc.parent, CALL_LEG_EV_RTP_STREAM_ADDR_AVAILABLE, rtps);
173 check_established(rtps);
174
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100175 if ((!rtps->remote_sent_to_mgw || !rtps->codecs_sent_to_mgw)
Neels Hofmeyr84ce2062019-10-05 05:15:25 +0200176 && osmo_sockaddr_str_is_nonzero(&rtps->remote)
Pau Espin Pedrola3cdab42019-05-09 17:54:08 +0200177 && (!rtps->use_osmux || rtps->remote_osmux_cid_sent_to_mgw)
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100178 && rtps->codecs_known) {
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100179 LOG_RTPS(rtps, LOGL_DEBUG,
Pau Espin Pedrola3cdab42019-05-09 17:54:08 +0200180 "local ip:port set;%s%s%s triggering MDCX to send the new settings\n",
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100181 (!rtps->remote_sent_to_mgw) ? " remote ip:port not yet sent," : "",
182 (!rtps->codecs_sent_to_mgw) ? " codecs not yet sent," : "",
Pau Espin Pedrola3cdab42019-05-09 17:54:08 +0200183 (rtps->use_osmux && !rtps->remote_osmux_cid_sent_to_mgw) ? "Osmux CID not yet sent,": "");
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100184 rtp_stream_do_mdcx(rtps);
185 }
186 return;
187
188 case RTP_STREAM_EV_MDCX_OK:
189 rtp_stream_update_id(rtps);
190 check_established(rtps);
191 return;
192
193 case RTP_STREAM_EV_CRCX_FAIL:
194 case RTP_STREAM_EV_MDCX_FAIL:
195 rtps->remote_sent_to_mgw = false;
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100196 rtps->codecs_sent_to_mgw = false;
Pau Espin Pedrola3cdab42019-05-09 17:54:08 +0200197 rtps->remote_osmux_cid_sent_to_mgw = false;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100198 rtp_stream_update_id(rtps);
199 rtp_stream_state_chg(rtps, RTP_STREAM_ST_DISCARDING);
200 return;
201
202 default:
203 OSMO_ASSERT(false);
204 };
205}
206
207void rtp_stream_fsm_established_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
208{
209 struct rtp_stream *rtps = fi->priv;
210 osmo_fsm_inst_dispatch(fi->proc.parent, CALL_LEG_EV_RTP_STREAM_ESTABLISHED, rtps);
211}
212
213static int rtp_stream_fsm_timer_cb(struct osmo_fsm_inst *fi)
214{
215 struct rtp_stream *rtps = fi->priv;
216 rtp_stream_state_chg(rtps, RTP_STREAM_ST_DISCARDING);
217 return 0;
218}
219
220static void rtp_stream_fsm_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
221{
222 struct rtp_stream *rtps = fi->priv;
223 if (rtps->ci) {
Neels Hofmeyr523b92f2019-10-05 01:14:41 +0200224 osmo_mgcpc_ep_cancel_notify(osmo_mgcpc_ep_ci_ep(rtps->ci), fi);
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100225 osmo_mgcpc_ep_ci_dlcx(rtps->ci);
226 rtps->ci = NULL;
227 }
228}
229
230void rtp_stream_fsm_discarding_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
231{
232 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
233}
234
235static const struct value_string rtp_stream_fsm_event_names[] = {
236 OSMO_VALUE_STRING(RTP_STREAM_EV_CRCX_OK),
237 OSMO_VALUE_STRING(RTP_STREAM_EV_CRCX_FAIL),
238 OSMO_VALUE_STRING(RTP_STREAM_EV_MDCX_OK),
239 OSMO_VALUE_STRING(RTP_STREAM_EV_MDCX_FAIL),
240 {}
241};
242
243#define S(x) (1 << (x))
244
245static const struct osmo_fsm_state rtp_stream_fsm_states[] = {
246 [RTP_STREAM_ST_UNINITIALIZED] = {
247 .name = "UNINITIALIZED",
248 .out_state_mask = 0
249 | S(RTP_STREAM_ST_ESTABLISHING)
250 | S(RTP_STREAM_ST_DISCARDING)
251 ,
252 },
253 [RTP_STREAM_ST_ESTABLISHING] = {
254 .name = "ESTABLISHING",
255 .in_event_mask = 0
256 | S(RTP_STREAM_EV_CRCX_OK)
257 | S(RTP_STREAM_EV_CRCX_FAIL)
258 | S(RTP_STREAM_EV_MDCX_OK)
259 | S(RTP_STREAM_EV_MDCX_FAIL)
260 ,
261 .out_state_mask = 0
262 | S(RTP_STREAM_ST_ESTABLISHED)
263 | S(RTP_STREAM_ST_DISCARDING)
264 ,
265 .action = rtp_stream_fsm_establishing_established,
266 },
267 [RTP_STREAM_ST_ESTABLISHED] = {
268 .name = "ESTABLISHED",
269 .out_state_mask = 0
270 | S(RTP_STREAM_ST_ESTABLISHING)
271 | S(RTP_STREAM_ST_DISCARDING)
272 ,
273 .onenter = rtp_stream_fsm_established_onenter,
274 .action = rtp_stream_fsm_establishing_established,
275 },
276 [RTP_STREAM_ST_DISCARDING] = {
277 .name = "DISCARDING",
278 .onenter = rtp_stream_fsm_discarding_onenter,
279 .out_state_mask = 0
280 | S(RTP_STREAM_ST_DISCARDING)
281 ,
282 },
283};
284
285static struct osmo_fsm rtp_stream_fsm = {
286 .name = "rtp_stream",
287 .states = rtp_stream_fsm_states,
288 .num_states = ARRAY_SIZE(rtp_stream_fsm_states),
289 .log_subsys = DCC,
290 .event_names = rtp_stream_fsm_event_names,
291 .timer_cb = rtp_stream_fsm_timer_cb,
292 .cleanup = rtp_stream_fsm_cleanup,
293};
294
295static int rtp_stream_do_mgcp_verb(struct rtp_stream *rtps, enum mgcp_verb verb, uint32_t ok_event, uint32_t fail_event)
296{
297 struct mgcp_conn_peer verb_info;
298
299 if (!rtps->ci) {
300 LOG_RTPS(rtps, LOGL_ERROR, "Cannot send %s, no endpoint CI allocated\n", osmo_mgcp_verb_name(verb));
301 return -EINVAL;
302 }
303
304 verb_info = (struct mgcp_conn_peer){
305 .call_id = rtps->call_id,
306 .ptime = 20,
Pau Espin Pedrola3cdab42019-05-09 17:54:08 +0200307 .x_osmo_osmux_use = rtps->use_osmux,
308 .x_osmo_osmux_cid = rtps->remote_osmux_cid,
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100309 };
310
311 if (verb == MGCP_VERB_CRCX)
312 verb_info.conn_mode = rtps->crcx_conn_mode;
313
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100314 if (rtps->codecs_known) {
315 /* Send the list of codecs to the MGW. Ideally we would just feed the SDP directly, but for legacy
316 * reasons we still need to translate to a struct mgcp_conn_peer representation to send it. */
317 struct sdp_audio_codec *codec;
318 int i = 0;
319 foreach_sdp_audio_codec(codec, &rtps->codecs) {
320 const struct codec_mapping *m = codec_mapping_by_subtype_name(codec->subtype_name);
321 if (!m) {
322 LOG_RTPS(rtps, LOGL_ERROR, "Cannot map codec '%s' to MGCP: codec is unknown\n",
323 codec->subtype_name);
324 continue;
325 }
326 verb_info.codecs[i] = m->mgcp;
327 verb_info.ptmap[i] = (struct ptmap){
328 .codec = m->mgcp,
329 .pt = codec->payload_type,
330 };
331 i++;
332 verb_info.codecs_len = i;
333 verb_info.ptmap_len = i;
334 }
335 rtps->codecs_sent_to_mgw = true;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100336 }
Neels Hofmeyr84ce2062019-10-05 05:15:25 +0200337 if (osmo_sockaddr_str_is_nonzero(&rtps->remote)) {
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100338 int rc = osmo_strlcpy(verb_info.addr, rtps->remote.ip, sizeof(verb_info.addr));
339 if (rc <= 0 || rc >= sizeof(verb_info.addr)) {
340 LOG_RTPS(rtps, LOGL_ERROR, "Failure to write IP address to MGCP message (rc=%d)\n", rc);
341 return -ENOSPC;
342 }
343 verb_info.port = rtps->remote.port;
344 rtps->remote_sent_to_mgw = true;
345 }
Pau Espin Pedrolc0f94742023-03-15 12:53:13 +0100346 if (rtps->use_osmux && rtps->remote_osmux_cid >= 0)
347 rtps->remote_osmux_cid_sent_to_mgw = true;
Pau Espin Pedrola202cf42023-03-15 11:58:16 +0100348 rtp_stream_update_id(rtps);
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100349
350 osmo_mgcpc_ep_ci_request(rtps->ci, verb, &verb_info, rtps->fi, ok_event, fail_event, NULL);
351 return 0;
352}
353
354int rtp_stream_ensure_ci(struct rtp_stream *rtps, struct osmo_mgcpc_ep *at_endpoint)
355{
356 if (rtps->ci)
357 return rtp_stream_commit(rtps);
358
359 rtp_stream_state_chg(rtps, RTP_STREAM_ST_ESTABLISHING);
360
361 rtps->ci = osmo_mgcpc_ep_ci_add(at_endpoint, "%s", rtp_direction_name(rtps->dir));
362 if (!rtps->ci)
363 return -ENODEV;
364
365 return rtp_stream_do_mgcp_verb(rtps, MGCP_VERB_CRCX, RTP_STREAM_EV_CRCX_OK, RTP_STREAM_EV_CRCX_FAIL);
366}
367
368int rtp_stream_do_mdcx(struct rtp_stream *rtps)
369{
370 return rtp_stream_do_mgcp_verb(rtps, MGCP_VERB_MDCX, RTP_STREAM_EV_MDCX_OK, RTP_STREAM_EV_MDCX_FAIL);
371}
372
373void rtp_stream_release(struct rtp_stream *rtps)
374{
375 if (!rtps)
376 return;
377
378 rtp_stream_state_chg(rtps, RTP_STREAM_ST_DISCARDING);
379}
380
381/* After setting up a remote RTP address or a new codec, call this to trigger an MDCX.
382 * The MDCX will only trigger if all data needed by an endpoint is available (both RTP address and codec) and if at
383 * least one of them has not yet been sent to the MGW in a previous CRCX or MDCX. */
384int rtp_stream_commit(struct rtp_stream *rtps)
385{
Neels Hofmeyr84ce2062019-10-05 05:15:25 +0200386 if (!osmo_sockaddr_str_is_nonzero(&rtps->remote)) {
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100387 LOG_RTPS(rtps, LOGL_DEBUG, "Not committing: no remote RTP address known\n");
388 return -1;
389 }
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100390 if (!rtps->codecs_known) {
391 LOG_RTPS(rtps, LOGL_DEBUG, "Not committing: no codecs known\n");
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100392 return -1;
393 }
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100394 if (rtps->remote_sent_to_mgw && rtps->codecs_sent_to_mgw) {
395 LOG_RTPS(rtps, LOGL_DEBUG, "Not committing: both remote RTP address and codecs already set up at MGW\n");
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100396 return 0;
397 }
Neels Hofmeyra899dea2022-10-31 18:15:32 +0100398 if (!rtps->ci) {
399 LOG_RTPS(rtps, LOGL_DEBUG, "Not committing: no MGW endpoint CI set up\n");
400 return -1;
401 }
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100402
Pau Espin Pedrola3cdab42019-05-09 17:54:08 +0200403 LOG_RTPS(rtps, LOGL_DEBUG, "Committing: Tx MDCX to update the MGW: updating%s%s%s\n",
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100404 rtps->remote_sent_to_mgw ? "" : " remote-RTP-IP-port",
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100405 rtps->codecs_sent_to_mgw ? "" : " codecs",
Pau Espin Pedrola3cdab42019-05-09 17:54:08 +0200406 (!rtps->use_osmux || rtps->remote_osmux_cid_sent_to_mgw) ? "" : " remote-Osmux-CID");
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100407 return rtp_stream_do_mdcx(rtps);
408}
409
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100410void rtp_stream_set_codecs(struct rtp_stream *rtps, const struct sdp_audio_codecs *codecs)
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100411{
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100412 if (!codecs || !codecs->count)
413 return;
414 if (sdp_audio_codecs_cmp(&rtps->codecs, codecs, false, true) == 0) {
415 LOG_RTPS(rtps, LOGL_DEBUG, "no change: codecs already set to %s\n",
416 sdp_audio_codecs_to_str(&rtps->codecs));
417 return;
418 }
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100419 if (rtps->fi->state == RTP_STREAM_ST_ESTABLISHED)
420 rtp_stream_state_chg(rtps, RTP_STREAM_ST_ESTABLISHING);
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100421 LOG_RTPS(rtps, LOGL_DEBUG, "setting codecs to %s\n", sdp_audio_codecs_to_str(codecs));
422 rtps->codecs = *codecs;
423 rtps->codecs_known = true;
424 rtps->codecs_sent_to_mgw = false;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100425 rtp_stream_update_id(rtps);
426}
427
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100428/* Convenience shortcut to call rtp_stream_set_codecs() with a list of only one sdp_audio_codec record. */
429void rtp_stream_set_one_codec(struct rtp_stream *rtps, const struct sdp_audio_codec *codec)
430{
431 struct sdp_audio_codecs codecs = {};
432 sdp_audio_codecs_add_copy(&codecs, codec);
433 rtp_stream_set_codecs(rtps, &codecs);
434}
435
436/* For legacy, rather use rtp_stream_set_codecs() with a full codecs list. */
437bool rtp_stream_set_codecs_from_mgcp_codec(struct rtp_stream *rtps, enum mgcp_codecs codec)
438{
439 struct sdp_audio_codecs codecs = {};
440 if (!sdp_audio_codecs_add_mgcp_codec(&codecs, codec))
441 return false;
442 rtp_stream_set_codecs(rtps, &codecs);
443 return true;
444}
445
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100446void rtp_stream_set_remote_addr(struct rtp_stream *rtps, const struct osmo_sockaddr_str *r)
447{
Neels Hofmeyr91c9c2f2022-10-31 18:21:16 +0100448 if (osmo_sockaddr_str_cmp(&rtps->remote, r) == 0) {
449 LOG_RTPS(rtps, LOGL_DEBUG, "remote addr already " OSMO_SOCKADDR_STR_FMT ", no change\n",
450 OSMO_SOCKADDR_STR_FMT_ARGS(r));
451 return;
452 }
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100453 if (rtps->fi->state == RTP_STREAM_ST_ESTABLISHED)
454 rtp_stream_state_chg(rtps, RTP_STREAM_ST_ESTABLISHING);
455 LOG_RTPS(rtps, LOGL_DEBUG, "setting remote addr to " OSMO_SOCKADDR_STR_FMT "\n", OSMO_SOCKADDR_STR_FMT_ARGS(r));
456 rtps->remote = *r;
457 rtps->remote_sent_to_mgw = false;
458 rtp_stream_update_id(rtps);
459}
460
Neels Hofmeyr8dd16462022-01-13 20:06:53 +0100461void rtp_stream_set_remote_addr_and_codecs(struct rtp_stream *rtps, const struct sdp_msg *sdp)
462{
463 rtp_stream_set_codecs(rtps, &sdp->audio_codecs);
464 if (osmo_sockaddr_str_is_nonzero(&sdp->rtp))
465 rtp_stream_set_remote_addr(rtps, &sdp->rtp);
466}
467
Pau Espin Pedrola3cdab42019-05-09 17:54:08 +0200468void rtp_stream_set_remote_osmux_cid(struct rtp_stream *rtps, uint8_t osmux_cid)
469{
470 if (rtps->fi->state == RTP_STREAM_ST_ESTABLISHED)
471 rtp_stream_state_chg(rtps, RTP_STREAM_ST_ESTABLISHING);
472 LOG_RTPS(rtps, LOGL_DEBUG, "setting remote Osmux CID to %u\n", osmux_cid);
473 rtps->remote_osmux_cid = osmux_cid;
474 rtps->remote_osmux_cid_sent_to_mgw = false;
475 rtp_stream_update_id(rtps);
476}
477
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100478bool rtp_stream_is_established(struct rtp_stream *rtps)
479{
480 if (!rtps)
481 return false;
482 if (!rtps->fi)
483 return false;
484 if (rtps->fi->state != RTP_STREAM_ST_ESTABLISHED)
485 return false;
486 if (!rtps->remote_sent_to_mgw
Neels Hofmeyr62bfa372022-10-31 18:51:07 +0100487 || !rtps->codecs_sent_to_mgw
Pau Espin Pedrola3cdab42019-05-09 17:54:08 +0200488 || (rtps->use_osmux && !rtps->remote_osmux_cid_sent_to_mgw))
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100489 return false;
490 return true;
491}