Struct DialogClient

Source
pub struct DialogClient { /* private fields */ }
Expand description

High-level client interface for SIP dialog management

The DialogClient provides a comprehensive, easy-to-use interface for client-side SIP operations. It handles the complexities of SIP dialog management while offering powerful features for call control, media negotiation, and session coordination.

§Key Capabilities

  • Call Management: Create, control, and terminate voice/video calls
  • Dialog Operations: Full SIP dialog lifecycle management
  • Media Coordination: Integration with media layers through session events
  • Request/Response Handling: Send arbitrary SIP methods and build responses
  • Authentication: Built-in support for SIP authentication challenges
  • Statistics & Monitoring: Real-time metrics and dialog state tracking

§Constructor Patterns

The DialogClient supports multiple construction patterns to fit different use cases:

use rvoip_dialog_core::api::{DialogClient, ClientConfig};
use rvoip_transaction_core::TransactionManager;
use std::sync::Arc;

// Your application manages transport
let tx_mgr = Arc::new(TransactionManager::new_sync(transport));
let config = ClientConfig::new("127.0.0.1:0".parse()?);

let client = DialogClient::with_dependencies(tx_mgr, config).await?;

§Pattern 2: Global Events (Best for Event Processing)

use rvoip_dialog_core::api::{DialogClient, ClientConfig};
use rvoip_transaction_core::{TransactionManager, TransactionEvent};
use tokio::sync::mpsc;
use std::sync::Arc;

let tx_mgr = Arc::new(TransactionManager::new_sync(transport));
let (events_tx, events_rx) = mpsc::channel(1000);
let config = ClientConfig::new("127.0.0.1:0".parse()?);

let client = DialogClient::with_global_events(tx_mgr, events_rx, config).await?;

§Complete Usage Example

use rvoip_dialog_core::api::{DialogClient, DialogApi, ClientConfig};
use rvoip_transaction_core::TransactionManager;
use std::sync::Arc;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Set up dependencies
    let tx_mgr = Arc::new(TransactionManager::new_sync(transport));
    let config = ClientConfig::new("192.168.1.100:5060".parse()?)
        .with_from_uri("sip:alice@company.com")
        .with_auth("alice", "secret123");
     
    // Create and start client
    let client = DialogClient::with_dependencies(tx_mgr, config).await?;
    client.start().await?;
     
    // Make an outgoing call
    let call = client.make_call(
        "sip:alice@company.com",
        "sip:bob@partner.com",
        Some("v=0\r\no=alice 123 456 IN IP4 192.168.1.100\r\n...".to_string())
    ).await?;
     
    println!("Call initiated: {}", call.call_id());
     
    // Call operations
    tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
    call.hold(Some("SDP with hold attributes".to_string())).await?;
     
    tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;
    call.resume(Some("SDP with active media".to_string())).await?;
     
    // Transfer the call
    call.transfer("sip:voicemail@company.com".to_string()).await?;
     
    // Get statistics
    let stats = client.get_stats().await;
    println!("Client stats: {} active dialogs, {} total", 
        stats.active_dialogs, stats.total_dialogs);
     
    // Clean shutdown
    client.stop().await?;
     
    Ok(())
}

§Advanced Dialog Operations

use rvoip_dialog_core::api::DialogClient;
use rvoip_sip_core::{Method, StatusCode};

// Create a dialog without sending initial request
let dialog = client.create_dialog("sip:me@here.com", "sip:you@there.com").await?;
 
// Send custom SIP methods within the dialog
let info_tx = client.send_info(&dialog.id(), "Application-specific data".to_string()).await?;
let notify_tx = client.send_notify(&dialog.id(), "presence".to_string(), Some("online".to_string())).await?;
let update_tx = client.send_update(&dialog.id(), Some("Updated media SDP".to_string())).await?;
 
// Monitor dialog state
let state = client.get_dialog_state(&dialog.id()).await?;
println!("Dialog state: {:?}", state);
 
