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