1use crate::ids::{BridgeId, ConnectionId};
15use dashmap::DashMap;
16use std::hash::Hash;
17use std::sync::Arc;
18
19pub use rvoip_media_core::relay::controller::{BridgeError, BridgeHandle};
20
21pub mod cross_handle;
22pub mod frame_pump;
23
24pub use cross_handle::CrossBridgeHandle;
25
26#[derive(Clone, Copy, Debug, Eq, PartialEq)]
33pub struct DirectionalMediaBridgePlan {
34 a_to_b: bool,
35 b_to_a: bool,
36}
37
38impl DirectionalMediaBridgePlan {
39 pub fn new(a_to_b: bool, b_to_a: bool) -> crate::Result<Self> {
42 if !a_to_b && !b_to_a {
43 return Err(crate::RvoipError::AdmissionRejected(
44 "media bridge must enable at least one direction",
45 ));
46 }
47 Ok(Self { a_to_b, b_to_a })
48 }
49
50 #[must_use]
51 pub const fn bidirectional() -> Self {
52 Self {
53 a_to_b: true,
54 b_to_a: true,
55 }
56 }
57
58 #[must_use]
59 pub const fn a_to_b(self) -> bool {
60 self.a_to_b
61 }
62
63 #[must_use]
64 pub const fn b_to_a(self) -> bool {
65 self.b_to_a
66 }
67}
68
69pub fn codec_to_pt(name: &str) -> Option<u8> {
81 match name.to_ascii_lowercase().as_str() {
82 "pcmu" | "g.711-mu" | "g711-mu" | "g711-u" => Some(0),
83 "pcma" | "g.711-a" | "g711-a" => Some(8),
84 "g729" | "g.729" => Some(18),
85 "opus" => Some(111),
86 "pcm_s16le" | "pcm-s16le" => Some(rvoip_media_core::codec::audio::payload_type::PCM_S16LE),
87 _ => None,
88 }
89}
90
91#[cfg(test)]
92mod codec_mapping_tests {
93 use super::codec_to_pt;
94 use rvoip_media_core::codec::audio::payload_type::PCM_S16LE;
95
96 #[test]
97 fn maps_internal_pcm_name_to_reserved_key() {
98 assert_eq!(codec_to_pt("pcm_s16le"), Some(PCM_S16LE));
99 assert_eq!(codec_to_pt("PCM_S16LE"), Some(PCM_S16LE));
100 assert_eq!(PCM_S16LE, 120);
101 }
102}
103
104pub struct BridgeManager<K = ConnectionId, I = BridgeId>
119where
120 K: Eq + Hash + Clone,
121 I: Eq + Hash + Clone,
122{
123 bridges: Arc<DashMap<I, (BridgeHandle, K)>>,
124 by_owner: Arc<DashMap<K, I>>,
125}
126
127impl<K, I> Clone for BridgeManager<K, I>
128where
129 K: Eq + Hash + Clone,
130 I: Eq + Hash + Clone,
131{
132 fn clone(&self) -> Self {
133 Self {
134 bridges: Arc::clone(&self.bridges),
135 by_owner: Arc::clone(&self.by_owner),
136 }
137 }
138}
139
140impl<K, I> Default for BridgeManager<K, I>
141where
142 K: Eq + Hash + Clone,
143 I: Eq + Hash + Clone,
144{
145 fn default() -> Self {
146 Self::new()
147 }
148}
149
150impl<K, I> BridgeManager<K, I>
151where
152 K: Eq + Hash + Clone,
153 I: Eq + Hash + Clone,
154{
155 pub fn new() -> Self {
156 Self {
157 bridges: Arc::new(DashMap::new()),
158 by_owner: Arc::new(DashMap::new()),
159 }
160 }
161
162 pub fn insert(&self, bridge_id: I, owner: K, handle: BridgeHandle) {
163 self.by_owner.insert(owner.clone(), bridge_id.clone());
164 self.bridges.insert(bridge_id, (handle, owner));
165 }
166
167 pub fn remove(&self, bridge_id: &I) -> Option<BridgeHandle> {
170 let (_, (handle, owner)) = self.bridges.remove(bridge_id)?;
171 self.by_owner
172 .remove_if(&owner, |_, registered| registered == bridge_id);
173 Some(handle)
174 }
175
176 pub fn bridge_for_owner(&self, owner: &K) -> Option<I> {
178 self.by_owner.get(owner).map(|entry| entry.value().clone())
179 }
180
181 pub fn len(&self) -> usize {
182 self.bridges.len()
183 }
184
185 pub fn is_empty(&self) -> bool {
186 self.bridges.is_empty()
187 }
188}