Skip to main content

Documentation Index

Fetch the complete documentation index at: https://developer.sanas.ai/llms.txt

Use this file to discover all available pages before exploring further.

Overview

This tutorial demonstrates how to process multiple concurrent audio streams using the Sanas SDK with dummy audio data. You’ll learn how to:
  • Share a single SDK instance across streams
  • Manage per-stream processors and state
  • Process multiple simultaneous audio streams
Use cases: Contact centers, conference platforms, multi-user applications, gaming voice chat servers.

Prerequisites

Sanas SDK is installed and configured. See Quick Start.

Handle Multiple Streams

To handle multiple audio streams, we’ll use a ThreadPoolExecutor to run each call in its own thread, with a shared SDK instance and a separate AudioProcessor per stream.
import sanas_remote_sdk
import threading
import time
from concurrent.futures import ThreadPoolExecutor

def sleep_until(target_time):
    """Sleep until target time with precision"""
    sleep_time = target_time - time.time()
    if sleep_time > 0.001:
        time.sleep(sleep_time - 0.001)
    while time.time() < target_time:
        pass

def process_call(call_id, sdk):
    """Process audio in a separate thread"""
    call_ready = threading.Event()

    def state_callback(state, reason):
        if state == sanas_remote_sdk.ProcessorState.READY:
            print(f"Call {call_id} state: READY")
            call_ready.set()
        elif state == sanas_remote_sdk.ProcessorState.FAILED:
            print(f"Call {call_id} state: FAILED")
        elif state == sanas_remote_sdk.ProcessorState.DISCONNECTED:
            print(f"Call {call_id} state: DISCONNECTED")
        elif state == sanas_remote_sdk.ProcessorState.INITIALIZING:
            print(f"Call {call_id} state: INITIALIZING")

    # Create processor for this stream
    audio_params = sanas_remote_sdk.AudioParams()
    audio_params.modelName = "desired_sanas_model"
    audio_params.sampleRate = 16000

    processor, result = sdk.CreateAudioProcessor(audio_params, state_callback)

    if result == sanas_remote_sdk.CreateProcessorResult.SUCCESS:
        if call_ready.wait(timeout=10):
            print(f"Call {call_id} processing audio...")

            first_chunk_time = time.time()

            # Process 1500 chunks (30 seconds of audio at 8kHz)
            for i in range(1500):
                ideal_time = first_chunk_time + (i * 0.02)
                sleep_until(ideal_time)

                input_samples = [0.1] * 160  # Simulated audio data (e.g., from network stream)
                output_samples = processor.ProcessSamples(input_samples)

        sdk.DestroyAudioProcessor(processor)

# Initialize SDK once - shared across all streams
sdk = sanas_remote_sdk.CreateRemoteSDK()
init_params = sanas_remote_sdk.InitParams()
init_params.remoteEndpoint = "your_server_ip"
init_params.accountId = "your_account_id"
init_params.accountSecret = "your_account_secret"
init_params.secureMedia = False
sdk.Initialize(init_params)

# Process 4 concurrent audio streams
with ThreadPoolExecutor(max_workers=4) as executor:
    futures = [executor.submit(process_call, i + 1, sdk) for i in range(4)]
    for future in futures:
        future.result()

sdk.Shutdown()
This example uses a ThreadPoolExecutor for demonstration purposes. In production, use any concurrency model (threads, asyncio, etc.) - each stream just needs its own AudioProcessor and must maintain precise 20ms timing between chunks.

Key Components

ComponentScopePurpose
SDK InstanceGlobalShared connection to the Sanas server
Audio ProcessorPer-threadIndependent audio processing
Threading EventPer-threadState synchronization
Thread PoolGlobalManages concurrent execution

References

RemoteSDK

SDK lifecycle methods including CreateAudioProcessor and DestroyAudioProcessor.

AudioProcessor

ProcessSamples and GetState methods for audio processing.

Need Help?

Email Support

support@sanas.aiResponse time: 1 business day

Support Portal

Raise a support ticket for urgent issues