// Build and send a response (if acting as UAS)
let response = client.build_response(&transaction_id, StatusCode::Ok, Some("Success".to_string())).await?;
client.send_response(&transaction_id, response).await?;
 
// Terminate the dialog
client.terminate_dialog(&dialog.id()).await?;

§Session Coordination Integration

use rvoip_dialog_core::api::{DialogClient, DialogApi};
use rvoip_dialog_core::events::SessionCoordinationEvent;
use tokio::sync::mpsc;

// Set up session coordination for media management
let (session_tx, mut session_rx) = mpsc::channel(100);
client.set_session_coordinator(session_tx).await?;
client.start().await?;

// Handle session events from the client
let session_handler = tokio::spawn(async move {
    while let Some(event) = session_rx.recv().await {
        match event {
            SessionCoordinationEvent::IncomingCall { dialog_id, request, .. } => {
                println!("Incoming call on dialog {}", dialog_id);
                // Extract SDP, set up media, send response
            },
            SessionCoordinationEvent::CallAnswered { dialog_id, session_answer } => {
                println!("Call {} answered", dialog_id);
                // Configure media streams based on SDP answer
            },
            SessionCoordinationEvent::CallTerminated { dialog_id, reason } => {
                println!("Call {} terminated: {}", dialog_id, reason);
                // Clean up media resources
            },
            _ => {}
        }
    }
});

// Make calls while session handler processes events
let call = client.make_call("sip:me@here.com", "sip:you@there.com", None).await?;
 
// Session events will be automatically generated and handled
tokio::time::sleep(tokio::time::Duration::from_secs(10)).await;
call.hangup().await?;
 

§Error Handling Strategies

use rvoip_dialog_core::api::{DialogClient, ApiError};
use tokio::time::{sleep, Duration};

// Retry logic for network errors
let mut attempts = 0;
let max_attempts = 3;

loop {
    match client.make_call("sip:me@here.com", "sip:you@there.com", None).await {
        Ok(call) => {
            println!("Call successful: {}", call.call_id());
            break;
        },
        Err(ApiError::Network { message }) if attempts < max_attempts => {
            attempts += 1;
            println!("Network error (attempt {}): {}", attempts, message);
            sleep(Duration::from_secs(2u64.pow(attempts))).await; // Exponential backoff
            continue;
        },
        Err(ApiError::Configuration { message }) => {
            eprintln!("Configuration error: {}", message);
            // Fix configuration and restart
            break;
        },
        Err(ApiError::Protocol { message }) => {
            eprintln!("SIP protocol error: {}", message);
            // Log for debugging, continue with other operations
            break;
        },
        Err(e) => {
            eprintln!("Unrecoverable error: {}", e);
            break;
        }
    }
}

Implementations§

Source§

impl DialogClient

Source

pub async fn new(local_address: &str) -> ApiResult<Self>

Create a new dialog client with simple configuration

This is the easiest way to create a client - just provide a local address and the client will be configured with sensible defaults.

§Arguments
  • local_address - Local address to use (e.g., “127.0.0.1:0”)
§Returns

A configured DialogClient ready to start

Source

pub async fn with_config(config: ClientConfig) -> ApiResult<Self>

Create a dialog client with custom configuration

ARCHITECTURAL NOTE: This method requires dependency injection to maintain proper separation of concerns. dialog-core should not directly manage transport concerns - that’s the responsibility of transaction-core.

Use with_global_events() or with_dependencies() instead, where you provide a pre-configured TransactionManager that handles all transport setup.

§Arguments
  • config - Client configuration (for validation and future use)
§Returns

An error directing users to the proper dependency injection constructors

Source

pub async fn with_global_events( transaction_manager: Arc<TransactionManager>, transaction_events: Receiver<TransactionEvent>, config: ClientConfig, ) -> ApiResult<Self>

Create a dialog client with dependency injection and global events (RECOMMENDED)

This is the recommended constructor for production applications. It uses global transaction event subscription which provides better event handling reliability and prevents event loss that can occur with per-transaction subscriptions.

