Skip to main content

ringo_core/
backend.rs

1use std::sync::mpsc::Receiver;
2
3use anyhow::Result;
4
5use crate::account::{Account, BackendOptions};
6use crate::event::{AppEvent, InviteHeaders};
7use crate::phone::Phone;
8
9pub use crate::baresip::BaresipBackend;
10pub use crate::baresip::call_count;
11pub use crate::baresip::is_registered;
12pub use crate::baresip::received_audio;
13pub use crate::baresip::sent_audio;
14pub use crate::baresip::{AudioFrame, push_audio, start_audio_stream, subscribe_received_audio};
15pub use crate::baresip::{sip_trace_file, sip_trace_stderr};
16
17/// Shut down the backend's global runtime: hang up calls, tear down the user
18/// agents, stop the event loop and join its thread. Call once at process exit;
19/// a no-op if the backend was never started. Agnostic façade over the concrete
20/// backend's teardown (the FFI backend stops its libre event thread here).
21pub fn shutdown() {
22    crate::baresip::stop_re_thread();
23}
24
25/// A backend provides SIP user-agent functionality — library init, event
26/// translation and the phone command interface. The FFI backend links
27/// libbaresip directly (statically with `vendored`, or dynamically via
28/// pkg-config).
29pub trait Backend: Send {
30    /// Spawn the backend (process or library), start I/O tasks on `rt`, and
31    /// return a [`Session`] handle. The session owns the event stream, phone
32    /// command interface, and optional header-polling closure. Connect retry
33    /// happens internally; `AppEvent::BackendConnectFailed` lands in the event
34    /// stream on failure.
35    fn spawn_session(
36        &self,
37        rt: &tokio::runtime::Handle,
38        name: &str,
39        account: &Account,
40        options: &BackendOptions,
41    ) -> Result<Session>;
42}
43
44/// A live backend session. Dropping this tears down the backend (stops the
45/// process / closes the library) and cleans up resources.
46pub struct Session {
47    /// Event stream (already translated to backend-neutral `AppEvent`s).
48    pub events: Receiver<AppEvent>,
49    /// Phone command interface.
50    pub phone: Box<dyn Phone>,
51    /// Poll for inbound INVITE headers. Returns `None` when there is nothing
52    /// new; `Some(headers)` when new headers have been parsed. `None` on the
53    /// closure itself means the backend exposes headers directly in events
54    /// (no trace polling needed).
55    pub header_poll: Option<Box<dyn Fn() -> Option<InviteHeaders> + Send + Sync>>,
56    /// Opaque handle — drop ends the backend session + cleanup.
57    pub handle: Box<dyn Send>,
58}
59
60impl Session {
61    pub fn new(
62        events: Receiver<AppEvent>,
63        phone: Box<dyn Phone>,
64        header_poll: Option<Box<dyn Fn() -> Option<InviteHeaders> + Send + Sync>>,
65        handle: Box<dyn Send>,
66    ) -> Self {
67        Self {
68            events,
69            phone,
70            header_poll,
71            handle,
72        }
73    }
74}