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