§Why Global Events?
  • Reliable Event Processing: All transaction events flow through a single channel
  • No Event Loss: Events are queued and processed in order
  • Better Resource Management: Single event loop handles all transactions
  • Cleaner Architecture: Separation between event generation and consumption
§Usage Pattern
use rvoip_dialog_core::api::{DialogClient, DialogApi, ClientConfig};
use rvoip_transaction_core::{TransactionManager, TransactionEvent};
use tokio::sync::mpsc;
use std::sync::Arc;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Set up transport layer (your responsibility)
     
    // Create transaction manager
    let tx_mgr = Arc::new(TransactionManager::new_sync(transport));
     
    // Set up global event channel
    let (event_tx, event_rx) = mpsc::channel(1000);
     
    // Configure client
    let config = ClientConfig::new("192.168.1.100:5060".parse()?)
        .with_from_uri("sip:client@company.com")
        .with_auth("client_user", "password123");
     
    // Create client with global events
    let client = DialogClient::with_global_events(tx_mgr, event_rx, config).await?;
     
    // Start client and begin processing
    client.start().await?;
     
    // Client is now ready for operations
    let call = client.make_call(
        "sip:client@company.com",
        "sip:target@partner.com",
        None
    ).await?;
     
    // Clean shutdown
    call.hangup().await?;
    client.stop().await?;
     
    Ok(())
}
§Advanced Event Processing
use rvoip_dialog_core::api::{DialogClient, ClientConfig, DialogApi};
use rvoip_transaction_core::{TransactionManager, TransactionEvent};
use tokio::sync::mpsc;
use std::sync::Arc;

let tx_mgr = Arc::new(TransactionManager::new_sync(transport));
let (event_tx, event_rx) = mpsc::channel(1000);
let config = ClientConfig::new("127.0.0.1:0".parse()?);

// Create client
let client = DialogClient::with_global_events(tx_mgr.clone(), event_rx, config).await?;

// You can also handle transaction events directly if needed
tokio::spawn(async move {
    // This would be your custom transaction event processor
    // The client gets its own copy of events through the channel
});

client.start().await?;
§Arguments
  • transaction_manager - Pre-configured transaction manager with transport
  • transaction_events - Global transaction event receiver channel
  • config - Client configuration with network and authentication settings
§Returns

A configured DialogClient ready to start processing

§Errors
  • ApiError::Configuration - Invalid configuration parameters
  • ApiError::Internal - Failed to create dialog manager with global events
Source

pub async fn with_dependencies( transaction_manager: Arc<TransactionManager>, config: ClientConfig, ) -> ApiResult<Self>

Create a dialog client with dependency injection

This constructor provides direct dependency injection for scenarios where you need full control over the dependencies. It’s particularly useful for testing, legacy integration, or when you have existing infrastructure to integrate with.

§When to Use This Pattern
  • Testing: When you need to inject mock dependencies
  • Legacy Integration: When working with existing transaction managers
  • Simple Use Cases: When you don’t need complex event processing
  • Custom Event Handling: When you want to handle transaction events differently
§Production Considerations

⚠️ Warning: This method uses individual transaction event subscriptions which may not be as reliable as global event subscriptions. For production applications, consider using with_global_events() instead.

§Usage Examples
§Basic Usage
use rvoip_dialog_core::api::{DialogClient, DialogApi, ClientConfig};
use rvoip_transaction_core::TransactionManager;
use std::sync::Arc;

// Set up transport (your responsibility)
let tx_mgr = Arc::new(TransactionManager::new_sync(transport));
let config = ClientConfig::new("127.0.0.1:0".parse()?);

// Create client with dependency injection
let client = DialogClient::with_dependencies(tx_mgr, config).await?;
client.start().await?;

// Client is ready for use
let stats = client.get_stats().await;
println!("Client initialized: {} active dialogs", stats.active_dialogs);
§Testing Pattern
use rvoip_dialog_core::api::{DialogClient, ClientConfig};
use rvoip_transaction_core::TransactionManager;
use std::sync::Arc;

