1#![deny(missing_docs)]
53
54use async_trait::async_trait;
55use std::collections::{HashMap, HashSet, VecDeque};
56use std::future::Future;
57use std::pin::Pin;
58use std::sync::Arc;
59use std::time::Duration;
60
61use crate::api::dialog_package::{DialogInfo, DialogInfoDocument};
62use crate::api::endpoint::SipAccount;
63use crate::api::events::{
64 Event, MediaSecurityState, SipTrace, SubscriptionState, TransferTargetEvidence,
65};
66use crate::api::handle::{CallId, SessionHandle};
67use crate::api::incoming::{IncomingCall, IncomingCallGuard};
68use crate::api::performance::PerformanceConfig;
69use crate::api::unified::{
70 Config, MediaMode, MediaSessionControllerConfig, RegistrationHandle, RtpSessionBufferConfig,
71 RtpTransportBufferConfig, UnifiedCoordinator,
72};
73use crate::auth::SipClientAuth;
74use crate::cleanup_diag::{self, CleanupStage};
75use crate::errors::{Result, SessionError};
76
77#[derive(Clone)]
84pub struct ShutdownHandle {
85 tx: tokio::sync::watch::Sender<bool>,
86}
87
88impl ShutdownHandle {
89 pub fn shutdown(&self) {
100 let _ = self.tx.send(true);
101 }
102
103 pub(crate) fn from_sender(tx: tokio::sync::watch::Sender<bool>) -> Self {
108 Self { tx }
109 }
110}
111
112pub enum CallHandlerDecision {
116 Accept,
118 AcceptWithSdp(String),
120 Reject {
122 status: u16,
124 reason: String,
126 },
127 Redirect(String),
129 Defer(IncomingCallGuard),
131}
132
133#[derive(Debug, Clone)]
137pub enum EndReason {
138 Normal,
140 Rejected,
142 Timeout,
144 NetworkError,
146 Other(String),
148}
149
150impl From<String> for EndReason {
151 fn from(s: String) -> Self {
152 match s.to_lowercase().as_str() {
153 r if r.contains("timeout") => EndReason::Timeout,
154 r if r.contains("reject") || r.contains("decline") || r.contains("busy") => {
155 EndReason::Rejected
156 }
157 r if r.contains("network") || r.contains("transport") => EndReason::NetworkError,
158 _ => EndReason::Other(s),
159 }
160 }
161}
162
163type CallbackFuture<T> = Pin<Box<dyn Future<Output = T> + Send>>;
164type EventHook = Arc<dyn Fn(Event) -> CallbackFuture<Result<()>> + Send + Sync>;
165type IncomingHook = Arc<dyn Fn(IncomingCall) -> CallbackFuture<CallHandlerDecision> + Send + Sync>;
166type EstablishedHook = Arc<dyn Fn(SessionHandle) -> CallbackFuture<Result<()>> + Send + Sync>;
167type ProgressHook = Arc<
168 dyn Fn(SessionHandle, u16, String, Option<String>) -> CallbackFuture<Result<()>> + Send + Sync,
169>;
170type DtmfHook = Arc<dyn Fn(SessionHandle, char) -> CallbackFuture<Result<()>> + Send + Sync>;
171type EndedHook = Arc<dyn Fn(CallId, EndReason) -> CallbackFuture<Result<()>> + Send + Sync>;
172type FailedHook = Arc<dyn Fn(CallId, u16, String) -> CallbackFuture<Result<()>> + Send + Sync>;
173type CancelledHook = Arc<dyn Fn(CallId) -> CallbackFuture<Result<()>> + Send + Sync>;
174type MediaSecurityHook =
175 Arc<dyn Fn(SessionHandle, MediaSecurityState) -> CallbackFuture<Result<()>> + Send + Sync>;
176type HoldHook = Arc<dyn Fn(SessionHandle) -> CallbackFuture<Result<()>> + Send + Sync>;
177type ReferReceivedHook = Arc<
178 dyn Fn(SessionHandle, crate::api::incoming::IncomingRequest) -> CallbackFuture<Result<bool>>
179 + Send
180 + Sync,
181>;
182type TransferAcceptedHook =
183 Arc<dyn Fn(SessionHandle, String) -> CallbackFuture<Result<()>> + Send + Sync>;
184type ReferProgressHook =
185 Arc<dyn Fn(SessionHandle, u16, String) -> CallbackFuture<Result<()>> + Send + Sync>;
186type ReferCompletedHook =
187 Arc<dyn Fn(SessionHandle, String, u16, String) -> CallbackFuture<Result<()>> + Send + Sync>;
188type TransferFailedHook =
189 Arc<dyn Fn(SessionHandle, u16, String) -> CallbackFuture<Result<()>> + Send + Sync>;
190type RegistrationSuccessHook =
191 Arc<dyn Fn(String, u32, String) -> CallbackFuture<Result<()>> + Send + Sync>;
192type RegistrationFailedHook =
193 Arc<dyn Fn(String, u16, String) -> CallbackFuture<Result<()>> + Send + Sync>;
194type UnregistrationSuccessHook = Arc<dyn Fn(String) -> CallbackFuture<Result<()>> + Send + Sync>;
195type UnregistrationFailedHook =
196 Arc<dyn Fn(String, String) -> CallbackFuture<Result<()>> + Send + Sync>;
197type SipTraceHook = Arc<dyn Fn(SipTrace) -> CallbackFuture<Result<()>> + Send + Sync>;
198
199pub struct CallbackPeerBuilder {
204 config: Config,
205 event: Option<EventHook>,
206 incoming: Option<IncomingHook>,
207 established: Option<EstablishedHook>,
208 progress: Option<ProgressHook>,
209 dtmf: Option<DtmfHook>,
210 ended: Option<EndedHook>,
211 failed: Option<FailedHook>,
212 cancelled: Option<CancelledHook>,
213 media_security: Option<MediaSecurityHook>,
214 local_hold: Option<HoldHook>,
215 local_resume: Option<HoldHook>,
216 remote_hold: Option<HoldHook>,
217 remote_resume: Option<HoldHook>,
218 refer_received: Option<ReferReceivedHook>,
219 transfer_accepted: Option<TransferAcceptedHook>,
220 refer_progress: Option<ReferProgressHook>,
221 refer_completed: Option<ReferCompletedHook>,
222 transfer_failed: Option<TransferFailedHook>,
223 registration_success: Option<RegistrationSuccessHook>,
224 registration_failed: Option<RegistrationFailedHook>,
225 unregistration_success: Option<UnregistrationSuccessHook>,
226 unregistration_failed: Option<UnregistrationFailedHook>,
227 sip_trace: Option<SipTraceHook>,
228}
229
230impl CallbackPeerBuilder {
231 pub fn new(config: Config) -> Self {
233 Self {
234 config,
235 event: None,
236 incoming: None,
237 established: None,
238 progress: None,
239 dtmf: None,
240 ended: None,
241 failed: None,
242 cancelled: None,
243 media_security: None,
244 local_hold: None,
245 local_resume: None,
246 remote_hold: None,
247 remote_resume: None,
248 refer_received: None,
249 transfer_accepted: None,
250 refer_progress: None,
251 refer_completed: None,
252 transfer_failed: None,
253 registration_success: None,
254 registration_failed: None,
255 unregistration_success: None,
256 unregistration_failed: None,
257 sip_trace: None,
258 }
259 }
260
261 pub fn with_auth(mut self, auth: SipClientAuth) -> Self {
266 self.config.auth = Some(auth);
267 self
268 }
269
270 pub fn with_credentials(
275 mut self,
276 username: impl Into<String>,
277 password: impl Into<String>,
278 ) -> Self {
279 self.config.credentials = Some(crate::types::Credentials::new(username, password));
280 self
281 }
282
283 pub fn with_bearer_token(mut self, token: impl Into<String>) -> Self {
285 self.config.auth = Some(SipClientAuth::bearer_token(token));
286 self
287 }
288
289 pub fn with_basic_credentials(
294 mut self,
295 username: impl Into<String>,
296 password: impl Into<String>,
297 ) -> Self {
298 self.config.auth = Some(SipClientAuth::basic(username, password));
299 self
300 }
301
302 pub fn on_event<F, Fut>(mut self, f: F) -> Self
304 where
305 F: Fn(Event) -> Fut + Send + Sync + 'static,
306 Fut: Future<Output = Result<()>> + Send + 'static,
307 {
308 self.event = Some(Arc::new(move |event| Box::pin(f(event))));
309 self
310 }
311
312 pub fn auto_180_ringing(mut self, enabled: bool) -> Self {
314 self.config = self.config.with_auto_180_ringing(enabled);
315 self
316 }
317
318 pub fn auto_100_trying(mut self, enabled: bool) -> Self {
320 self.config = self.config.with_auto_100_trying(enabled);
321 self
322 }
323
324 pub fn fast_auto_accept_incoming_calls(mut self, enabled: bool) -> Self {
326 self.config = self.config.with_fast_auto_accept_incoming_calls(enabled);
327 self
328 }
329
330 pub fn media_enabled(mut self, enabled: bool) -> Self {
332 self.config = self.config.with_media_enabled(enabled);
333 self
334 }
335
336 pub fn signaling_only_media(mut self, sdp_rtp_port: u16) -> Self {
338 self.config = self
339 .config
340 .with_media_mode(MediaMode::SignalingOnly { sdp_rtp_port });
341 self
342 }
343
344 pub fn media_port_capacity(mut self, start: u16, capacity: usize) -> Self {
346 self.config = self.config.with_media_port_capacity(start, capacity);
347 self
348 }
349
350 pub fn media_session_capacity(mut self, capacity: usize) -> Self {
352 self.config = self.config.with_media_session_capacity(capacity);
353 self
354 }
355
356 pub fn rtp_session_buffer_config(mut self, config: RtpSessionBufferConfig) -> Self {
358 self.config = self.config.with_rtp_session_buffer_config(config);
359 self
360 }
361
362 pub fn rtp_transport_buffer_config(mut self, config: RtpTransportBufferConfig) -> Self {
364 self.config = self.config.with_rtp_transport_buffer_config(config);
365 self
366 }
367
368 pub fn media_session_controller_config(mut self, config: MediaSessionControllerConfig) -> Self {
370 self.config = self.config.with_media_session_controller_config(config);
371 self
372 }
373
374 pub fn high_cps_udp_auto_answer(mut self, capacity: usize) -> Self {
376 self.config = self.config.with_high_cps_udp_auto_answer(capacity);
377 self
378 }
379
380 pub fn performance_config(mut self, performance: PerformanceConfig) -> Result<Self> {
382 self.config = self.config.try_with_performance_config(performance)?;
383 Ok(self)
384 }
385
386 pub fn pbx_media_server_performance(mut self, capacity: usize) -> Self {
388 self.config = self.config.with_pbx_media_server_performance(capacity);
389 self
390 }
391
392 pub fn signaling_only_server_high_performance(
394 mut self,
395 capacity: usize,
396 sdp_rtp_port: u16,
397 ) -> Self {
398 self.config = self
399 .config
400 .with_signaling_only_server_high_performance(capacity, sdp_rtp_port);
401 self
402 }
403
404 pub fn app_event_channel_capacity(mut self, capacity: usize) -> Self {
406 self.config = self.config.with_app_event_channel_capacity(capacity);
407 self
408 }
409
410 pub fn sip_udp_parse_workers(mut self, workers: usize) -> Self {
412 self.config = self.config.with_sip_udp_parse_workers(workers);
413 self
414 }
415
416 pub fn sip_udp_parse_queue_capacity(mut self, capacity: usize) -> Self {
418 self.config = self.config.with_sip_udp_parse_queue_capacity(capacity);
419 self
420 }
421
422 pub fn sip_transaction_command_channel_capacity(mut self, capacity: usize) -> Self {
424 self.config = self
425 .config
426 .with_sip_transaction_command_channel_capacity(capacity);
427 self
428 }
429
430 pub fn server_call_admission_limit(mut self, limit: usize) -> Self {
432 self.config = self.config.with_server_call_admission_limit(limit);
433 self
434 }
435
436 pub fn server_call_admission_soft_limit(mut self, limit: usize) -> Self {
438 self.config = self.config.with_server_call_admission_soft_limit(limit);
439 self
440 }
441
442 pub fn server_call_admission_pacing_delay_ms(mut self, delay_ms: u64) -> Self {
444 self.config = self
445 .config
446 .with_server_call_admission_pacing_delay_ms(delay_ms);
447 self
448 }
449
450 pub fn server_overload_retry_after_secs(mut self, seconds: u32) -> Self {
452 self.config = self.config.with_server_overload_retry_after_secs(seconds);
453 self
454 }
455
456 pub fn sip_udp_diagnostics(mut self, enabled: bool) -> Self {
458 self.config = self.config.with_sip_udp_diagnostics(enabled);
459 self
460 }
461
462 pub fn media_setup_diagnostics(mut self, enabled: bool) -> Self {
464 self.config = self.config.with_media_setup_diagnostics(enabled);
465 self
466 }
467
468 pub fn cleanup_diagnostics(mut self, enabled: bool) -> Self {
470 self.config = self.config.with_cleanup_diagnostics(enabled);
471 self
472 }
473
474 pub fn cleanup_diagnostic_events(mut self, enabled: bool) -> Self {
476 self.config = self.config.with_cleanup_diagnostic_events(enabled);
477 self
478 }
479
480 #[cfg(feature = "perf-tests")]
482 pub fn perf_max_rss_growth_mb_per_hr(mut self, limit: f64) -> Self {
483 self.config = self.config.with_perf_max_rss_growth_mb_per_hr(limit);
484 self
485 }
486
487 pub fn srtp_diagnostics(mut self, enabled: bool) -> Self {
489 self.config = self.config.with_srtp_diagnostics(enabled);
490 self
491 }
492
493 pub fn rtp_diagnostics(mut self, enabled: bool) -> Self {
495 self.config = self.config.with_rtp_diagnostics(enabled);
496 self
497 }
498
499 pub fn media_sdp_diagnostics(mut self, enabled: bool) -> Self {
501 self.config = self.config.with_media_sdp_diagnostics(enabled);
502 self
503 }
504
505 pub fn on_incoming<F, Fut>(mut self, f: F) -> Self
510 where
511 F: Fn(IncomingCall) -> Fut + Send + Sync + 'static,
512 Fut: Future<Output = CallHandlerDecision> + Send + 'static,
513 {
514 self.incoming = Some(Arc::new(move |call| Box::pin(f(call))));
515 self
516 }
517
518 pub fn on_established<F, Fut>(mut self, f: F) -> Self
520 where
521 F: Fn(SessionHandle) -> Fut + Send + Sync + 'static,
522 Fut: Future<Output = Result<()>> + Send + 'static,
523 {
524 self.established = Some(Arc::new(move |handle| Box::pin(f(handle))));
525 self
526 }
527
528 pub fn on_progress<F, Fut>(mut self, f: F) -> Self
530 where
531 F: Fn(SessionHandle, u16, String, Option<String>) -> Fut + Send + Sync + 'static,
532 Fut: Future<Output = Result<()>> + Send + 'static,
533 {
534 self.progress = Some(Arc::new(move |handle, status, reason, sdp| {
535 Box::pin(f(handle, status, reason, sdp))
536 }));
537 self
538 }
539
540 pub fn on_dtmf<F, Fut>(mut self, f: F) -> Self
542 where
543 F: Fn(SessionHandle, char) -> Fut + Send + Sync + 'static,
544 Fut: Future<Output = Result<()>> + Send + 'static,
545 {
546 self.dtmf = Some(Arc::new(move |handle, digit| Box::pin(f(handle, digit))));
547 self
548 }
549
550 pub fn on_failed<F, Fut>(mut self, f: F) -> Self
552 where
553 F: Fn(CallId, u16, String) -> Fut + Send + Sync + 'static,
554 Fut: Future<Output = Result<()>> + Send + 'static,
555 {
556 self.failed = Some(Arc::new(move |call_id, status, reason| {
557 Box::pin(f(call_id, status, reason))
558 }));
559 self
560 }
561
562 pub fn on_cancelled<F, Fut>(mut self, f: F) -> Self
564 where
565 F: Fn(CallId) -> Fut + Send + Sync + 'static,
566 Fut: Future<Output = Result<()>> + Send + 'static,
567 {
568 self.cancelled = Some(Arc::new(move |call_id| Box::pin(f(call_id))));
569 self
570 }
571
572 pub fn on_media_security<F, Fut>(mut self, f: F) -> Self
574 where
575 F: Fn(SessionHandle, MediaSecurityState) -> Fut + Send + Sync + 'static,
576 Fut: Future<Output = Result<()>> + Send + 'static,
577 {
578 self.media_security = Some(Arc::new(move |handle, state| Box::pin(f(handle, state))));
579 self
580 }
581
582 pub fn on_local_hold<F, Fut>(mut self, f: F) -> Self
584 where
585 F: Fn(SessionHandle) -> Fut + Send + Sync + 'static,
586 Fut: Future<Output = Result<()>> + Send + 'static,
587 {
588 self.local_hold = Some(Arc::new(move |handle| Box::pin(f(handle))));
589 self
590 }
591
592 pub fn on_local_resume<F, Fut>(mut self, f: F) -> Self
594 where
595 F: Fn(SessionHandle) -> Fut + Send + Sync + 'static,
596 Fut: Future<Output = Result<()>> + Send + 'static,
597 {
598 self.local_resume = Some(Arc::new(move |handle| Box::pin(f(handle))));
599 self
600 }
601
602 pub fn on_remote_hold<F, Fut>(mut self, f: F) -> Self
604 where
605 F: Fn(SessionHandle) -> Fut + Send + Sync + 'static,
606 Fut: Future<Output = Result<()>> + Send + 'static,
607 {
608 self.remote_hold = Some(Arc::new(move |handle| Box::pin(f(handle))));
609 self
610 }
611
612 pub fn on_remote_resume<F, Fut>(mut self, f: F) -> Self
614 where
615 F: Fn(SessionHandle) -> Fut + Send + Sync + 'static,
616 Fut: Future<Output = Result<()>> + Send + 'static,
617 {
618 self.remote_resume = Some(Arc::new(move |handle| Box::pin(f(handle))));
619 self
620 }
621
622 pub fn on_ended<F, Fut>(mut self, f: F) -> Self
624 where
625 F: Fn(CallId, EndReason) -> Fut + Send + Sync + 'static,
626 Fut: Future<Output = Result<()>> + Send + 'static,
627 {
628 self.ended = Some(Arc::new(move |call_id, reason| {
629 Box::pin(f(call_id, reason))
630 }));
631 self
632 }
633
634 pub fn on_refer_received<F, Fut>(mut self, f: F) -> Self
644 where
645 F: Fn(SessionHandle, crate::api::incoming::IncomingRequest) -> Fut + Send + Sync + 'static,
646 Fut: Future<Output = Result<bool>> + Send + 'static,
647 {
648 self.refer_received = Some(Arc::new(move |handle, req| Box::pin(f(handle, req))));
649 self
650 }
651
652 pub fn on_transfer_accepted<F, Fut>(mut self, f: F) -> Self
654 where
655 F: Fn(SessionHandle, String) -> Fut + Send + Sync + 'static,
656 Fut: Future<Output = Result<()>> + Send + 'static,
657 {
658 self.transfer_accepted = Some(Arc::new(move |handle, refer_to| {
659 Box::pin(f(handle, refer_to))
660 }));
661 self
662 }
663
664 pub fn on_refer_progress<F, Fut>(mut self, f: F) -> Self
666 where
667 F: Fn(SessionHandle, u16, String) -> Fut + Send + Sync + 'static,
668 Fut: Future<Output = Result<()>> + Send + 'static,
669 {
670 self.refer_progress = Some(Arc::new(move |handle, status, reason| {
671 Box::pin(f(handle, status, reason))
672 }));
673 self
674 }
675
676 pub fn on_refer_completed<F, Fut>(mut self, f: F) -> Self
678 where
679 F: Fn(SessionHandle, String, u16, String) -> Fut + Send + Sync + 'static,
680 Fut: Future<Output = Result<()>> + Send + 'static,
681 {
682 self.refer_completed = Some(Arc::new(move |handle, target, status, reason| {
683 Box::pin(f(handle, target, status, reason))
684 }));
685 self
686 }
687
688 pub fn on_transfer_failed<F, Fut>(mut self, f: F) -> Self
690 where
691 F: Fn(SessionHandle, u16, String) -> Fut + Send + Sync + 'static,
692 Fut: Future<Output = Result<()>> + Send + 'static,
693 {
694 self.transfer_failed = Some(Arc::new(move |handle, status, reason| {
695 Box::pin(f(handle, status, reason))
696 }));
697 self
698 }
699
700 pub fn on_registration_success<F, Fut>(mut self, f: F) -> Self
702 where
703 F: Fn(String, u32, String) -> Fut + Send + Sync + 'static,
704 Fut: Future<Output = Result<()>> + Send + 'static,
705 {
706 self.registration_success = Some(Arc::new(move |registrar, expires, contact| {
707 Box::pin(f(registrar, expires, contact))
708 }));
709 self
710 }
711
712 pub fn on_registration_failed<F, Fut>(mut self, f: F) -> Self
714 where
715 F: Fn(String, u16, String) -> Fut + Send + Sync + 'static,
716 Fut: Future<Output = Result<()>> + Send + 'static,
717 {
718 self.registration_failed = Some(Arc::new(move |registrar, status, reason| {
719 Box::pin(f(registrar, status, reason))
720 }));
721 self
722 }
723
724 pub fn on_unregistration_success<F, Fut>(mut self, f: F) -> Self
726 where
727 F: Fn(String) -> Fut + Send + Sync + 'static,
728 Fut: Future<Output = Result<()>> + Send + 'static,
729 {
730 self.unregistration_success = Some(Arc::new(move |registrar| Box::pin(f(registrar))));
731 self
732 }
733
734 pub fn on_unregistration_failed<F, Fut>(mut self, f: F) -> Self
736 where
737 F: Fn(String, String) -> Fut + Send + Sync + 'static,
738 Fut: Future<Output = Result<()>> + Send + 'static,
739 {
740 self.unregistration_failed = Some(Arc::new(move |registrar, reason| {
741 Box::pin(f(registrar, reason))
742 }));
743 self
744 }
745
746 pub fn on_sip_trace<F, Fut>(mut self, f: F) -> Self
748 where
749 F: Fn(SipTrace) -> Fut + Send + Sync + 'static,
750 Fut: Future<Output = Result<()>> + Send + 'static,
751 {
752 self.sip_trace = Some(Arc::new(move |trace| Box::pin(f(trace))));
753 self
754 }
755
756 pub async fn build(self) -> Result<CallbackPeer<CallbackBuilderHandler>> {
758 let incoming = self.incoming.ok_or_else(|| {
759 SessionError::ConfigError(
760 "CallbackPeer::builder requires an on_incoming hook".to_string(),
761 )
762 })?;
763 CallbackPeer::new(
764 CallbackBuilderHandler {
765 event: self.event,
766 incoming,
767 established: self.established,
768 progress: self.progress,
769 dtmf: self.dtmf,
770 ended: self.ended,
771 failed: self.failed,
772 cancelled: self.cancelled,
773 media_security: self.media_security,
774 local_hold: self.local_hold,
775 local_resume: self.local_resume,
776 remote_hold: self.remote_hold,
777 remote_resume: self.remote_resume,
778 refer_received: self.refer_received,
779 transfer_accepted: self.transfer_accepted,
780 refer_progress: self.refer_progress,
781 refer_completed: self.refer_completed,
782 transfer_failed: self.transfer_failed,
783 registration_success: self.registration_success,
784 registration_failed: self.registration_failed,
785 unregistration_success: self.unregistration_success,
786 unregistration_failed: self.unregistration_failed,
787 sip_trace: self.sip_trace,
788 },
789 self.config,
790 )
791 .await
792 }
793}
794
795#[doc(hidden)]
797pub struct CallbackBuilderHandler {
798 event: Option<EventHook>,
799 incoming: IncomingHook,
800 established: Option<EstablishedHook>,
801 progress: Option<ProgressHook>,
802 dtmf: Option<DtmfHook>,
803 ended: Option<EndedHook>,
804 failed: Option<FailedHook>,
805 cancelled: Option<CancelledHook>,
806 media_security: Option<MediaSecurityHook>,
807 local_hold: Option<HoldHook>,
808 local_resume: Option<HoldHook>,
809 remote_hold: Option<HoldHook>,
810 remote_resume: Option<HoldHook>,
811 refer_received: Option<ReferReceivedHook>,
812 transfer_accepted: Option<TransferAcceptedHook>,
813 refer_progress: Option<ReferProgressHook>,
814 refer_completed: Option<ReferCompletedHook>,
815 transfer_failed: Option<TransferFailedHook>,
816 registration_success: Option<RegistrationSuccessHook>,
817 registration_failed: Option<RegistrationFailedHook>,
818 unregistration_success: Option<UnregistrationSuccessHook>,
819 unregistration_failed: Option<UnregistrationFailedHook>,
820 sip_trace: Option<SipTraceHook>,
821}
822
823#[async_trait]
824impl CallHandler for CallbackBuilderHandler {
825 async fn on_event(&self, event: Event) {
826 if let Some(hook) = &self.event {
827 if let Err(err) = hook(event).await {
828 tracing::warn!("[CallbackPeerBuilder] on_event failed: {}", err);
829 }
830 }
831 }
832
833 async fn on_incoming_call(&self, call: IncomingCall) -> CallHandlerDecision {
834 (self.incoming)(call).await
835 }
836
837 async fn on_call_established(&self, handle: SessionHandle) {
838 if let Some(hook) = &self.established {
839 if let Err(err) = hook(handle).await {
840 tracing::warn!("[CallbackPeerBuilder] on_established failed: {}", err);
841 }
842 }
843 }
844
845 async fn on_call_progress(
846 &self,
847 handle: SessionHandle,
848 status_code: u16,
849 reason: String,
850 sdp: Option<String>,
851 ) {
852 if let Some(hook) = &self.progress {
853 if let Err(err) = hook(handle, status_code, reason, sdp).await {
854 tracing::warn!("[CallbackPeerBuilder] on_progress failed: {}", err);
855 }
856 }
857 }
858
859 async fn on_call_ended(&self, call_id: CallId, reason: EndReason) {
860 if let Some(hook) = &self.ended {
861 if let Err(err) = hook(call_id, reason).await {
862 tracing::warn!("[CallbackPeerBuilder] on_ended failed: {}", err);
863 }
864 }
865 }
866
867 async fn on_call_failed(&self, call_id: CallId, status_code: u16, reason: String) {
868 if let Some(hook) = &self.failed {
869 if let Err(err) = hook(call_id, status_code, reason).await {
870 tracing::warn!("[CallbackPeerBuilder] on_failed failed: {}", err);
871 }
872 }
873 }
874
875 async fn on_call_cancelled(&self, call_id: CallId) {
876 if let Some(hook) = &self.cancelled {
877 if let Err(err) = hook(call_id).await {
878 tracing::warn!("[CallbackPeerBuilder] on_cancelled failed: {}", err);
879 }
880 }
881 }
882
883 async fn on_dtmf(&self, handle: SessionHandle, digit: char) {
884 if let Some(hook) = &self.dtmf {
885 if let Err(err) = hook(handle, digit).await {
886 tracing::warn!("[CallbackPeerBuilder] on_dtmf failed: {}", err);
887 }
888 }
889 }
890
891 async fn on_media_security_negotiated(&self, handle: SessionHandle, state: MediaSecurityState) {
892 if let Some(hook) = &self.media_security {
893 if let Err(err) = hook(handle, state).await {
894 tracing::warn!("[CallbackPeerBuilder] on_media_security failed: {}", err);
895 }
896 }
897 }
898
899 async fn on_call_on_hold(&self, handle: SessionHandle) {
900 if let Some(hook) = &self.local_hold {
901 if let Err(err) = hook(handle).await {
902 tracing::warn!("[CallbackPeerBuilder] on_local_hold failed: {}", err);
903 }
904 }
905 }
906
907 async fn on_call_resumed(&self, handle: SessionHandle) {
908 if let Some(hook) = &self.local_resume {
909 if let Err(err) = hook(handle).await {
910 tracing::warn!("[CallbackPeerBuilder] on_local_resume failed: {}", err);
911 }
912 }
913 }
914
915 async fn on_remote_call_on_hold(&self, handle: SessionHandle) {
916 if let Some(hook) = &self.remote_hold {
917 if let Err(err) = hook(handle).await {
918 tracing::warn!("[CallbackPeerBuilder] on_remote_hold failed: {}", err);
919 }
920 }
921 }
922
923 async fn on_remote_call_resumed(&self, handle: SessionHandle) {
924 if let Some(hook) = &self.remote_resume {
925 if let Err(err) = hook(handle).await {
926 tracing::warn!("[CallbackPeerBuilder] on_remote_resume failed: {}", err);
927 }
928 }
929 }
930
931 async fn on_refer_received(&self, request: crate::api::incoming::IncomingRequest) {
932 let Some(hook) = &self.refer_received else {
933 return;
934 };
935 let Some(coord) = request.coordinator.clone() else {
936 tracing::warn!(
937 "[CallbackPeerBuilder] on_refer_received fired without a coordinator hook; \
938 dropping REFER for call {}",
939 request.call_id
940 );
941 return;
942 };
943 let handle = SessionHandle::new(request.call_id.clone(), coord);
944 let accepted = match hook(handle.clone(), request).await {
945 Ok(b) => b,
946 Err(err) => {
947 tracing::warn!(
948 "[CallbackPeerBuilder] on_refer_received failed; rejecting REFER: {}",
949 err
950 );
951 false
952 }
953 };
954 let result = if accepted {
955 handle.accept_refer().await
956 } else {
957 handle.reject_refer(603, "Decline").await
958 };
959 if let Err(err) = result {
960 tracing::warn!(
961 "[CallbackPeerBuilder] applying REFER decision failed: {}",
962 err
963 );
964 }
965 }
966
967 async fn on_transfer_accepted(&self, handle: SessionHandle, refer_to: String) {
968 if let Some(hook) = &self.transfer_accepted {
969 if let Err(err) = hook(handle, refer_to).await {
970 tracing::warn!("[CallbackPeerBuilder] on_transfer_accepted failed: {}", err);
971 }
972 }
973 }
974
975 async fn on_refer_progress(&self, handle: SessionHandle, status_code: u16, reason: String) {
976 if let Some(hook) = &self.refer_progress {
977 if let Err(err) = hook(handle, status_code, reason).await {
978 tracing::warn!("[CallbackPeerBuilder] on_refer_progress failed: {}", err);
979 }
980 }
981 }
982
983 async fn on_refer_completed(
984 &self,
985 handle: SessionHandle,
986 target: String,
987 status_code: u16,
988 reason: String,
989 ) {
990 if let Some(hook) = &self.refer_completed {
991 if let Err(err) = hook(handle, target, status_code, reason).await {
992 tracing::warn!("[CallbackPeerBuilder] on_refer_completed failed: {}", err);
993 }
994 }
995 }
996
997 async fn on_transfer_failed(&self, handle: SessionHandle, status_code: u16, reason: String) {
998 if let Some(hook) = &self.transfer_failed {
999 if let Err(err) = hook(handle, status_code, reason).await {
1000 tracing::warn!("[CallbackPeerBuilder] on_transfer_failed failed: {}", err);
1001 }
1002 }
1003 }
1004
1005 async fn on_registration_success(&self, registrar: String, expires: u32, contact: String) {
1006 if let Some(hook) = &self.registration_success {
1007 if let Err(err) = hook(registrar, expires, contact).await {
1008 tracing::warn!(
1009 "[CallbackPeerBuilder] on_registration_success failed: {}",
1010 err
1011 );
1012 }
1013 }
1014 }
1015
1016 async fn on_registration_failed(&self, registrar: String, status_code: u16, reason: String) {
1017 if let Some(hook) = &self.registration_failed {
1018 if let Err(err) = hook(registrar, status_code, reason).await {
1019 tracing::warn!(
1020 "[CallbackPeerBuilder] on_registration_failed failed: {}",
1021 err
1022 );
1023 }
1024 }
1025 }
1026
1027 async fn on_unregistration_success(&self, registrar: String) {
1028 if let Some(hook) = &self.unregistration_success {
1029 if let Err(err) = hook(registrar).await {
1030 tracing::warn!(
1031 "[CallbackPeerBuilder] on_unregistration_success failed: {}",
1032 err
1033 );
1034 }
1035 }
1036 }
1037
1038 async fn on_unregistration_failed(&self, registrar: String, reason: String) {
1039 if let Some(hook) = &self.unregistration_failed {
1040 if let Err(err) = hook(registrar, reason).await {
1041 tracing::warn!(
1042 "[CallbackPeerBuilder] on_unregistration_failed failed: {}",
1043 err
1044 );
1045 }
1046 }
1047 }
1048
1049 async fn on_sip_trace(&self, trace: SipTrace) {
1050 if let Some(hook) = &self.sip_trace {
1051 if let Err(err) = hook(trace).await {
1052 tracing::warn!("[CallbackPeerBuilder] on_sip_trace failed: {}", err);
1053 }
1054 }
1055 }
1056}
1057
1058#[async_trait]
1088pub trait CallHandler: Send + Sync + 'static {
1089 #[allow(unused_variables)]
1091 async fn on_event(&self, event: Event) {}
1092
1093 async fn on_incoming_call(&self, call: IncomingCall) -> CallHandlerDecision;
1105
1106 #[allow(unused_variables)]
1108 async fn on_call_established(&self, handle: SessionHandle) {}
1109
1110 #[allow(unused_variables)]
1116 async fn on_call_progress(
1117 &self,
1118 handle: SessionHandle,
1119 status_code: u16,
1120 reason: String,
1121 sdp: Option<String>,
1122 ) {
1123 }
1124
1125 #[allow(unused_variables)]
1127 async fn on_call_ended(&self, call_id: CallId, reason: EndReason) {}
1128
1129 #[allow(unused_variables)]
1131 async fn on_call_failed(&self, call_id: CallId, status_code: u16, reason: String) {}
1132
1133 #[allow(unused_variables)]
1135 async fn on_call_cancelled(&self, call_id: CallId) {}
1136
1137 #[allow(unused_variables)]
1139 async fn on_dtmf(&self, handle: SessionHandle, digit: char) {}
1140
1141 #[allow(unused_variables)]
1145 async fn on_media_security_negotiated(&self, handle: SessionHandle, state: MediaSecurityState) {
1146 }
1147
1148 #[allow(unused_variables)]
1150 async fn on_call_on_hold(&self, handle: SessionHandle) {}
1151
1152 #[allow(unused_variables)]
1154 async fn on_call_resumed(&self, handle: SessionHandle) {}
1155
1156 #[allow(unused_variables)]
1158 async fn on_remote_call_on_hold(&self, handle: SessionHandle) {}
1159
1160 #[allow(unused_variables)]
1162 async fn on_remote_call_resumed(&self, handle: SessionHandle) {}
1163
1164 #[allow(unused_variables)]
1166 async fn on_transfer_accepted(&self, handle: SessionHandle, refer_to: String) {}
1167
1168 #[allow(unused_variables)]
1170 async fn on_refer_notify(
1171 &self,
1172 handle: SessionHandle,
1173 status_code: u16,
1174 reason: String,
1175 subscription_state: Option<SubscriptionState>,
1176 body: Option<String>,
1177 ) {
1178 }
1179
1180 #[allow(unused_variables)]
1182 async fn on_refer_progress(&self, handle: SessionHandle, status_code: u16, reason: String) {}
1183
1184 #[allow(unused_variables)]
1186 async fn on_refer_completed(
1187 &self,
1188 handle: SessionHandle,
1189 target: String,
1190 status_code: u16,
1191 reason: String,
1192 ) {
1193 }
1194
1195 #[allow(unused_variables)]
1197 async fn on_transfer_failed(&self, handle: SessionHandle, status_code: u16, reason: String) {}
1198
1199 #[allow(unused_variables)]
1201 async fn on_transfer_target_answered(
1202 &self,
1203 handle: SessionHandle,
1204 target_uri: String,
1205 evidence: TransferTargetEvidence,
1206 ) {
1207 }
1208
1209 #[allow(unused_variables)]
1211 async fn on_transfer_replacement_dialog_observed(
1212 &self,
1213 handle: SessionHandle,
1214 dialog: DialogInfo,
1215 ) {
1216 }
1217
1218 #[allow(unused_variables)]
1220 async fn on_transfer_replacement_dialog_terminated(
1221 &self,
1222 handle: SessionHandle,
1223 dialog: DialogInfo,
1224 reason: Option<String>,
1225 ) {
1226 }
1227
1228 #[allow(unused_variables)]
1230 async fn on_dialog_package_notify(
1231 &self,
1232 subscription_id: CallId,
1233 entity: Option<String>,
1234 version: Option<u32>,
1235 dialogs: Vec<DialogInfo>,
1236 document: DialogInfoDocument,
1237 ) {
1238 }
1239
1240 #[allow(unused_variables)]
1242 async fn on_dialog_state_changed(&self, subscription_id: CallId, dialog: DialogInfo) {}
1243
1244 #[allow(unused_variables)]
1250 async fn on_notify_received(&self, request: crate::api::incoming::IncomingRequest) {}
1251
1252 #[allow(unused_variables)]
1257 async fn on_refer_received(&self, request: crate::api::incoming::IncomingRequest) {}
1258
1259 #[allow(unused_variables)]
1264 async fn on_info_received(&self, request: crate::api::incoming::IncomingRequest) {}
1265
1266 #[allow(unused_variables)]
1268 async fn on_message_received(&self, request: crate::api::incoming::IncomingRequest) {}
1269
1270 #[allow(unused_variables)]
1274 async fn on_options_received(&self, request: crate::api::incoming::IncomingRequest) {}
1275
1276 #[allow(unused_variables)]
1281 async fn on_update_received(&self, request: crate::api::incoming::IncomingRequest) {}
1282
1283 #[allow(unused_variables)]
1290 async fn on_register_received(&self, register: crate::api::incoming::IncomingRegister) {}
1291
1292 #[allow(unused_variables)]
1294 async fn on_registration_success(&self, registrar: String, expires: u32, contact: String) {}
1295
1296 #[allow(unused_variables)]
1298 async fn on_registration_failed(&self, registrar: String, status_code: u16, reason: String) {}
1299
1300 #[allow(unused_variables)]
1302 async fn on_unregistration_success(&self, registrar: String) {}
1303
1304 #[allow(unused_variables)]
1306 async fn on_unregistration_failed(&self, registrar: String, reason: String) {}
1307
1308 #[allow(unused_variables)]
1310 async fn on_sip_trace(&self, trace: SipTrace) {}
1311
1312 #[allow(unused_variables)]
1321 async fn on_auth_retrying(&self, call_id: CallId, status_code: u16, realm: String) {}
1322}
1323
1324#[derive(Clone)]
1326pub struct CallbackPeerControl {
1327 coordinator: Arc<UnifiedCoordinator>,
1328 local_uri: String,
1329 shutdown_tx: tokio::sync::watch::Sender<bool>,
1330}
1331
1332impl CallbackPeerControl {
1333 pub fn register(
1340 &self,
1341 registrar: impl Into<String>,
1342 username: impl Into<String>,
1343 password: impl Into<String>,
1344 ) -> crate::api::send::RegisterBuilder {
1345 self.coordinator.register(registrar, username, password)
1346 }
1347
1348 pub fn register_account(&self, account: &SipAccount) -> crate::api::send::RegisterBuilder {
1350 let mut builder = self
1351 .register(
1352 account.registrar.clone(),
1353 account.effective_auth_username().to_string(),
1354 account.password.clone(),
1355 )
1356 .with_expires(account.expires);
1357 if let Some(from_uri) = &account.from_uri {
1358 builder = builder.with_from_uri(from_uri.clone());
1359 }
1360 if let Some(contact_uri) = &account.contact_uri {
1361 builder = builder.with_contact_uri(contact_uri.clone());
1362 }
1363 builder
1364 }
1365
1366 pub async fn is_registered(&self, handle: &RegistrationHandle) -> Result<bool> {
1382 self.coordinator.is_registered(handle).await
1383 }
1384
1385 pub async fn unregister(&self, handle: &RegistrationHandle) -> Result<()> {
1401 self.coordinator.unregister(handle).await
1402 }
1403
1404 pub async fn hangup(&self, handle: &SessionHandle) -> Result<()> {
1422 self.coordinator.hangup(handle.id()).await
1423 }
1424
1425 pub fn shutdown(&self) {
1439 let _ = self.shutdown_tx.send(true);
1440 }
1441
1442 pub fn coordinator(&self) -> &Arc<UnifiedCoordinator> {
1447 &self.coordinator
1448 }
1449
1450 pub fn invite(&self, target: impl Into<String>) -> crate::api::send::OutboundCallBuilder {
1454 self.coordinator
1455 .invite(Some(self.local_uri.clone()), target)
1456 }
1457}
1458
1459pub struct CallbackPeer<H: CallHandler> {
1501 handler: Arc<H>,
1502 coordinator: Arc<UnifiedCoordinator>,
1503 local_uri: String,
1504 shutdown_tx: tokio::sync::watch::Sender<bool>,
1505 shutdown_rx: tokio::sync::watch::Receiver<bool>,
1506 established_callbacks: Arc<tokio::sync::Mutex<HashSet<CallId>>>,
1507 terminal_callbacks: Arc<tokio::sync::Mutex<BoundedCallDedupe>>,
1508 deferred_calls: Arc<tokio::sync::Mutex<HashMap<CallId, IncomingCallGuard>>>,
1509}
1510
1511const TERMINAL_CALLBACK_DEDUPE_CAPACITY: usize = 8192;
1512
1513struct BoundedCallDedupe {
1514 set: HashSet<CallId>,
1515 order: VecDeque<CallId>,
1516 capacity: usize,
1517}
1518
1519impl BoundedCallDedupe {
1520 fn with_capacity(capacity: usize) -> Self {
1521 Self {
1522 set: HashSet::with_capacity(capacity),
1523 order: VecDeque::with_capacity(capacity),
1524 capacity: capacity.max(1),
1525 }
1526 }
1527
1528 fn insert(&mut self, call_id: CallId) -> bool {
1529 if self.set.contains(&call_id) {
1530 return false;
1531 }
1532
1533 self.set.insert(call_id.clone());
1534 self.order.push_back(call_id);
1535
1536 while self.order.len() > self.capacity {
1537 if let Some(oldest) = self.order.pop_front() {
1538 self.set.remove(&oldest);
1539 }
1540 }
1541
1542 true
1543 }
1544
1545 #[cfg(test)]
1546 fn len(&self) -> usize {
1547 self.set.len()
1548 }
1549}
1550
1551impl CallbackPeer<CallbackBuilderHandler> {
1552 pub fn builder(config: Config) -> CallbackPeerBuilder {
1569 CallbackPeerBuilder::new(config)
1570 }
1571}
1572
1573impl<H: CallHandler> CallbackPeer<H> {
1574 pub async fn new(handler: H, config: Config) -> Result<Self> {
1599 let local_uri = config.local_uri.clone();
1600 let coordinator = UnifiedCoordinator::new(config).await?;
1601 let (shutdown_tx, shutdown_rx) = tokio::sync::watch::channel(false);
1602 Ok(Self {
1603 handler: Arc::new(handler),
1604 coordinator,
1605 local_uri,
1606 shutdown_tx,
1607 shutdown_rx,
1608 established_callbacks: Arc::new(tokio::sync::Mutex::new(HashSet::new())),
1609 terminal_callbacks: Arc::new(tokio::sync::Mutex::new(
1610 BoundedCallDedupe::with_capacity(TERMINAL_CALLBACK_DEDUPE_CAPACITY),
1611 )),
1612 deferred_calls: Arc::new(tokio::sync::Mutex::new(HashMap::new())),
1613 })
1614 }
1615
1616 pub fn coordinator(&self) -> &Arc<UnifiedCoordinator> {
1633 &self.coordinator
1634 }
1635
1636 pub fn invite(&self, target: impl Into<String>) -> crate::api::send::OutboundCallBuilder {
1640 self.coordinator
1641 .invite(Some(self.local_uri.clone()), target)
1642 }
1643
1644 pub fn control(&self) -> CallbackPeerControl {
1661 CallbackPeerControl {
1662 coordinator: self.coordinator.clone(),
1663 local_uri: self.local_uri.clone(),
1664 shutdown_tx: self.shutdown_tx.clone(),
1665 }
1666 }
1667
1668 pub fn register(
1678 &self,
1679 registrar: impl Into<String>,
1680 username: impl Into<String>,
1681 password: impl Into<String>,
1682 ) -> crate::api::send::RegisterBuilder {
1683 self.coordinator.register(registrar, username, password)
1684 }
1685
1686 pub fn register_account(&self, account: &SipAccount) -> crate::api::send::RegisterBuilder {
1688 self.control().register_account(account)
1689 }
1690
1691 pub async fn is_registered(
1709 &self,
1710 handle: &crate::api::unified::RegistrationHandle,
1711 ) -> Result<bool> {
1712 self.coordinator.is_registered(handle).await
1713 }
1714
1715 pub async fn unregister(&self, handle: &crate::api::unified::RegistrationHandle) -> Result<()> {
1731 self.coordinator.unregister(handle).await
1732 }
1733
1734 pub fn shutdown(&self) {
1749 let _ = self.shutdown_tx.send(true);
1750 }
1751
1752 pub fn shutdown_handle(&self) -> ShutdownHandle {
1772 ShutdownHandle {
1773 tx: self.shutdown_tx.clone(),
1774 }
1775 }
1776
1777 pub async fn run(self) -> Result<()> {
1811 let mut event_rx = self.coordinator.subscribe_events().await?;
1812 let mut shutdown_rx = self.shutdown_rx.clone();
1813 let mut handlers: tokio::task::JoinSet<()> = tokio::task::JoinSet::new();
1814
1815 loop {
1816 reap_ready_handlers(&mut handlers, "completed");
1817 tokio::select! {
1818 _ = shutdown_rx.changed() => {
1820 if *shutdown_rx.borrow() {
1821 tracing::info!("[CallbackPeer] Shutdown signal received");
1822 break;
1823 }
1824 }
1825 Some(join_result) = handlers.join_next(), if !handlers.is_empty() => {
1829 if let Err(e) = join_result {
1830 if !e.is_cancelled() {
1831 tracing::warn!("[CallbackPeer] Handler task panicked or errored: {}", e);
1832 }
1833 }
1834 }
1835 raw = event_rx.recv() => {
1837 let Some(raw_event) = raw else {
1838 tracing::info!("[CallbackPeer] Event channel closed, stopping");
1839 break;
1840 };
1841
1842 let Some(session_event) = raw_event
1844 .as_any()
1845 .downcast_ref::<crate::adapters::SessionApiCrossCrateEvent>()
1846 else {
1847 continue;
1848 };
1849
1850 let event = session_event.event.clone();
1851 self.dispatch(event, &mut handlers).await;
1852 reap_ready_handlers(&mut handlers, "post-dispatch");
1853 }
1854 }
1855 }
1856
1857 while let Some(join_result) = handlers.join_next().await {
1861 if let Err(e) = join_result {
1862 if !e.is_cancelled() {
1863 tracing::warn!(
1864 "[CallbackPeer] Handler task panicked or errored on drain: {}",
1865 e
1866 );
1867 }
1868 }
1869 }
1870
1871 {
1872 let mut deferred = self.deferred_calls.lock().await;
1873 for guard in deferred.values() {
1874 guard.resolve_without_response();
1875 }
1876 deferred.clear();
1877 }
1878
1879 if let Err(e) = self
1884 .coordinator
1885 .shutdown_gracefully(Some(Duration::ZERO))
1886 .await
1887 {
1888 tracing::warn!("[CallbackPeer] Coordinator shutdown failed: {}", e);
1889 }
1890 Ok(())
1891 }
1892
1893 async fn dispatch(&self, event: Event, handlers: &mut tokio::task::JoinSet<()>) {
1896 let handler = self.handler.clone();
1897 let coordinator = self.coordinator.clone();
1898 let established_callbacks = self.established_callbacks.clone();
1899 let terminal_callbacks = self.terminal_callbacks.clone();
1900 let deferred_calls = self.deferred_calls.clone();
1901 let fast_auto_accept_incoming_calls = coordinator.fast_auto_accept_incoming_calls();
1902
1903 handlers.spawn(async move {
1904 let dispatch_guard = cleanup_diag::stage_guard(
1905 callback_stage_for_event(&event),
1906 callback_label_for_event(&event),
1907 );
1908 handler.on_event(event.clone()).await;
1909
1910 match event {
1911 Event::IncomingCall {
1912 call_id,
1913 from,
1914 to,
1915 sdp,
1916 } => {
1917 let parsed = coordinator
1925 .session_registry
1926 .peek_pending_incoming_request()
1927 .await;
1928 let transport = coordinator
1929 .session_registry
1930 .peek_pending_incoming_transport()
1931 .await;
1932 let incoming = match parsed {
1933 Some(req) => IncomingCall::with_request(
1934 call_id.clone(),
1935 from,
1936 to,
1937 sdp,
1938 coordinator.clone(),
1939 req,
1940 ),
1941 None => IncomingCall::new(
1942 call_id.clone(),
1943 from,
1944 to,
1945 sdp,
1946 coordinator.clone(),
1947 ),
1948 }
1949 .with_transport_context(
1950 transport
1951 .as_deref()
1952 .cloned()
1953 .unwrap_or_else(crate::auth::SipTransportSecurityContext::unknown),
1954 );
1955 let decision = handler.on_incoming_call(incoming).await;
1956 match decision {
1960 CallHandlerDecision::Accept => {
1961 if fast_auto_accept_incoming_calls {
1962 tracing::debug!(
1963 "Callback accept decision for {} already handled by fast auto-accept",
1964 call_id
1965 );
1966 return;
1967 }
1968
1969 let accept_guard = cleanup_diag::stage_guard(
1970 CleanupStage::CallbackAcceptCall,
1971 call_id.to_string(),
1972 );
1973 match coordinator.accept_call(&call_id).await {
1974 Ok(()) => {
1975 accept_guard.finish_success();
1976 let should_notify = {
1977 let mut callbacks = established_callbacks.lock().await;
1978 callbacks.insert(call_id.clone())
1979 };
1980 if should_notify {
1981 let handle =
1982 SessionHandle::new(call_id.clone(), coordinator.clone());
1983 handler.on_call_established(handle).await;
1984 }
1985 }
1986 Err(e) => {
1987 tracing::debug!(
1988 "Callback accept decision for {} was not applied: {}",
1989 call_id,
1990 e
1991 );
1992 accept_guard.finish_failure();
1993 }
1994 }
1995 }
1996 CallHandlerDecision::AcceptWithSdp(sdp) => {
1997 if fast_auto_accept_incoming_calls {
1998 tracing::debug!(
1999 "Callback accept-with-SDP decision for {} already handled by fast auto-accept",
2000 call_id
2001 );
2002 return;
2003 }
2004
2005 let accept_guard = cleanup_diag::stage_guard(
2006 CleanupStage::CallbackAcceptCall,
2007 call_id.to_string(),
2008 );
2009 match coordinator.accept_call_with_sdp(&call_id, sdp).await {
2010 Ok(()) => {
2011 accept_guard.finish_success();
2012 let should_notify = {
2013 let mut callbacks = established_callbacks.lock().await;
2014 callbacks.insert(call_id.clone())
2015 };
2016 if should_notify {
2017 let handle =
2018 SessionHandle::new(call_id.clone(), coordinator.clone());
2019 handler.on_call_established(handle).await;
2020 }
2021 }
2022 Err(e) => {
2023 tracing::debug!(
2024 "Callback accept-with-SDP decision for {} was not applied: {}",
2025 call_id,
2026 e
2027 );
2028 accept_guard.finish_failure();
2029 }
2030 }
2031 }
2032 CallHandlerDecision::Reject { status, reason } => {
2033 if fast_auto_accept_incoming_calls {
2034 tracing::debug!(
2035 "Callback reject decision for {} ignored because fast auto-accept already answered the call",
2036 call_id
2037 );
2038 return;
2039 }
2040
2041 let _ = coordinator
2042 .reject(&call_id)
2043 .with_status(status)
2044 .with_reason(reason)
2045 .send()
2046 .await;
2047 }
2048 CallHandlerDecision::Redirect(target) => {
2049 if fast_auto_accept_incoming_calls {
2050 tracing::debug!(
2051 "Callback redirect decision for {} ignored because fast auto-accept already answered the call",
2052 call_id
2053 );
2054 return;
2055 }
2056
2057 let _ = coordinator
2058 .redirect(&call_id)
2059 .with_status(302)
2060 .with_contacts(vec![target])
2061 .send()
2062 .await;
2063 }
2064 CallHandlerDecision::Defer(guard) => {
2065 if fast_auto_accept_incoming_calls {
2066 guard.resolve_without_response();
2067 tracing::debug!(
2068 "Callback defer decision for {} ignored because fast auto-accept already answered the call",
2069 call_id
2070 );
2071 return;
2072 }
2073
2074 deferred_calls.lock().await.insert(call_id, guard);
2075 }
2076 }
2077 }
2078
2079 Event::CallAnswered { call_id, .. } => {
2080 if let Some(guard) = deferred_calls.lock().await.remove(&call_id) {
2081 guard.resolve_without_response();
2082 }
2083 let should_notify = {
2084 let mut callbacks = established_callbacks.lock().await;
2085 callbacks.insert(call_id.clone())
2086 };
2087 if should_notify {
2088 let handle = SessionHandle::new(call_id, coordinator);
2089 handler.on_call_established(handle).await;
2090 }
2091 }
2092
2093 Event::CallProgress {
2094 call_id,
2095 status_code,
2096 reason,
2097 sdp,
2098 } => {
2099 let handle = SessionHandle::new(call_id, coordinator);
2100 handler
2101 .on_call_progress(handle, status_code, reason, sdp)
2102 .await;
2103 }
2104
2105 Event::CallEnded { call_id, reason } => {
2106 if let Some(guard) = deferred_calls.lock().await.remove(&call_id) {
2107 guard.resolve_without_response();
2108 }
2109 established_callbacks.lock().await.remove(&call_id);
2110 let should_notify = {
2111 let mut callbacks = terminal_callbacks.lock().await;
2112 callbacks.insert(call_id.clone())
2113 };
2114 if should_notify {
2115 let end_reason = EndReason::from(reason);
2116 handler.on_call_ended(call_id, end_reason).await;
2117 }
2118 }
2119
2120 Event::CallFailed {
2121 call_id,
2122 status_code,
2123 reason,
2124 } => {
2125 if let Some(guard) = deferred_calls.lock().await.remove(&call_id) {
2126 guard.resolve_without_response();
2127 }
2128 established_callbacks.lock().await.remove(&call_id);
2129 let should_notify = {
2130 let mut callbacks = terminal_callbacks.lock().await;
2131 callbacks.insert(call_id.clone())
2132 };
2133 if should_notify {
2134 handler.on_call_failed(call_id, status_code, reason).await;
2135 }
2136 }
2137
2138 Event::CallCancelled { call_id } => {
2139 if let Some(guard) = deferred_calls.lock().await.remove(&call_id) {
2140 guard.resolve_without_response();
2141 }
2142 established_callbacks.lock().await.remove(&call_id);
2143 let should_notify = {
2144 let mut callbacks = terminal_callbacks.lock().await;
2145 callbacks.insert(call_id.clone())
2146 };
2147 if should_notify {
2148 handler.on_call_cancelled(call_id).await;
2149 }
2150 }
2151
2152 Event::CallOnHold { call_id } => {
2153 let handle = SessionHandle::new(call_id, coordinator);
2154 handler.on_call_on_hold(handle).await;
2155 }
2156
2157 Event::CallResumed { call_id } => {
2158 let handle = SessionHandle::new(call_id, coordinator);
2159 handler.on_call_resumed(handle).await;
2160 }
2161
2162 Event::RemoteCallOnHold { call_id } => {
2163 let handle = SessionHandle::new(call_id, coordinator);
2164 handler.on_remote_call_on_hold(handle).await;
2165 }
2166
2167 Event::RemoteCallResumed { call_id } => {
2168 let handle = SessionHandle::new(call_id, coordinator);
2169 handler.on_remote_call_resumed(handle).await;
2170 }
2171
2172 Event::DtmfReceived { call_id, digit } => {
2173 let handle = SessionHandle::new(call_id, coordinator);
2174 handler.on_dtmf(handle, digit).await;
2175 }
2176
2177 Event::MediaSecurityNegotiated {
2178 call_id,
2179 keying,
2180 suite,
2181 profile,
2182 contexts_installed,
2183 } => {
2184 let handle = SessionHandle::new(call_id, coordinator);
2185 handler
2186 .on_media_security_negotiated(
2187 handle,
2188 MediaSecurityState {
2189 keying,
2190 suite,
2191 profile,
2192 contexts_installed,
2193 },
2194 )
2195 .await;
2196 }
2197
2198 Event::ReferReceived {
2199 call_id: _, refer_to: _, request, ..
2200 } => {
2201 if let Some(mut req) = request {
2207 req.set_coordinator(coordinator.clone());
2208 handler.on_refer_received(req).await;
2209 }
2210 }
2211
2212 Event::TransferAccepted { call_id, refer_to } => {
2213 let handle = SessionHandle::new(call_id, coordinator);
2214 handler.on_transfer_accepted(handle, refer_to).await;
2215 }
2216
2217 Event::ReferNotify {
2218 call_id,
2219 status_code,
2220 reason,
2221 subscription_state,
2222 body,
2223 } => {
2224 let handle = SessionHandle::new(call_id, coordinator);
2225 handler
2226 .on_refer_notify(handle, status_code, reason, subscription_state, body)
2227 .await;
2228 }
2229
2230 Event::ReferProgress {
2231 call_id,
2232 status_code,
2233 reason,
2234 } => {
2235 let handle = SessionHandle::new(call_id, coordinator);
2236 handler.on_refer_progress(handle, status_code, reason).await;
2237 }
2238
2239 Event::ReferCompleted {
2240 call_id,
2241 target,
2242 status_code,
2243 reason,
2244 } => {
2245 let handle = SessionHandle::new(call_id, coordinator);
2246 handler
2247 .on_refer_completed(handle, target, status_code, reason)
2248 .await;
2249 }
2250
2251 Event::TransferFailed {
2252 call_id,
2253 status_code,
2254 reason,
2255 } => {
2256 let handle = SessionHandle::new(call_id, coordinator);
2257 handler
2258 .on_transfer_failed(handle, status_code, reason)
2259 .await;
2260 }
2261
2262 Event::TransferTargetAnswered {
2263 transfer_call_id,
2264 target_uri,
2265 evidence,
2266 } => {
2267 let handle = SessionHandle::new(transfer_call_id, coordinator);
2268 handler
2269 .on_transfer_target_answered(handle, target_uri, evidence)
2270 .await;
2271 }
2272
2273 Event::TransferReplacementDialogObserved {
2274 transfer_call_id,
2275 dialog,
2276 } => {
2277 let handle = SessionHandle::new(transfer_call_id, coordinator);
2278 handler
2279 .on_transfer_replacement_dialog_observed(handle, dialog)
2280 .await;
2281 }
2282
2283 Event::TransferReplacementDialogTerminated {
2284 transfer_call_id,
2285 dialog,
2286 reason,
2287 } => {
2288 let handle = SessionHandle::new(transfer_call_id, coordinator);
2289 handler
2290 .on_transfer_replacement_dialog_terminated(handle, dialog, reason)
2291 .await;
2292 }
2293
2294 Event::DialogPackageNotify {
2295 subscription_id,
2296 entity,
2297 version,
2298 dialogs,
2299 document,
2300 } => {
2301 handler
2302 .on_dialog_package_notify(subscription_id, entity, version, dialogs, document)
2303 .await;
2304 }
2305
2306 Event::DialogStateChanged {
2307 subscription_id,
2308 dialog,
2309 } => {
2310 handler
2311 .on_dialog_state_changed(subscription_id, dialog)
2312 .await;
2313 }
2314
2315 Event::NotifyReceived {
2316 call_id: _,
2317 event_package: _,
2318 subscription_state: _,
2319 content_type: _,
2320 body: _,
2321 request,
2322 } => {
2323 if let Some(mut req) = request {
2328 req.set_coordinator(coordinator.clone());
2329 handler.on_notify_received(req).await;
2330 }
2331 }
2332
2333 Event::RegistrationSuccess {
2334 registrar,
2335 expires,
2336 contact,
2337 } => {
2338 handler
2339 .on_registration_success(registrar, expires, contact)
2340 .await;
2341 }
2342
2343 Event::RegistrationFailed {
2344 registrar,
2345 status_code,
2346 reason,
2347 } => {
2348 handler
2349 .on_registration_failed(registrar, status_code, reason)
2350 .await;
2351 }
2352
2353 Event::UnregistrationSuccess { registrar } => {
2354 handler.on_unregistration_success(registrar).await;
2355 }
2356
2357 Event::UnregistrationFailed { registrar, reason } => {
2358 handler.on_unregistration_failed(registrar, reason).await;
2359 }
2360
2361 Event::SipTrace(trace) => {
2362 handler.on_sip_trace(trace).await;
2363 }
2364
2365 Event::CallAuthRetrying {
2366 call_id,
2367 status_code,
2368 realm,
2369 } => {
2370 handler.on_auth_retrying(call_id, status_code, realm).await;
2371 }
2372
2373 Event::SessionRefreshed { .. }
2374 | Event::SessionRefreshFailed { .. }
2375 | Event::CallMuted { .. }
2376 | Event::CallUnmuted { .. }
2377 | Event::MediaQualityChanged { .. }
2378 | Event::NetworkError { .. }
2379 | Event::AuthenticationRequired { .. }
2380 | Event::CallProgressDetailed(_)
2387 | Event::CallEstablishedDetailed(_)
2388 | Event::CallFailedDetailed(_) => {}
2389 Event::InfoReceived { call_id: _, mut request } => {
2394 request.set_coordinator(coordinator.clone());
2395 handler.on_info_received(request).await;
2396 }
2397 Event::MessageReceived { call_id: _, mut request } => {
2398 request.set_coordinator(coordinator.clone());
2399 handler.on_message_received(request).await;
2400 }
2401 Event::OptionsReceived { call_id: _, mut request } => {
2402 request.set_coordinator(coordinator.clone());
2403 handler.on_options_received(request).await;
2404 }
2405 Event::UpdateReceived { call_id: _, mut request } => {
2406 request.set_coordinator(coordinator.clone());
2407 handler.on_update_received(request).await;
2408 }
2409 Event::IncomingRegister { mut register } => {
2410 register.set_coordinator(coordinator.clone());
2411 handler.on_register_received(register).await;
2412 }
2413 }
2414 dispatch_guard.finish_success();
2415 });
2416 }
2417}
2418
2419fn reap_ready_handlers(handlers: &mut tokio::task::JoinSet<()>, context: &str) {
2420 while let Some(join_result) = handlers.try_join_next() {
2421 if let Err(e) = join_result {
2422 if !e.is_cancelled() {
2423 tracing::warn!("[CallbackPeer] Handler task panicked or errored ({context}): {e}");
2424 }
2425 }
2426 }
2427}
2428
2429fn callback_stage_for_event(event: &Event) -> CleanupStage {
2430 match event {
2431 Event::IncomingCall { .. } => CleanupStage::CallbackIncomingDispatch,
2432 _ => CleanupStage::CallbackEventDispatch,
2433 }
2434}
2435
2436fn callback_label_for_event(event: &Event) -> String {
2437 event
2438 .call_id()
2439 .map(|call_id| call_id.to_string())
2440 .unwrap_or_else(|| "-".to_string())
2441}
2442
2443use crate::api::handlers::{AutoAnswerHandler, RejectAllHandler};
2446
2447impl CallbackPeer<AutoAnswerHandler> {
2448 pub async fn with_auto_answer(config: Config) -> Result<Self> {
2464 Self::new(AutoAnswerHandler, config).await
2465 }
2466}
2467
2468pub struct ClosureHandler {
2478 f: Box<dyn Fn(&IncomingCall) -> CallHandlerDecision + Send + Sync>,
2479}
2480
2481#[async_trait]
2482impl CallHandler for ClosureHandler {
2483 async fn on_incoming_call(&self, call: IncomingCall) -> CallHandlerDecision {
2484 match (self.f)(&call) {
2485 CallHandlerDecision::Defer(_) => {
2486 tracing::warn!("[ClosureHandler] Defer decision not supported; rejecting");
2490 call.reject(503, "Service Unavailable");
2491 CallHandlerDecision::Reject {
2492 status: 503,
2493 reason: "Service Unavailable".to_string(),
2494 }
2495 }
2496 decision => decision,
2497 }
2498 }
2499}
2500
2501impl CallbackPeer<ClosureHandler> {
2502 pub async fn from_fn(
2523 config: Config,
2524 handler: impl Fn(&IncomingCall) -> CallHandlerDecision + Send + Sync + 'static,
2525 ) -> Result<Self> {
2526 Self::new(
2527 ClosureHandler {
2528 f: Box::new(handler),
2529 },
2530 config,
2531 )
2532 .await
2533 }
2534}
2535
2536impl CallbackPeer<RejectAllHandler> {
2537 pub async fn with_reject_all(config: Config) -> Result<Self> {
2553 Self::new(RejectAllHandler::default(), config).await
2554 }
2555
2556 pub async fn with_reject(
2572 config: Config,
2573 status: u16,
2574 reason: impl Into<String>,
2575 ) -> Result<Self> {
2576 Self::new(RejectAllHandler::new(status, reason), config).await
2577 }
2578}
2579
2580#[cfg(test)]
2581mod tests {
2582 use super::*;
2583 use crate::api::events::{MediaSecurityKeying, MediaSecurityProfile};
2584 use crate::state_table::types::SessionId;
2585 use rvoip_sip_core::types::sdp::CryptoSuite;
2586 use std::sync::Mutex;
2587 use tokio::task::JoinSet;
2588
2589 #[test]
2590 fn callback_peer_builder_exposes_rtp_media_buffer_tuning() {
2591 let session_buffers = RtpSessionBufferConfig {
2592 sender_channel_capacity: 9,
2593 receiver_channel_capacity: 6,
2594 event_channel_capacity: 18,
2595 };
2596 let transport_buffers = RtpTransportBufferConfig {
2597 event_channel_capacity: 14,
2598 recv_buffer_size: 2048,
2599 rtcp_recv_buffer_size: 1024,
2600 };
2601 let mut media_config = MediaSessionControllerConfig::default();
2602 media_config.rtp_buffer_size = 960;
2603 media_config.rtp_buffer_initial_count = 5;
2604 media_config.rtp_buffer_max_count = 20;
2605
2606 let builder = CallbackPeer::builder(Config::local("callback-builder", 15444))
2607 .media_session_controller_config(media_config)
2608 .rtp_session_buffer_config(session_buffers)
2609 .rtp_transport_buffer_config(transport_buffers);
2610
2611 assert_eq!(builder.config.rtp_session_buffer_config, session_buffers);
2612 assert_eq!(
2613 builder.config.rtp_transport_buffer_config,
2614 transport_buffers
2615 );
2616 assert_eq!(
2617 builder
2618 .config
2619 .media_session_controller_config
2620 .rtp_buffer_size,
2621 960
2622 );
2623 assert_eq!(
2624 builder
2625 .config
2626 .media_session_controller_config
2627 .rtp_buffer_initial_count,
2628 5
2629 );
2630 assert_eq!(
2631 builder
2632 .config
2633 .media_session_controller_config
2634 .rtp_buffer_max_count,
2635 20
2636 );
2637 }
2638
2639 #[test]
2640 fn bounded_terminal_callback_dedupe_evicts_oldest_entries() {
2641 let mut dedupe = BoundedCallDedupe::with_capacity(2);
2642 assert!(dedupe.insert(SessionId("call-1".to_string())));
2643 assert!(!dedupe.insert(SessionId("call-1".to_string())));
2644 assert!(dedupe.insert(SessionId("call-2".to_string())));
2645 assert_eq!(dedupe.len(), 2);
2646 assert!(dedupe.insert(SessionId("call-3".to_string())));
2647 assert_eq!(dedupe.len(), 2);
2648 assert!(dedupe.insert(SessionId("call-1".to_string())));
2649 }
2650
2651 #[derive(Default)]
2652 struct RecordingHandler {
2653 events: Arc<Mutex<Vec<String>>>,
2654 }
2655
2656 impl RecordingHandler {
2657 fn push(&self, value: impl Into<String>) {
2658 self.events.lock().unwrap().push(value.into());
2659 }
2660 }
2661
2662 #[async_trait]
2663 impl CallHandler for RecordingHandler {
2664 async fn on_event(&self, _event: Event) {
2665 self.push("event");
2666 }
2667
2668 async fn on_incoming_call(&self, call: IncomingCall) -> CallHandlerDecision {
2669 self.push("incoming");
2670 CallHandlerDecision::Defer(call.defer(std::time::Duration::from_millis(10)))
2671 }
2672
2673 async fn on_call_established(&self, _handle: SessionHandle) {
2674 self.push("answered");
2675 }
2676
2677 async fn on_call_progress(
2678 &self,
2679 _handle: SessionHandle,
2680 status_code: u16,
2681 _reason: String,
2682 _sdp: Option<String>,
2683 ) {
2684 self.push(format!("progress:{status_code}"));
2685 }
2686
2687 async fn on_call_ended(&self, _call_id: CallId, _reason: EndReason) {
2688 self.push("ended");
2689 }
2690
2691 async fn on_call_failed(&self, _call_id: CallId, status_code: u16, _reason: String) {
2692 self.push(format!("failed:{status_code}"));
2693 }
2694
2695 async fn on_call_cancelled(&self, _call_id: CallId) {
2696 self.push("cancelled");
2697 }
2698
2699 async fn on_dtmf(&self, _handle: SessionHandle, digit: char) {
2700 self.push(format!("dtmf:{digit}"));
2701 }
2702
2703 async fn on_media_security_negotiated(
2704 &self,
2705 _handle: SessionHandle,
2706 state: MediaSecurityState,
2707 ) {
2708 self.push(format!("media-security:{}", state.contexts_installed));
2709 }
2710
2711 async fn on_call_on_hold(&self, _handle: SessionHandle) {
2712 self.push("hold");
2713 }
2714
2715 async fn on_call_resumed(&self, _handle: SessionHandle) {
2716 self.push("resume");
2717 }
2718
2719 async fn on_remote_call_on_hold(&self, _handle: SessionHandle) {
2720 self.push("remote-hold");
2721 }
2722
2723 async fn on_remote_call_resumed(&self, _handle: SessionHandle) {
2724 self.push("remote-resume");
2725 }
2726
2727 async fn on_transfer_accepted(&self, _handle: SessionHandle, _refer_to: String) {
2728 self.push("transfer-accepted");
2729 }
2730
2731 async fn on_refer_notify(
2732 &self,
2733 _handle: SessionHandle,
2734 status_code: u16,
2735 _reason: String,
2736 _subscription_state: Option<SubscriptionState>,
2737 _body: Option<String>,
2738 ) {
2739 self.push(format!("refer-notify:{status_code}"));
2740 }
2741
2742 async fn on_refer_progress(
2743 &self,
2744 _handle: SessionHandle,
2745 status_code: u16,
2746 _reason: String,
2747 ) {
2748 self.push(format!("refer-progress:{status_code}"));
2749 }
2750
2751 async fn on_refer_completed(
2752 &self,
2753 _handle: SessionHandle,
2754 _target: String,
2755 status_code: u16,
2756 _reason: String,
2757 ) {
2758 self.push(format!("refer-completed:{status_code}"));
2759 }
2760
2761 async fn on_transfer_failed(
2762 &self,
2763 _handle: SessionHandle,
2764 status_code: u16,
2765 _reason: String,
2766 ) {
2767 self.push(format!("transfer-failed:{status_code}"));
2768 }
2769
2770 async fn on_registration_success(
2771 &self,
2772 _registrar: String,
2773 _expires: u32,
2774 _contact: String,
2775 ) {
2776 self.push("registration-success");
2777 }
2778
2779 async fn on_registration_failed(
2780 &self,
2781 _registrar: String,
2782 status_code: u16,
2783 _reason: String,
2784 ) {
2785 self.push(format!("registration-failed:{status_code}"));
2786 }
2787
2788 async fn on_unregistration_success(&self, _registrar: String) {
2789 self.push("unregistration-success");
2790 }
2791
2792 async fn on_unregistration_failed(&self, _registrar: String, _reason: String) {
2793 self.push("unregistration-failed");
2794 }
2795 }
2796
2797 async fn drain(mut handlers: JoinSet<()>) {
2798 while let Some(result) = handlers.join_next().await {
2799 result.unwrap();
2800 }
2801 }
2802
2803 #[tokio::test]
2804 async fn callback_dispatch_invokes_typed_hooks_for_public_events() {
2805 let seen = Arc::new(Mutex::new(Vec::new()));
2806 let handler = RecordingHandler {
2807 events: seen.clone(),
2808 };
2809 let peer = CallbackPeer::new(handler, Config::local("callback-test", 15440))
2810 .await
2811 .unwrap();
2812 let mut handlers = JoinSet::new();
2813 let call_id = SessionId::new();
2814 let failed_call_id = SessionId::new();
2815 let cancelled_call_id = SessionId::new();
2816
2817 let events = vec![
2818 Event::IncomingCall {
2819 call_id: call_id.clone(),
2820 from: "sip:a@example.test".into(),
2821 to: "sip:b@example.test".into(),
2822 sdp: None,
2823 },
2824 Event::CallAnswered {
2825 call_id: call_id.clone(),
2826 sdp: None,
2827 },
2828 Event::CallAnswered {
2829 call_id: call_id.clone(),
2830 sdp: None,
2831 },
2832 Event::CallProgress {
2833 call_id: call_id.clone(),
2834 status_code: 180,
2835 reason: "Ringing".into(),
2836 sdp: None,
2837 },
2838 Event::CallEnded {
2839 call_id: call_id.clone(),
2840 reason: "normal".into(),
2841 },
2842 Event::CallFailed {
2843 call_id: failed_call_id.clone(),
2844 status_code: 486,
2845 reason: "Busy Here".into(),
2846 },
2847 Event::CallCancelled {
2848 call_id: cancelled_call_id.clone(),
2849 },
2850 Event::CallCancelled {
2851 call_id: cancelled_call_id.clone(),
2852 },
2853 Event::CallOnHold {
2854 call_id: call_id.clone(),
2855 },
2856 Event::CallResumed {
2857 call_id: call_id.clone(),
2858 },
2859 Event::RemoteCallOnHold {
2860 call_id: call_id.clone(),
2861 },
2862 Event::RemoteCallResumed {
2863 call_id: call_id.clone(),
2864 },
2865 Event::DtmfReceived {
2866 call_id: call_id.clone(),
2867 digit: '5',
2868 },
2869 Event::MediaSecurityNegotiated {
2870 call_id: call_id.clone(),
2871 keying: MediaSecurityKeying::Sdes,
2872 suite: CryptoSuite::AesCm128HmacSha1_80,
2873 profile: MediaSecurityProfile::RtpSavp,
2874 contexts_installed: true,
2875 },
2876 Event::ReferReceived {
2877 call_id: call_id.clone(),
2878 refer_to: "sip:c@example.test".into(),
2879 referred_by: None,
2880 replaces: None,
2881 transaction_id: "tx-1".into(),
2882 transfer_type: "blind".into(),
2883 request: None,
2884 },
2885 Event::TransferAccepted {
2886 call_id: call_id.clone(),
2887 refer_to: "sip:c@example.test".into(),
2888 },
2889 Event::ReferNotify {
2890 call_id: call_id.clone(),
2891 status_code: 100,
2892 reason: "Trying".into(),
2893 subscription_state: Some(SubscriptionState::parse("active;expires=60")),
2894 body: Some("SIP/2.0 100 Trying".into()),
2895 },
2896 Event::ReferProgress {
2897 call_id: call_id.clone(),
2898 status_code: 180,
2899 reason: "Ringing".into(),
2900 },
2901 Event::ReferCompleted {
2902 call_id: call_id.clone(),
2903 target: "sip:c@example.test".into(),
2904 status_code: 200,
2905 reason: "OK".into(),
2906 },
2907 Event::TransferFailed {
2908 call_id: call_id.clone(),
2909 status_code: 503,
2910 reason: "Service Unavailable".into(),
2911 },
2912 Event::NotifyReceived {
2913 call_id: call_id.clone(),
2914 event_package: "refer".into(),
2915 subscription_state: Some("active".into()),
2916 content_type: Some("message/sipfrag".into()),
2917 body: Some("SIP/2.0 100 Trying".into()),
2918 request: None,
2919 },
2920 Event::RegistrationSuccess {
2921 registrar: "sip:registrar.example.test".into(),
2922 expires: 300,
2923 contact: "sip:callback-test@example.test".into(),
2924 },
2925 Event::RegistrationFailed {
2926 registrar: "sip:registrar.example.test".into(),
2927 status_code: 403,
2928 reason: "Forbidden".into(),
2929 },
2930 Event::UnregistrationSuccess {
2931 registrar: "sip:registrar.example.test".into(),
2932 },
2933 Event::UnregistrationFailed {
2934 registrar: "sip:registrar.example.test".into(),
2935 reason: "timeout".into(),
2936 },
2937 ];
2938
2939 for event in events {
2940 peer.dispatch(event, &mut handlers).await;
2941 }
2942 drain(handlers).await;
2943
2944 let seen = seen.lock().unwrap().clone();
2945 for expected in [
2946 "incoming",
2947 "answered",
2948 "progress:180",
2949 "ended",
2950 "failed:486",
2951 "cancelled",
2952 "hold",
2953 "resume",
2954 "remote-hold",
2955 "remote-resume",
2956 "dtmf:5",
2957 "media-security:true",
2958 "transfer-accepted",
2959 "refer-notify:100",
2960 "refer-progress:180",
2961 "refer-completed:200",
2962 "transfer-failed:503",
2963 "registration-success",
2964 "registration-failed:403",
2965 "unregistration-success",
2966 "unregistration-failed",
2967 ] {
2968 assert!(
2969 seen.iter().any(|value| value == expected),
2970 "missing {expected}"
2971 );
2972 }
2973 assert_eq!(
2974 seen.iter()
2975 .filter(|value| value.as_str() == "event")
2976 .count(),
2977 25
2978 );
2979 assert_eq!(
2980 seen.iter()
2981 .filter(|value| value.as_str() == "answered")
2982 .count(),
2983 1
2984 );
2985 assert_eq!(
2986 seen.iter()
2987 .filter(|value| value.as_str() == "cancelled")
2988 .count(),
2989 1
2990 );
2991 }
2992
2993 #[tokio::test]
2994 async fn callback_builder_invokes_common_closure_hooks() {
2995 let seen = Arc::new(Mutex::new(Vec::new()));
2996 let peer = CallbackPeer::builder(Config::local("callback-builder", 15441))
2997 .on_incoming({
2998 let seen = seen.clone();
2999 move |_call| {
3000 let seen = seen.clone();
3001 async move {
3002 seen.lock().unwrap().push("incoming".to_string());
3003 CallHandlerDecision::Reject {
3004 status: 486,
3005 reason: "Busy Here".into(),
3006 }
3007 }
3008 }
3009 })
3010 .on_established({
3011 let seen = seen.clone();
3012 move |_handle| {
3013 let seen = seen.clone();
3014 async move {
3015 seen.lock().unwrap().push("established".to_string());
3016 Ok(())
3017 }
3018 }
3019 })
3020 .on_dtmf({
3021 let seen = seen.clone();
3022 move |_handle, digit| {
3023 let seen = seen.clone();
3024 async move {
3025 seen.lock().unwrap().push(format!("dtmf:{digit}"));
3026 Ok(())
3027 }
3028 }
3029 })
3030 .on_ended({
3031 let seen = seen.clone();
3032 move |_call_id, _reason| {
3033 let seen = seen.clone();
3034 async move {
3035 seen.lock().unwrap().push("ended".to_string());
3036 Ok(())
3037 }
3038 }
3039 })
3040 .build()
3041 .await
3042 .unwrap();
3043
3044 let mut handlers = JoinSet::new();
3045 let call_id = SessionId::new();
3046 for event in [
3047 Event::IncomingCall {
3048 call_id: call_id.clone(),
3049 from: "sip:a@example.test".into(),
3050 to: "sip:b@example.test".into(),
3051 sdp: None,
3052 },
3053 Event::CallAnswered {
3054 call_id: call_id.clone(),
3055 sdp: None,
3056 },
3057 Event::DtmfReceived {
3058 call_id: call_id.clone(),
3059 digit: '7',
3060 },
3061 Event::ReferReceived {
3062 call_id: call_id.clone(),
3063 refer_to: "sip:c@example.test".into(),
3064 referred_by: None,
3065 replaces: None,
3066 transaction_id: "tx-builder".into(),
3067 transfer_type: "blind".into(),
3068 request: None,
3069 },
3070 Event::CallEnded {
3071 call_id,
3072 reason: "normal".into(),
3073 },
3074 ] {
3075 peer.dispatch(event, &mut handlers).await;
3076 }
3077 drain(handlers).await;
3078
3079 let seen = seen.lock().unwrap().clone();
3080 for expected in ["incoming", "established", "dtmf:7", "ended"] {
3081 assert!(
3082 seen.iter().any(|value| value == expected),
3083 "missing {expected}; saw {seen:?}"
3084 );
3085 }
3086 }
3087
3088 #[tokio::test]
3089 async fn callback_builder_requires_incoming_hook() {
3090 let result = CallbackPeer::builder(Config::local("callback-builder-missing", 15443))
3091 .build()
3092 .await;
3093 let err = match result {
3094 Ok(_) => panic!("builder without on_incoming should fail"),
3095 Err(err) => err,
3096 };
3097 assert!(err.to_string().contains("on_incoming"));
3098 }
3099
3100 #[tokio::test]
3101 async fn callback_control_can_initiate_calls_while_peer_can_be_moved_to_run() {
3102 struct NoopHandler;
3103 #[async_trait]
3104 impl CallHandler for NoopHandler {
3105 async fn on_incoming_call(&self, _call: IncomingCall) -> CallHandlerDecision {
3106 CallHandlerDecision::Reject {
3107 status: 486,
3108 reason: "Busy Here".into(),
3109 }
3110 }
3111 }
3112
3113 let peer = CallbackPeer::new(NoopHandler, Config::local("callback-control", 15442))
3114 .await
3115 .unwrap();
3116 let control = peer.control();
3117 let stop = peer.shutdown_handle();
3118 let run_task = tokio::spawn(async move { peer.run().await });
3119
3120 let call_id = control
3121 .invite("sip:unreachable@127.0.0.1:15443")
3122 .send()
3123 .await
3124 .unwrap();
3125 assert!(!call_id.to_string().is_empty());
3126
3127 control.shutdown();
3128 stop.shutdown();
3129 tokio::time::timeout(std::time::Duration::from_secs(2), run_task)
3130 .await
3131 .unwrap()
3132 .unwrap()
3133 .unwrap();
3134 }
3135}