rvoip_client_core/client/builder.rs
1//! Client builder for creating SIP clients
2//!
3//! This module provides a fluent builder interface for constructing SIP clients
4//! with comprehensive configuration options. The builder pattern allows for
5//! readable, flexible client configuration while providing sensible defaults.
6//!
7//! # Architecture
8//!
9//! The `ClientBuilder` uses the builder pattern to construct a `ClientManager`
10//! with all necessary configuration. It supports:
11//!
12//! - Network configuration (local addresses, ports)
13//! - Media configuration (codecs, SRTP, echo cancellation)
14//! - SIP settings (user agent, domain)
15//! - Resource limits (concurrent calls, bandwidth)
16//! - Fluent sub-builders for complex configuration
17//!
18//! # Examples
19//!
20//! ## Basic Client Setup
21//!
22//! ```rust
23//! use rvoip_client_core::ClientBuilder;
24//!
25//! # tokio_test::block_on(async {
26//! let client = ClientBuilder::new()
27//! .local_address("127.0.0.1:5060".parse().unwrap())
28//! .domain("example.com")
29//! .user_agent("MyApp/1.0")
30//! .build()
31//! .await
32//! .expect("Failed to build client");
33//! # })
34//! ```
35//!
36//! ## Advanced Media Configuration
37//!
38//! ```rust
39//! use rvoip_client_core::{ClientBuilder, MediaPreset};
40//!
41//! # tokio_test::block_on(async {
42//! let client = ClientBuilder::new()
43//! .local_address("0.0.0.0:5060".parse().unwrap())
44//! .media_address("192.168.1.100:7000".parse().unwrap())
45//! .with_media(|m| m
46//! .codecs(vec!["opus", "G722", "PCMU"])
47//! .require_srtp(true)
48//! .echo_cancellation(true)
49//! .noise_suppression(true)
50//! .max_bandwidth_kbps(256)
51//! .rtp_ports(7000..8000)
52//! )
53//! .max_concurrent_calls(10)
54//! .build()
55//! .await
56//! .expect("Failed to build client");
57//! # })
58//! ```
59
60use std::sync::Arc;
61use crate::{ClientConfig, ClientResult, client::ClientManager};
62use super::config::{MediaConfig, MediaPreset};
63use super::media_builder::MediaConfigBuilder;
64
65/// Fluent builder for creating SIP clients with comprehensive configuration
66///
67/// The `ClientBuilder` provides a chainable interface for constructing SIP clients
68/// with all necessary configuration options. It encapsulates the complexity of
69/// client setup while providing sensible defaults and validation.
70///
71/// # Design Principles
72///
73/// - **Fluent Interface**: All configuration methods return `Self` for chaining
74/// - **Sensible Defaults**: Works out-of-the-box with minimal configuration
75/// - **Type Safety**: Compile-time validation of configuration parameters
76/// - **Async Ready**: Built for async/await patterns with tokio integration
77/// - **Flexible Media**: Supports both simple and advanced media configuration
78///
79/// # Configuration Categories
80///
81/// ## Network Configuration
82/// - Local SIP and media addresses
83/// - Port ranges for RTP traffic
84/// - Domain and transport settings
85///
86/// ## Media Configuration
87/// - Codec preferences and capabilities
88/// - Audio processing (echo cancellation, noise suppression)
89/// - Security (SRTP requirements)
90/// - Bandwidth and quality settings
91///
92/// ## SIP Configuration
93/// - User agent identification
94/// - Protocol compliance settings
95/// - Extension support
96///
97/// ## Resource Management
98/// - Concurrent call limits
99/// - Memory and CPU constraints
100/// - Network resource allocation
101///
102/// # Examples
103///
104/// ## Simple Desktop Client
105///
106/// ```rust
107/// use rvoip_client_core::ClientBuilder;
108///
109/// # tokio_test::block_on(async {
110/// let client = ClientBuilder::new()
111/// .local_address("127.0.0.1:5060".parse().unwrap())
112/// .domain("sip.example.com")
113/// .echo_cancellation(true)
114/// .build()
115/// .await.unwrap();
116/// # })
117/// ```
118///
119/// ## Enterprise Server Setup
120///
121/// ```rust
122/// use rvoip_client_core::{ClientBuilder, MediaPreset};
123///
124/// # tokio_test::block_on(async {
125/// let client = ClientBuilder::new()
126/// .local_address("0.0.0.0:5060".parse().unwrap())
127/// .media_address("192.168.1.100:0".parse().unwrap())
128/// .domain("enterprise.example.com")
129/// .user_agent("EnterpriseVoIP/2.1")
130/// .media_preset(MediaPreset::VoiceOptimized)
131/// .max_concurrent_calls(100)
132/// .rtp_ports(10000, 20000)
133/// .build()
134/// .await.unwrap();
135/// # })
136/// ```
137///
138/// ## WebRTC-Compatible Client
139///
140/// ```rust
141/// use rvoip_client_core::ClientBuilder;
142///
143/// # tokio_test::block_on(async {
144/// let client = ClientBuilder::new()
145/// .local_address("127.0.0.1:5060".parse().unwrap())
146/// .with_media(|m| m
147/// .codecs(vec!["opus", "G722"])
148/// .require_srtp(true)
149/// .echo_cancellation(true)
150/// .auto_gain_control(true)
151/// .noise_suppression(true)
152/// )
153/// .build()
154/// .await.unwrap();
155/// # })
156/// ```
157pub struct ClientBuilder {
158 config: ClientConfig,
159}
160
161impl ClientBuilder {
162 /// Create a new client builder with default configuration
163 ///
164 /// Initializes a new `ClientBuilder` with sensible default values suitable
165 /// for most use cases. The defaults include:
166 ///
167 /// - Local SIP address: `127.0.0.1:5060`
168 /// - Local media address: `127.0.0.1:0` (auto-assigned port)
169 /// - User agent: Generated from crate name and version
170 /// - Media configuration: Basic codecs with standard settings
171 /// - No domain specified (must be set for registration)
172 /// - Maximum concurrent calls: 10
173 ///
174 /// # Returns
175 ///
176 /// A new `ClientBuilder` instance ready for configuration chaining.
177 ///
178 /// # Examples
179 ///
180 /// ## Basic Initialization
181 ///
182 /// ```rust
183 /// use rvoip_client_core::ClientBuilder;
184 ///
185 /// let builder = ClientBuilder::new();
186 ///
187 /// // Builder is ready for configuration
188 /// # tokio_test::block_on(async {
189 /// let client = builder
190 /// .local_address("127.0.0.1:5060".parse().unwrap())
191 /// .build()
192 /// .await.unwrap();
193 /// # })
194 /// ```
195 ///
196 /// ## Chained Configuration
197 ///
198 /// ```rust
199 /// use rvoip_client_core::ClientBuilder;
200 ///
201 /// # tokio_test::block_on(async {
202 /// let client = ClientBuilder::new()
203 /// .local_address("0.0.0.0:5060".parse().unwrap())
204 /// .domain("sip.example.com")
205 /// .user_agent("CustomApp/1.0")
206 /// .max_concurrent_calls(50)
207 /// .build()
208 /// .await.unwrap();
209 /// # })
210 /// ```
211 pub fn new() -> Self {
212 Self {
213 config: ClientConfig::default(),
214 }
215 }
216
217 /// Set the local SIP address for binding the SIP transport
218 ///
219 /// Configures the local socket address where the SIP client will bind to
220 /// listen for incoming SIP messages and send outgoing requests. This address
221 /// is used for all SIP protocol communication.
222 ///
223 /// # Arguments
224 ///
225 /// * `addr` - The socket address (IP and port) to bind for SIP communication
226 ///
227 /// # Network Considerations
228 ///
229 /// - **IP Address**: Use `0.0.0.0` to bind to all interfaces, or a specific IP for single-interface binding
230 /// - **Port**: Standard SIP port is 5060 (UDP/TCP) or 5061 (TLS)
231 /// - **Firewall**: Ensure the specified port is accessible for incoming connections
232 /// - **NAT**: Consider using STUN/TURN for NAT traversal in production environments
233 ///
234 /// # Examples
235 ///
236 /// ## Standard SIP Port
237 ///
238 /// ```rust
239 /// use rvoip_client_core::ClientBuilder;
240 ///
241 /// # tokio_test::block_on(async {
242 /// let client = ClientBuilder::new()
243 /// .local_address("127.0.0.1:5060".parse().unwrap())
244 /// .build()
245 /// .await.unwrap();
246 /// # })
247 /// ```
248 ///
249 /// ## All Interfaces Binding
250 ///
251 /// ```rust
252 /// use rvoip_client_core::ClientBuilder;
253 ///
254 /// # tokio_test::block_on(async {
255 /// let client = ClientBuilder::new()
256 /// .local_address("0.0.0.0:5060".parse().unwrap())
257 /// .domain("sip.provider.com")
258 /// .build()
259 /// .await.unwrap();
260 /// # })
261 /// ```
262 ///
263 /// ## Custom Port
264 ///
265 /// ```rust
266 /// use rvoip_client_core::ClientBuilder;
267 ///
268 /// # tokio_test::block_on(async {
269 /// let client = ClientBuilder::new()
270 /// .local_address("127.0.0.1:15060".parse().unwrap())
271 /// .build()
272 /// .await.unwrap();
273 /// # })
274 /// ```
275 pub fn local_address(mut self, addr: std::net::SocketAddr) -> Self {
276 self.config.local_sip_addr = addr;
277 self
278 }
279
280 /// Set the local media address for RTP/RTCP traffic
281 ///
282 /// Configures the local address where the client will bind for media traffic.
283 /// This address is used for RTP (Real-time Transport Protocol) audio streams
284 /// and RTCP (Real-time Control Protocol) feedback messages.
285 ///
286 /// # Arguments
287 ///
288 /// * `addr` - The socket address (IP and port) to bind for media communication
289 ///
290 /// # Media Network Considerations
291 ///
292 /// - **Separate from SIP**: Media traffic is independent of SIP signaling
293 /// - **Port Zero**: When set to port 0, uses automatic port allocation via GlobalPortAllocator
294 /// - **Firewall**: RTP requires a range of UDP ports to be accessible
295 /// - **Quality of Service**: Consider network QoS settings for media traffic
296 /// - **NAT Handling**: Media traffic often requires additional NAT traversal
297 ///
298 /// # Examples
299 ///
300 /// ## Auto-assigned Media Port
301 ///
302 /// ```rust
303 /// use rvoip_client_core::ClientBuilder;
304 ///
305 /// # tokio_test::block_on(async {
306 /// let client = ClientBuilder::new()
307 /// .local_address("127.0.0.1:5060".parse().unwrap())
308 /// .media_address("127.0.0.1:0".parse().unwrap()) // Port auto-assigned
309 /// .build()
310 /// .await.unwrap();
311 /// # })
312 /// ```
313 ///
314 /// ## Specific Media Interface
315 ///
316 /// ```rust
317 /// use rvoip_client_core::ClientBuilder;
318 ///
319 /// # tokio_test::block_on(async {
320 /// let client = ClientBuilder::new()
321 /// .local_address("127.0.0.1:5060".parse().unwrap())
322 /// .media_address("127.0.0.1:7000".parse().unwrap())
323 /// .rtp_ports(7000, 8000) // Define RTP port range
324 /// .build()
325 /// .await.unwrap();
326 /// # })
327 /// ```
328 ///
329 /// ## Multi-homed Configuration
330 ///
331 /// ```rust
332 /// use rvoip_client_core::ClientBuilder;
333 ///
334 /// # tokio_test::block_on(async {
335 /// // SIP on one port, media on another
336 /// let client = ClientBuilder::new()
337 /// .local_address("127.0.0.1:5060".parse().unwrap())
338 /// .media_address("127.0.0.1:0".parse().unwrap())
339 /// .build()
340 /// .await.unwrap();
341 /// # })
342 /// ```
343 pub fn media_address(mut self, addr: std::net::SocketAddr) -> Self {
344 self.config.local_media_addr = addr;
345 self
346 }
347
348 /// Set the User-Agent header value for SIP messages
349 ///
350 /// Configures the User-Agent header that will be included in outgoing SIP
351 /// requests and responses. This header identifies the client software and
352 /// version to remote SIP endpoints and servers.
353 ///
354 /// # Arguments
355 ///
356 /// * `user_agent` - String identifying the client application and version
357 ///
358 /// # SIP Protocol Considerations
359 ///
360 /// - **RFC 3261 Compliance**: User-Agent header is recommended in SIP messages
361 /// - **Identification**: Helps with debugging and interoperability testing
362 /// - **Statistics**: SIP servers often collect User-Agent statistics
363 /// - **Format**: Typically follows "ProductName/Version" convention
364 ///
365 /// # Examples
366 ///
367 /// ## Application Identification
368 ///
369 /// ```rust
370 /// use rvoip_client_core::ClientBuilder;
371 ///
372 /// # tokio_test::block_on(async {
373 /// let client = ClientBuilder::new()
374 /// .local_address("127.0.0.1:5060".parse().unwrap())
375 /// .user_agent("MyVoIPApp/2.1.0")
376 /// .build()
377 /// .await.unwrap();
378 /// # })
379 /// ```
380 ///
381 /// ## Platform-Specific Agent
382 ///
383 /// ```rust
384 /// use rvoip_client_core::ClientBuilder;
385 ///
386 /// # tokio_test::block_on(async {
387 /// let platform = std::env::consts::OS;
388 /// let user_agent = format!("EnterprisePhone/1.0 ({})", platform);
389 ///
390 /// let client = ClientBuilder::new()
391 /// .local_address("127.0.0.1:5060".parse().unwrap())
392 /// .user_agent(user_agent)
393 /// .build()
394 /// .await.unwrap();
395 /// # })
396 /// ```
397 ///
398 /// ## SDK Integration
399 ///
400 /// ```rust
401 /// use rvoip_client_core::ClientBuilder;
402 ///
403 /// # tokio_test::block_on(async {
404 /// let client = ClientBuilder::new()
405 /// .local_address("127.0.0.1:5060".parse().unwrap())
406 /// .user_agent("CustomerApp/3.2 rvoip-client-core/1.0")
407 /// .build()
408 /// .await.unwrap();
409 /// # })
410 /// ```
411 pub fn user_agent(mut self, user_agent: impl Into<String>) -> Self {
412 self.config.user_agent = user_agent.into();
413 self
414 }
415
416 /// Set the SIP domain for registration and routing
417 ///
418 /// Configures the SIP domain that this client belongs to. This domain is used
419 /// for SIP registration, request routing, and URI construction. It typically
420 /// corresponds to the SIP service provider's domain.
421 ///
422 /// # Arguments
423 ///
424 /// * `domain` - The SIP domain name (e.g., "sip.provider.com")
425 ///
426 /// # SIP Domain Usage
427 ///
428 /// - **Registration**: Used as the domain in REGISTER requests
429 /// - **URI Construction**: Forms the domain part of SIP URIs (sip:user@domain)
430 /// - **Routing**: Helps determine where to send outbound requests
431 /// - **Authentication**: Often tied to authentication realm
432 ///
433 /// # Examples
434 ///
435 /// ## Service Provider Domain
436 ///
437 /// ```rust
438 /// use rvoip_client_core::ClientBuilder;
439 ///
440 /// # tokio_test::block_on(async {
441 /// let client = ClientBuilder::new()
442 /// .local_address("127.0.0.1:5060".parse().unwrap())
443 /// .domain("sip.provider.com")
444 /// .build()
445 /// .await.unwrap();
446 /// # })
447 /// ```
448 ///
449 /// ## Enterprise Domain
450 ///
451 /// ```rust
452 /// use rvoip_client_core::ClientBuilder;
453 ///
454 /// # tokio_test::block_on(async {
455 /// let client = ClientBuilder::new()
456 /// .local_address("0.0.0.0:5060".parse().unwrap())
457 /// .domain("pbx.company.com")
458 /// .user_agent("CompanyPhone/1.0")
459 /// .build()
460 /// .await.unwrap();
461 /// # })
462 /// ```
463 ///
464 /// ## Local Development
465 ///
466 /// ```rust
467 /// use rvoip_client_core::ClientBuilder;
468 ///
469 /// # tokio_test::block_on(async {
470 /// let client = ClientBuilder::new()
471 /// .local_address("127.0.0.1:5060".parse().unwrap())
472 /// .domain("localhost")
473 /// .build()
474 /// .await.unwrap();
475 /// # })
476 /// ```
477 pub fn domain(mut self, domain: impl Into<String>) -> Self {
478 self.config.domain = Some(domain.into());
479 self
480 }
481
482 /// Set preferred audio codecs in priority order
483 ///
484 /// Configures the list of preferred audio codecs for media negotiation.
485 /// Codecs are specified in order of preference, with the first codec being
486 /// the most preferred. During SDP negotiation, the client will attempt to
487 /// use codecs in the specified order.
488 ///
489 /// # Arguments
490 ///
491 /// * `codecs` - Iterator of codec names in preference order
492 ///
493 /// # Codec Considerations
494 ///
495 /// - **Quality vs Bandwidth**: Balance audio quality with network bandwidth
496 /// - **Compatibility**: Ensure codecs are supported by remote endpoints
497 /// - **Computational Load**: Consider CPU requirements for codec processing
498 /// - **Network Conditions**: Some codecs handle packet loss better than others
499 ///
500 /// # Common Codecs
501 ///
502 /// - **opus**: Modern, high-quality codec with excellent packet loss resilience
503 /// - **G722**: Wideband codec (7kHz) with good quality
504 /// - **PCMU/PCMA**: Standard narrowband codecs with universal compatibility
505 /// - **G729**: Low-bandwidth codec, good for limited networks
506 /// - **iLBC**: Designed for packet loss resilience
507 ///
508 /// # Examples
509 ///
510 /// ## High-Quality Configuration
511 ///
512 /// ```rust
513 /// use rvoip_client_core::ClientBuilder;
514 ///
515 /// # tokio_test::block_on(async {
516 /// let client = ClientBuilder::new()
517 /// .local_address("127.0.0.1:5060".parse().unwrap())
518 /// .codecs(vec!["opus", "G722", "PCMU"])
519 /// .build()
520 /// .await.unwrap();
521 /// # })
522 /// ```
523 ///
524 /// ## Low-Bandwidth Configuration
525 ///
526 /// ```rust
527 /// use rvoip_client_core::ClientBuilder;
528 ///
529 /// # tokio_test::block_on(async {
530 /// let client = ClientBuilder::new()
531 /// .local_address("127.0.0.1:5060".parse().unwrap())
532 /// .codecs(vec!["G729", "iLBC", "PCMU"])
533 /// .build()
534 /// .await.unwrap();
535 /// # })
536 /// ```
537 ///
538 /// ## Universal Compatibility
539 ///
540 /// ```rust
541 /// use rvoip_client_core::ClientBuilder;
542 ///
543 /// # tokio_test::block_on(async {
544 /// let client = ClientBuilder::new()
545 /// .local_address("127.0.0.1:5060".parse().unwrap())
546 /// .codecs(vec!["PCMU", "PCMA", "G722"])
547 /// .build()
548 /// .await.unwrap();
549 /// # })
550 /// ```
551 pub fn codecs<I, S>(mut self, codecs: I) -> Self
552 where
553 I: IntoIterator<Item = S>,
554 S: Into<String>,
555 {
556 self.config.media.preferred_codecs = codecs.into_iter().map(Into::into).collect();
557 self
558 }
559
560 /// Configure media settings using a fluent sub-builder interface
561 ///
562 /// This method provides access to a comprehensive media configuration builder
563 /// that allows fine-grained control over audio processing, codecs, security,
564 /// and network settings. The closure receives a `MediaConfigBuilder` that
565 /// can be chained to configure multiple media options.
566 ///
567 /// # Arguments
568 ///
569 /// * `f` - Closure that configures media settings via `MediaConfigBuilder`
570 ///
571 /// # Media Configuration Options
572 ///
573 /// The sub-builder provides access to:
574 /// - **Codec Selection**: Preferred codecs and priority ordering
575 /// - **Audio Processing**: Echo cancellation, noise suppression, AGC
576 /// - **Security**: SRTP requirements and key management
577 /// - **Network**: Bandwidth limits, port ranges, DSCP marking
578 /// - **Quality**: Sample rates, frame sizes, packet times
579 ///
580 /// # Examples
581 ///
582 /// ## Professional Audio Setup
583 ///
584 /// ```rust
585 /// use rvoip_client_core::ClientBuilder;
586 ///
587 /// # tokio_test::block_on(async {
588 /// let client = ClientBuilder::new()
589 /// .local_address("127.0.0.1:5060".parse().unwrap())
590 /// .with_media(|m| m
591 /// .codecs(vec!["opus", "G722", "PCMU"])
592 /// .echo_cancellation(true)
593 /// .noise_suppression(true)
594 /// .auto_gain_control(true)
595 /// .max_bandwidth_kbps(256)
596 /// .ptime(20)
597 /// )
598 /// .build()
599 /// .await.unwrap();
600 /// # })
601 /// ```
602 ///
603 /// ## Secure Enterprise Configuration
604 ///
605 /// ```rust
606 /// use rvoip_client_core::ClientBuilder;
607 ///
608 /// # tokio_test::block_on(async {
609 /// let client = ClientBuilder::new()
610 /// .local_address("0.0.0.0:5060".parse().unwrap())
611 /// .with_media(|m| m
612 /// .codecs(vec!["opus", "G722"])
613 /// .require_srtp(true)
614 /// .srtp_profiles(vec!["AES_CM_128_HMAC_SHA1_80"])
615 /// .rtp_ports(10000..20000)
616 ///
617 /// .echo_cancellation(true)
618 /// )
619 /// .build()
620 /// .await.unwrap();
621 /// # })
622 /// ```
623 ///
624 /// ## Low-Bandwidth Mobile Setup
625 ///
626 /// ```rust
627 /// use rvoip_client_core::ClientBuilder;
628 ///
629 /// # tokio_test::block_on(async {
630 /// let client = ClientBuilder::new()
631 /// .local_address("127.0.0.1:5060".parse().unwrap())
632 /// .with_media(|m| m
633 /// .codecs(vec!["opus", "iLBC", "G729"])
634 /// .max_bandwidth_kbps(64)
635 /// .ptime(40) // Larger packets for efficiency
636 /// .echo_cancellation(true)
637 /// )
638 /// .build()
639 /// .await.unwrap();
640 /// # })
641 /// ```
642 ///
643 /// ## WebRTC-Style Configuration
644 ///
645 /// ```rust
646 /// use rvoip_client_core::ClientBuilder;
647 ///
648 /// # tokio_test::block_on(async {
649 /// let client = ClientBuilder::new()
650 /// .local_address("127.0.0.1:5060".parse().unwrap())
651 /// .with_media(|m| m
652 /// .codecs(vec!["opus", "G722"])
653 /// .require_srtp(true)
654 /// .echo_cancellation(true)
655 /// .noise_suppression(true)
656 /// .auto_gain_control(true)
657 /// )
658 /// .build()
659 /// .await.unwrap();
660 /// # })
661 /// ```
662 pub fn with_media<F>(mut self, f: F) -> Self
663 where
664 F: FnOnce(MediaConfigBuilder) -> MediaConfigBuilder,
665 {
666 let builder = MediaConfigBuilder::new();
667 self.config.media = f(builder).build();
668 self
669 }
670
671 /// Set media configuration directly
672 pub fn media_config(mut self, media: MediaConfig) -> Self {
673 self.config.media = media;
674 self
675 }
676
677 /// Apply a predefined media configuration preset
678 ///
679 /// Media presets provide quick configuration for common use cases by applying
680 /// a set of predefined media settings. This is convenient when you need
681 /// standard configurations without detailed customization.
682 ///
683 /// # Arguments
684 ///
685 /// * `preset` - The media preset to apply
686 ///
687 /// # Available Presets
688 ///
689 /// - **`VoiceOptimized`**: Optimized for voice calls with echo cancellation and noise suppression
690 /// - **`HighQuality`**: Premium audio quality with wideband codecs and advanced processing
691 /// - **`LowLatency`**: Minimal processing delay for real-time applications
692 /// - **`LowBandwidth`**: Optimized for limited network conditions
693 /// - **`Conference`**: Multi-party conferencing with audio mixing support
694 /// - **`WebRTCCompatible`**: Settings compatible with WebRTC endpoints
695 ///
696 /// # Examples
697 ///
698 /// ## Voice-Optimized Desktop Client
699 ///
700 /// ```rust
701 /// use rvoip_client_core::{ClientBuilder, MediaPreset};
702 ///
703 /// # tokio_test::block_on(async {
704 /// let client = ClientBuilder::new()
705 /// .local_address("127.0.0.1:5060".parse().unwrap())
706 /// .media_preset(MediaPreset::VoiceOptimized)
707 /// .build()
708 /// .await.unwrap();
709 /// # })
710 /// ```
711 ///
712 /// ## Security-Focused System
713 ///
714 /// ```rust
715 /// use rvoip_client_core::{ClientBuilder, MediaPreset};
716 ///
717 /// # tokio_test::block_on(async {
718 /// let client = ClientBuilder::new()
719 /// .local_address("127.0.0.1:5060".parse().unwrap())
720 /// .media_preset(MediaPreset::Secure)
721 /// .domain("premium.voip.com")
722 /// .build()
723 /// .await
724 /// .unwrap();
725 /// # })
726 /// ```
727 ///
728 /// ## Legacy-Compatible Application
729 ///
730 /// ```rust
731 /// use rvoip_client_core::{ClientBuilder, MediaPreset};
732 ///
733 /// # tokio_test::block_on(async {
734 /// let client = ClientBuilder::new()
735 /// .local_address("127.0.0.1:18060".parse().unwrap())
736 /// .media_preset(MediaPreset::Legacy)
737 /// .max_concurrent_calls(50)
738 /// .build()
739 /// .await
740 /// .unwrap();
741 /// # })
742 /// ```
743 ///
744 /// ## Mobile/Limited Bandwidth
745 ///
746 /// ```rust
747 /// use rvoip_client_core::{ClientBuilder, MediaPreset};
748 ///
749 /// # tokio_test::block_on(async {
750 /// let client = ClientBuilder::new()
751 /// .local_address("127.0.0.1:5060".parse().unwrap())
752 /// .media_preset(MediaPreset::LowBandwidth)
753 /// .build()
754 /// .await
755 /// .unwrap();
756 /// # })
757 /// ```
758 pub fn media_preset(mut self, preset: MediaPreset) -> Self {
759 self.config.media = MediaConfig::from_preset(preset);
760 self
761 }
762
763 /// Enable or disable acoustic echo cancellation (AEC)
764 ///
765 /// Acoustic echo cancellation removes the echo of your own voice that
766 /// can occur when the remote party's audio is played through speakers
767 /// instead of headphones. This is essential for hands-free operation.
768 ///
769 /// # Arguments
770 ///
771 /// * `enabled` - Whether to enable echo cancellation processing
772 ///
773 /// # Use Cases
774 ///
775 /// - **Hands-free calling**: Essential when using speakers instead of headphones
776 /// - **Conference rooms**: Critical for room-based conferencing systems
777 /// - **Desktop applications**: Improves user experience in office environments
778 /// - **Mobile devices**: Important for speakerphone functionality
779 ///
780 /// # Performance Considerations
781 ///
782 /// - **CPU Usage**: Echo cancellation requires additional processing power
783 /// - **Latency**: May introduce small amounts of audio delay
784 /// - **Quality**: Generally improves overall call quality significantly
785 ///
786 /// # Examples
787 ///
788 /// ```rust
789 /// use rvoip_client_core::ClientBuilder;
790 ///
791 /// # tokio_test::block_on(async {
792 /// // Enable for desktop/conference use
793 /// let client = ClientBuilder::new()
794 /// .local_address("127.0.0.1:5060".parse().unwrap())
795 /// .echo_cancellation(true)
796 /// .build()
797 /// .await.unwrap();
798 /// # })
799 /// ```
800 pub fn echo_cancellation(mut self, enabled: bool) -> Self {
801 self.config.media.echo_cancellation = enabled;
802 self
803 }
804
805 /// Require or allow SRTP (Secure Real-time Transport Protocol)
806 ///
807 /// SRTP provides encryption and authentication for RTP media streams.
808 /// When required, the client will only establish calls that support
809 /// encrypted media, rejecting unencrypted connections.
810 ///
811 /// # Arguments
812 ///
813 /// * `required` - Whether SRTP is mandatory for all media streams
814 ///
815 /// # Security Considerations
816 ///
817 /// - **Data Protection**: Encrypts audio streams end-to-end
818 /// - **Integrity**: Protects against media tampering and injection
819 /// - **Compliance**: May be required for regulatory compliance
820 /// - **Performance**: Adds minimal computational overhead
821 ///
822 /// # Compatibility
823 ///
824 /// - **WebRTC**: SRTP is mandatory in WebRTC implementations
825 /// - **Legacy Systems**: Some older SIP devices may not support SRTP
826 /// - **Enterprise**: Most modern enterprise systems support SRTP
827 ///
828 /// # Examples
829 ///
830 /// ## Security-First Configuration
831 ///
832 /// ```rust
833 /// use rvoip_client_core::ClientBuilder;
834 ///
835 /// # tokio_test::block_on(async {
836 /// let client = ClientBuilder::new()
837 /// .local_address("127.0.0.1:5060".parse().unwrap())
838 /// .require_srtp(true)
839 /// .domain("secure.voip.com")
840 /// .build()
841 /// .await.unwrap();
842 /// # })
843 /// ```
844 ///
845 /// ## Flexible Security (SRTP preferred but not required)
846 ///
847 /// ```rust
848 /// use rvoip_client_core::ClientBuilder;
849 ///
850 /// # tokio_test::block_on(async {
851 /// let client = ClientBuilder::new()
852 /// .local_address("127.0.0.1:5060".parse().unwrap())
853 /// .require_srtp(false) // Allow fallback to RTP
854 /// .build()
855 /// .await.unwrap();
856 /// # })
857 /// ```
858 pub fn require_srtp(mut self, required: bool) -> Self {
859 self.config.media.require_srtp = required;
860 self
861 }
862
863 /// Set the UDP port range for RTP media traffic
864 ///
865 /// Configures the range of UDP ports that will be used for RTP and RTCP
866 /// media streams. The client will allocate ports within this range for
867 /// each active call's media streams.
868 ///
869 /// # Arguments
870 ///
871 /// * `start` - First port in the range (inclusive)
872 /// * `end` - Last port in the range (inclusive)
873 ///
874 /// # Port Planning Considerations
875 ///
876 /// - **Concurrent Calls**: Each call typically uses 2 ports (RTP + RTCP)
877 /// - **Firewall Configuration**: All ports in range must be accessible
878 /// - **Range Size**: Should accommodate maximum expected simultaneous calls
879 /// - **Standard Ranges**: Many systems use 10000-20000 or 16384-32767
880 ///
881 /// # Examples
882 ///
883 /// ## Standard Enterprise Range
884 ///
885 /// ```rust
886 /// use rvoip_client_core::ClientBuilder;
887 ///
888 /// # tokio_test::block_on(async {
889 /// let client = ClientBuilder::new()
890 /// .local_address("0.0.0.0:5060".parse().unwrap())
891 /// .rtp_ports(10000, 20000) // 10,000 ports for ~5,000 calls
892 /// .max_concurrent_calls(1000)
893 /// .build()
894 /// .await.unwrap();
895 /// # })
896 /// ```
897 ///
898 /// ## Small Office Configuration
899 ///
900 /// ```rust
901 /// use rvoip_client_core::ClientBuilder;
902 ///
903 /// # tokio_test::block_on(async {
904 /// let client = ClientBuilder::new()
905 /// .local_address("127.0.0.1:5060".parse().unwrap())
906 /// .rtp_ports(7000, 7100) // 100 ports for ~50 calls
907 /// .max_concurrent_calls(25)
908 /// .build()
909 /// .await.unwrap();
910 /// # })
911 /// ```
912 ///
913 /// ## High-Density Server
914 ///
915 /// ```rust
916 /// use rvoip_client_core::ClientBuilder;
917 ///
918 /// # tokio_test::block_on(async {
919 /// let client = ClientBuilder::new()
920 /// .local_address("0.0.0.0:5060".parse().unwrap())
921 /// .rtp_ports(16384, 32767) // ~16k ports for high capacity
922 /// .max_concurrent_calls(5000)
923 /// .build()
924 /// .await.unwrap();
925 /// # })
926 /// ```
927 pub fn rtp_ports(mut self, start: u16, end: u16) -> Self {
928 self.config.media.rtp_port_start = start;
929 self.config.media.rtp_port_end = end;
930 self
931 }
932
933 /// Set the maximum number of concurrent calls
934 ///
935 /// Limits the number of simultaneous active calls that the client can handle.
936 /// This prevents resource exhaustion and ensures predictable performance
937 /// under load. New call attempts beyond this limit will be rejected.
938 ///
939 /// # Arguments
940 ///
941 /// * `max` - Maximum number of concurrent calls allowed
942 ///
943 /// # Resource Planning
944 ///
945 /// Consider the following resources when setting limits:
946 /// - **CPU**: Audio processing scales with concurrent calls
947 /// - **Memory**: Each call maintains state and buffers
948 /// - **Network**: Bandwidth requirements multiply with call count
949 /// - **Ports**: Each call requires RTP/RTCP port pairs
950 ///
951 /// # Examples
952 ///
953 /// ## Desktop Client
954 ///
955 /// ```rust
956 /// use rvoip_client_core::ClientBuilder;
957 ///
958 /// # tokio_test::block_on(async {
959 /// let client = ClientBuilder::new()
960 /// .local_address("127.0.0.1:5060".parse().unwrap())
961 /// .max_concurrent_calls(5) // Typical for desktop use
962 /// .build()
963 /// .await.unwrap();
964 /// # })
965 /// ```
966 ///
967 /// ## Small Business Server
968 ///
969 /// ```rust
970 /// use rvoip_client_core::ClientBuilder;
971 ///
972 /// # tokio_test::block_on(async {
973 /// let client = ClientBuilder::new()
974 /// .local_address("0.0.0.0:5060".parse().unwrap())
975 /// .max_concurrent_calls(100)
976 /// .rtp_ports(10000, 10500) // Adequate port range
977 /// .build()
978 /// .await.unwrap();
979 /// # })
980 /// ```
981 ///
982 /// ## High-Capacity System
983 ///
984 /// ```rust
985 /// use rvoip_client_core::ClientBuilder;
986 ///
987 /// # tokio_test::block_on(async {
988 /// let client = ClientBuilder::new()
989 /// .local_address("0.0.0.0:5060".parse().unwrap())
990 /// .max_concurrent_calls(10000)
991 /// .rtp_ports(10000, 40000) // Large port range
992 /// .with_media(|m| m
993 /// .codecs(vec!["G729", "PCMU"]) // Low-bandwidth codecs
994 /// .max_bandwidth_kbps(64)
995 /// )
996 /// .build()
997 /// .await.unwrap();
998 /// # })
999 /// ```
1000 pub fn max_concurrent_calls(mut self, max: usize) -> Self {
1001 self.config.max_concurrent_calls = max;
1002 self
1003 }
1004
1005 /// Build and initialize the SIP client
1006 ///
1007 /// Consumes the builder and creates a fully configured `ClientManager` instance.
1008 /// This method performs all necessary initialization including network binding,
1009 /// media system setup, and internal component initialization.
1010 ///
1011 /// # Returns
1012 ///
1013 /// Returns a `ClientResult<Arc<ClientManager>>` which will be:
1014 /// - `Ok(client)` on successful initialization
1015 /// - `Err(error)` if initialization fails for any reason
1016 ///
1017 /// # Initialization Process
1018 ///
1019 /// The build process performs several critical steps:
1020 /// 1. **Configuration Validation**: Verifies all settings are valid and consistent
1021 /// 2. **Network Binding**: Binds to specified SIP and media addresses
1022 /// 3. **Media System Init**: Initializes audio processing and codec subsystems
1023 /// 4. **Component Startup**: Starts internal services and background tasks
1024 /// 5. **Resource Allocation**: Reserves ports, memory, and other resources
1025 ///
1026 /// # Error Conditions
1027 ///
1028 /// The build process can fail for various reasons:
1029 /// - **Network Errors**: Port already in use, invalid addresses, permission denied
1030 /// - **Resource Limits**: Insufficient system resources, file descriptor limits
1031 /// - **Configuration Errors**: Invalid settings, unsupported codec combinations
1032 /// - **System Errors**: Audio device access, network interface issues
1033 ///
1034 /// # Examples
1035 ///
1036 /// ## Basic Client Creation
1037 ///
1038 /// ```rust
1039 /// use rvoip_client_core::ClientBuilder;
1040 ///
1041 /// # tokio_test::block_on(async {
1042 /// let client = ClientBuilder::new()
1043 /// .local_address("127.0.0.1:5060".parse().unwrap())
1044 /// .build()
1045 /// .await.unwrap();
1046 ///
1047 /// // Client is ready for use
1048 /// println!("Client initialized successfully");
1049 /// # })
1050 /// ```
1051 ///
1052 /// ## Error Handling
1053 ///
1054 /// ```rust
1055 /// use rvoip_client_core::ClientBuilder;
1056 ///
1057 /// # tokio_test::block_on(async {
1058 /// match ClientBuilder::new()
1059 /// .local_address("127.0.0.1:5060".parse().unwrap())
1060 /// .domain("sip.provider.com")
1061 /// .build()
1062 /// .await
1063 /// {
1064 /// Ok(client) => {
1065 /// println!("Client ready for SIP operations");
1066 /// // Use client...
1067 /// }
1068 /// Err(error) => {
1069 /// eprintln!("Failed to initialize client: {}", error);
1070 /// // Handle initialization failure...
1071 /// }
1072 /// }
1073 /// # })
1074 /// ```
1075 ///
1076 /// ## Production Configuration
1077 ///
1078 /// ```rust
1079 /// use rvoip_client_core::{ClientBuilder, MediaPreset};
1080 ///
1081 /// # tokio_test::block_on(async {
1082 /// let client = ClientBuilder::new()
1083 /// .local_address("0.0.0.0:5060".parse().unwrap())
1084 /// .media_address("192.168.1.100:0".parse().unwrap())
1085 /// .domain("enterprise.company.com")
1086 /// .user_agent("CompanyPhone/3.1.0")
1087 /// .media_preset(MediaPreset::VoiceOptimized)
1088 /// .max_concurrent_calls(50)
1089 /// .rtp_ports(10000, 20000)
1090 /// .require_srtp(true)
1091 /// .build()
1092 /// .await.unwrap();
1093 ///
1094 /// println!("Enterprise client initialized and ready");
1095 /// # })
1096 /// ```
1097 ///
1098 /// # Thread Safety
1099 ///
1100 /// The returned `ClientManager` is wrapped in an `Arc` for safe sharing
1101 /// across threads and async tasks. All client operations are thread-safe.
1102 ///
1103 /// # Resource Management
1104 ///
1105 /// The client automatically manages its resources and will clean up
1106 /// properly when dropped. For graceful shutdown, use the client's
1107 /// shutdown methods before dropping.
1108 pub async fn build(mut self) -> ClientResult<Arc<ClientManager>> {
1109 // If media address has default IP (127.0.0.1), update to match SIP IP but keep port
1110 let default_media_addr: std::net::SocketAddr = "127.0.0.1:0".parse().unwrap();
1111 if self.config.local_media_addr.ip() == default_media_addr.ip() {
1112 let sip_ip = self.config.local_sip_addr.ip();
1113 let media_port = self.config.local_media_addr.port(); // Keep existing port (0 = auto)
1114 self.config.local_media_addr = format!("{}:{}", sip_ip, media_port).parse().unwrap();
1115 }
1116 ClientManager::new(self.config).await
1117 }
1118}
1119
1120/// Default implementation for ClientBuilder
1121///
1122/// Creates a new `ClientBuilder` with default configuration settings.
1123/// This is equivalent to calling `ClientBuilder::new()`.
1124///
1125/// # Examples
1126///
1127/// ```rust
1128/// use rvoip_client_core::ClientBuilder;
1129///
1130/// // These are equivalent:
1131/// let builder1 = ClientBuilder::new();
1132/// let builder2 = ClientBuilder::default();
1133///
1134/// # tokio_test::block_on(async {
1135/// let client = ClientBuilder::default()
1136/// .local_address("127.0.0.1:5060".parse().unwrap())
1137/// .build()
1138/// .await.unwrap();
1139/// # })
1140/// ```
1141impl Default for ClientBuilder {
1142 fn default() -> Self {
1143 Self::new()
1144 }
1145}