// Create mock transport for testing
let tx_mgr = Arc::new(TransactionManager::new_sync(mock_transport));
let config = ClientConfig::new("127.0.0.1:0".parse()?)
    .with_from_uri("sip:test@localhost");

let client = DialogClient::with_dependencies(tx_mgr, config).await?;

// Test client operations
assert_eq!(client.config().from_uri.as_ref().unwrap(), "sip:test@localhost");
§Integration with Existing Infrastructure
use rvoip_dialog_core::api::{DialogClient, ClientConfig, DialogApi};
use rvoip_transaction_core::TransactionManager;
use std::sync::Arc;

// Use existing transaction manager from your infrastructure
let config = ClientConfig::new("10.0.1.50:5060".parse()?)
    .with_from_uri("sip:service@internal.company.com")
    .with_auth("service", "internal_password");

let client = DialogClient::with_dependencies(existing_tx_mgr, config).await?;

// Integrate with existing systems
client.start().await?;
§Arguments
  • transaction_manager - Pre-configured transaction manager with transport
  • config - Client configuration with network and authentication settings
§Returns

A configured DialogClient ready to start processing

§Errors
  • ApiError::Configuration - Invalid configuration parameters
  • ApiError::Internal - Failed to create dialog manager
Source

pub async fn make_call( &self, from_uri: &str, to_uri: &str, sdp_offer: Option<String>, ) -> ApiResult<CallHandle>

Make an outgoing call

Creates a new SIP dialog and initiates an outgoing call by sending an INVITE request. This is the primary method for establishing voice/video calls and handles all the complexity of SIP dialog creation, request generation, and initial negotiation.

§Call Flow
  1. URI Validation: Validates and parses the provided SIP URIs
  2. Dialog Creation: Creates a new outgoing dialog with unique identifiers
  3. INVITE Generation: Builds and sends an INVITE request with optional SDP
  4. Handle Creation: Returns a CallHandle for subsequent call operations
  5. Statistics Update: Updates internal call tracking metrics
§Usage Examples
§Basic Call
use rvoip_dialog_core::api::DialogClient;

let call = client.make_call(
    "sip:alice@company.com",      // Who the call is from
    "sip:bob@partner.com",        // Who to call
    None                          // No SDP offer (late negotiation)
).await?;

println!("Call initiated: {}", call.call_id());
// Call is now ringing, wait for response...
§Call with SDP Offer (Early Media Negotiation)
use rvoip_dialog_core::api::DialogClient;

let sdp_offer = r#"v=0
o=alice 2890844526 2890844527 IN IP4 192.168.1.100
s=Call
c=IN IP4 192.168.1.100
t=0 0
m=audio 5004 RTP/AVP 0
a=rtpmap:0 PCMU/8000"#;

let call = client.make_call(
    "sip:alice@company.com",
    "sip:bob@partner.com",
    Some(sdp_offer.to_string())
).await?;

println!("Call with media offer sent: {}", call.call_id());
§Production Call with Error Handling
use rvoip_dialog_core::api::{DialogClient, ApiError};
use tokio::time::{timeout, Duration};

// Set a timeout for the call setup
let call_result = timeout(Duration::from_secs(30), async {
    client.make_call(
        "sip:service@company.com",
        "sip:customer@external.com",
        None
    ).await
}).await;

match call_result {
    Ok(Ok(call)) => {
        println!("Call successful: {}", call.call_id());
         
        // Set up call monitoring
        tokio::spawn(async move {
            if call.is_active().await {
                println!("Call is active and can be managed");
            }
        });
    },
    Ok(Err(ApiError::Configuration { message })) => {
        eprintln!("Configuration error: {}", message);
        // Fix URIs and retry
    },
    Ok(Err(ApiError::Network { message })) => {
        eprintln!("Network error: {}", message);
        // Check connectivity and retry
    },
    Err(_) => {
        eprintln!("Call setup timed out");
        // Handle timeout scenario
    },
    Ok(Err(e)) => {
        eprintln!("Call failed: {}", e);
    }
}
§Batch Call Operations
use rvoip_dialog_core::api::DialogClient;

let call_targets = vec![
    ("sip:alice@company.com", "sip:customer1@external.com"),
    ("sip:alice@company.com", "sip:customer2@external.com"),
    ("sip:alice@company.com", "sip:customer3@external.com"),
];

// Make multiple calls sequentially for simplicity
let mut calls = Vec::new();
for (from, to) in call_targets {
    let call = client.make_call(from, to, None).await?;
    calls.push(call);
}
println!("Successfully initiated {} calls", calls.len());

// Monitor all calls
for call in calls {
    let info = call.info().await?;
    println!("Call {}: {} -> {} ({})", 
        call.call_id(), info.local_uri, info.remote_uri, info.state);
}
§Arguments
  • from_uri - Local SIP URI (From header) - who the call is from
  • to_uri - Remote SIP URI (To header) - who to call
  • sdp_offer - Optional SDP offer for media negotiation
§Returns

A CallHandle for managing the call lifecycle and operations

§Errors
  • ApiError::Configuration - Invalid SIP URIs provided
  • ApiError::Dialog - Failed to create dialog or send INVITE
  • ApiError::Internal - Internal dialog manager error
Source

pub async fn create_dialog( &self, from_uri: &str, to_uri: &str, ) -> ApiResult<DialogHandle>

Create a new dialog without sending a request

Creates a SIP dialog without immediately sending an INVITE or other initial request. This is useful for advanced scenarios where you need fine-grained control over the dialog lifecycle, want to send custom requests, or need to prepare dialogs for specific protocol sequences.

§When to Use This Method
  • Custom Protocol Sequences: When you need to send non-INVITE initial requests
  • Conditional Call Setup: When call initiation depends on external factors
  • Advanced Dialog Management: When you need dialog state before sending requests
  • Testing Scenarios: When you want to test dialog creation independently
  • Batch Operations: When preparing multiple dialogs for coordinated operations
§Usage Examples
§Basic Dialog Creation
use rvoip_dialog_core::api::DialogClient;
use rvoip_sip_core::Method;

// Create dialog without initial request
let dialog = client.create_dialog(
    "sip:alice@company.com",
    "sip:bob@partner.com"
).await?;

println!("Dialog created: {}", dialog.id());

// Now you can send custom requests
dialog.send_request(Method::Options, None).await?;
dialog.send_request(Method::Info, Some("Custom info".to_string())).await?;

// Check dialog state
let state = dialog.state().await?;
println!("Dialog state: {:?}", state);
§Conditional Call Setup
use rvoip_dialog_core::api::DialogClient;
use rvoip_sip_core::Method;

// Create dialog first
let dialog = client.create_dialog(
    "sip:service@company.com",
    "sip:customer@external.com"
).await?;

// Check external conditions before proceeding
if check_customer_availability().await? {
    // Send INVITE if customer is available
    dialog.send_request(Method::Invite, Some("SDP offer".to_string())).await?;
    println!("Call initiated for available customer");
} else {
    // Send MESSAGE instead
    dialog.send_request(Method::Message, Some("Customer callback requested".to_string())).await?;
    println!("Message sent to unavailable customer");
}
§Advanced Protocol Sequences
use rvoip_dialog_core::api::DialogClient;
use rvoip_sip_core::Method;

let dialog = client.create_dialog(
    "sip:alice@company.com",
    "sip:conference@partner.com"
).await?;

// Custom protocol: Send OPTIONS first to check capabilities
let options_tx = dialog.send_request(Method::Options, None).await?;
println!("Sent OPTIONS: {}", options_tx);

// Wait for response processing (in real code, you'd handle this via events)
tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;

// Send SUBSCRIBE for presence information
let subscribe_tx = dialog.send_request(
    Method::Subscribe, 
    Some("Event: presence\r\nExpires: 3600".to_string())
).await?;
println!("Sent SUBSCRIBE: {}", subscribe_tx);

// Finally, send INVITE for the actual call
let invite_tx = dialog.send_request(Method::Invite, Some("SDP offer".to_string())).await?;
println!("Sent INVITE: {}", invite_tx);
§Batch Dialog Preparation
use rvoip_dialog_core::api::DialogClient;
use std::future::Future;

let targets = vec![
    "sip:customer1@external.com",
    "sip:customer2@external.com", 
    "sip:customer3@external.com",
];

// Create multiple dialogs concurrently using join_all from std
let mut dialogs = Vec::new();
for target in targets {
    let dialog = client.create_dialog("sip:service@company.com", target).await?;
    dialogs.push(dialog);
}
println!("Created {} dialogs", dialogs.len());

// Now you can coordinate operations across all dialogs
for (i, dialog) in dialogs.iter().enumerate() {
    // Stagger call initiation
    tokio::time::sleep(tokio::time::Duration::from_millis(i as u64 * 100)).await;
    dialog.send_request(rvoip_sip_core::Method::Invite, None).await?;
}
§Arguments
  • from_uri - Local SIP URI (From header)
  • to_uri - Remote SIP URI (To header)
§Returns

A DialogHandle for the new dialog

§Errors
  • ApiError::Configuration - Invalid SIP URIs provided
  • ApiError::Dialog - Failed to create dialog
  • ApiError::Internal - Internal dialog manager error
Source

pub async fn send_request_in_dialog( &self, dialog_id: &DialogId, method: Method, body: Option<Bytes>, ) -> ApiResult<TransactionKey>

Send a SIP request within an existing dialog

Sends arbitrary SIP methods within an established dialog. This method provides direct access to SIP protocol operations and is essential for session-core coordination, custom protocol implementations, and advanced call control.

§Supported SIP Methods

This method can send any SIP method within a dialog context:

  • INVITE: Re-INVITE for media changes, call transfers
  • BYE: Call termination (prefer using send_bye() convenience method)
  • UPDATE: Media parameter updates (RFC 3311)
  • INFO: Application-specific information (RFC 6086)
  • REFER: Call transfers and redirections (RFC 3515)
  • NOTIFY: Event notifications (RFC 3265)
  • MESSAGE: Instant messaging within dialogs
  • OPTIONS: Capability queries
  • SUBSCRIBE: Event subscriptions
§Usage Examples
§Media Management with UPDATE
use rvoip_dialog_core::api::DialogClient;
use rvoip_sip_core::Method;
use rvoip_dialog_core::dialog::DialogId;

// Send UPDATE to modify media parameters
let updated_sdp = r#"v=0
o=alice 2890844526 2890844528 IN IP4 192.168.1.100
s=Updated Call
c=IN IP4 192.168.1.100
t=0 0
m=audio 5004 RTP/AVP 0 8
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000"#;

let tx_key = client.send_request_in_dialog(
    &dialog_id,
    Method::Update,
    Some(bytes::Bytes::from(updated_sdp))
).await?;

println!("Sent UPDATE request: {}", tx_key);
§Application Information Exchange
use rvoip_dialog_core::api::DialogClient;
use rvoip_sip_core::Method;
use rvoip_dialog_core::dialog::DialogId;

// Send application-specific information
let app_data = r#"Content-Type: application/json

{
  "action": "screen_share_request",
  "timestamp": "2024-01-15T10:30:00Z",
  "session_id": "abc123"
}"#;

let tx_key = client.send_request_in_dialog(
    &dialog_id,
    Method::Info,
    Some(bytes::Bytes::from(app_data))
).await?;

println!("Sent INFO with application data: {}", tx_key);
§Event Notifications
use rvoip_dialog_core::api::DialogClient;
use rvoip_sip_core::Method;
use rvoip_dialog_core::dialog::DialogId;

// Send NOTIFY for presence update
let notify_body = r#"Event: presence
Subscription-State: active;expires=3600
Content-Type: application/pidf+xml

<?xml version="1.0" encoding="UTF-8"?>
<presence xmlns="urn:ietf:params:xml:ns:pidf" entity="sip:alice@company.com">
  <tuple id="tuple1">
    <status><basic>open</basic></status>
    <contact>sip:alice@company.com</contact>
  </tuple>
</presence>"#;

let tx_key = client.send_request_in_dialog(
    &dialog_id,
    Method::Notify,
    Some(bytes::Bytes::from(notify_body))
).await?;

println!("Sent NOTIFY for presence: {}", tx_key);
§Call Transfer with REFER
use rvoip_dialog_core::api::DialogClient;
use rvoip_sip_core::Method;
use rvoip_dialog_core::dialog::DialogId;

// Send REFER for call transfer
let refer_body = r#"Refer-To: sip:bob@partner.com
Referred-By: sip:alice@company.com
Contact: sip:alice@company.com
Content-Length: 0"#;

let tx_key = client.send_request_in_dialog(
    &dialog_id,
    Method::Refer,
    Some(bytes::Bytes::from(refer_body))
).await?;

println!("Sent REFER for transfer: {}", tx_key);
§Session Coordination Pattern
use rvoip_dialog_core::api::DialogClient;
use rvoip_sip_core::Method;
use rvoip_dialog_core::dialog::DialogId;

// Coordinate with session layer for media changes
let media_session = setup_media_session().await?;
let new_sdp = media_session.generate_offer().await?;

// Send re-INVITE with new media parameters
let tx_key = client.send_request_in_dialog(
    &dialog_id,
    Method::Invite,
    Some(bytes::Bytes::from(new_sdp))
).await?;

println!("Sent re-INVITE for media change: {}", tx_key);

// The response will be handled by session coordination events
§Arguments
  • dialog_id - The dialog ID to send the request within
  • method - SIP method to send (INVITE, BYE, UPDATE, INFO, etc.)
  • body - Optional message body (SDP, application data, etc.)
§Returns

Transaction key for tracking the request and its response

§Errors
  • ApiError::Dialog - Dialog not found or invalid state
  • ApiError::Protocol - Invalid method for current dialog state
  • ApiError::Internal - Failed to send request
Source

pub async fn get_dialog_info(&self, dialog_id: &DialogId) -> ApiResult<Dialog>

Get detailed information about a dialog

Provides access to the complete dialog state for session coordination and monitoring purposes.

§Arguments
  • dialog_id - The dialog ID to query
§Returns

Complete dialog information

Source

pub async fn get_dialog_state( &self, dialog_id: &DialogId, ) -> ApiResult<DialogState>

Get the current state of a dialog

Provides quick access to dialog state without retrieving the full dialog information.

§Arguments
  • dialog_id - The dialog ID to query
§Returns

Current dialog state

Source

pub async fn terminate_dialog(&self, dialog_id: &DialogId) -> ApiResult<()>

Terminate a dialog and clean up resources

This method provides direct control over dialog termination, which is essential for session lifecycle management.

§Arguments
  • dialog_id - The dialog ID to terminate
§Returns

Success or error

Source

pub async fn list_active_dialogs(&self) -> Vec<DialogId>

List all active dialog IDs

Provides access to all active dialogs for monitoring and management purposes.

§Returns

Vector of active dialog IDs

Source

pub async fn send_response( &self, transaction_id: &TransactionKey, response: Response, ) -> ApiResult<()>

Send a SIP response for a transaction

Provides direct control over response generation, which is essential for custom response handling in session coordination.

§Arguments
  • transaction_id - Transaction to respond to
  • response - Complete SIP response
§Returns

Success or error

Source

pub async fn build_response( &self, transaction_id: &TransactionKey, status_code: StatusCode, body: Option<String>, ) -> ApiResult<Response>

Build a SIP response with automatic header generation

Convenience method for creating properly formatted SIP responses with correct headers and routing information using Phase 3 dialog functions.

§Arguments
  • transaction_id - Transaction to respond to
  • status_code - SIP status code
  • body - Optional response body
§Returns

Built SIP response ready for sending

Source

pub async fn build_dialog_response( &self, transaction_id: &TransactionKey, dialog_id: &DialogId, status_code: StatusCode, body: Option<String>, ) -> ApiResult<Response>

Build a dialog-aware response with enhanced context

This method provides dialog-aware response building using Phase 3 dialog utilities to ensure proper response construction for dialog transactions.

§Arguments
  • transaction_id - Transaction to respond to
  • dialog_id - Dialog ID for context
  • status_code - SIP status code
  • body - Optional response body
§Returns

Built SIP response with dialog awareness

Source

pub async fn send_status_response( &self, transaction_id: &TransactionKey, status_code: StatusCode, reason: Option<String>, ) -> ApiResult<()>

Send a status response with automatic response building

Convenience method for sending simple status responses without manual response construction.

§Arguments
  • transaction_id - Transaction to respond to
  • status_code - SIP status code
  • reason - Optional reason phrase
§Returns

Success or error

Source

pub async fn send_bye(&self, dialog_id: &DialogId) -> ApiResult<TransactionKey>

Send a BYE request to terminate a dialog

Convenience method for the common operation of ending a call by sending a BYE request.

§Arguments
  • dialog_id - Dialog to terminate
§Returns

Transaction key for the BYE request

Source

pub async fn send_refer( &self, dialog_id: &DialogId, target_uri: String, refer_body: Option<String>, ) -> ApiResult<TransactionKey>

Send a REFER request for call transfer

Convenience method for initiating call transfers using the REFER method as defined in RFC 3515.

§Arguments
  • dialog_id - Dialog to send REFER within
  • target_uri - URI to transfer the call to
  • refer_body - Optional REFER body with additional headers
§Returns

Transaction key for the REFER request

Source

pub async fn send_notify( &self, dialog_id: &DialogId, event: String, body: Option<String>, ) -> ApiResult<TransactionKey>

Send a NOTIFY request for event notifications

Convenience method for sending event notifications using the NOTIFY method as defined in RFC 3265.

§Arguments
  • dialog_id - Dialog to send NOTIFY within
  • event - Event type being notified
  • body - Optional notification body
§Returns

Transaction key for the NOTIFY request

Source

pub async fn send_update( &self, dialog_id: &DialogId, sdp: Option<String>, ) -> ApiResult<TransactionKey>

Send an UPDATE request for media modifications

Convenience method for updating media parameters using the UPDATE method as defined in RFC 3311.

§Arguments
  • dialog_id - Dialog to send UPDATE within
  • sdp - Optional SDP body with new media parameters
§Returns

Transaction key for the UPDATE request

Source

pub async fn send_info( &self, dialog_id: &DialogId, info_body: String, ) -> ApiResult<TransactionKey>

Send an INFO request for application-specific information

Convenience method for sending application-specific information using the INFO method as defined in RFC 6086.

§Arguments
  • dialog_id - Dialog to send INFO within
  • info_body - Information to send
§Returns

Transaction key for the INFO request

Source

pub fn config(&self) -> &ClientConfig

Get client configuration

Source

pub async fn active_dialogs(&self) -> Vec<DialogHandle>

Get a list of all active dialog handles

Trait Implementations§

Source§

impl DialogApi for DialogClient

Source§

fn dialog_manager(&self) -> &Arc<DialogManager>

Get access to the underlying dialog manager Read more
Source§

async fn set_session_coordinator( &self, sender: Sender<SessionCoordinationEvent>, ) -> ApiResult<()>

Set session coordinator for communication with session-core Read more
Source§

async fn start(&self) -> ApiResult<()>

Start the dialog API Read more
Source§

async fn stop(&self) -> ApiResult<()>

Stop the dialog API Read more
Source§

async fn get_stats(&self) -> DialogStats

Get statistics for this API instance Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> ErasedDestructor for T
where T: 'static,