Connecteur vidéo

La bibliothèque Python du connecteur vidéo de Vonage vous permet de participer de manière programmatique aux sessions de l'API Video de Vonage en tant que participant côté serveur. Cette bibliothèque vous permet de vous connecter à des sessions vidéo, de publier des flux et de vous y abonner, et de traiter des données audio et vidéo en temps réel.

La bibliothèque gère automatiquement la connectivité WebRTC, le traitement des médias et la gestion des sessions, ce qui vous permet de vous concentrer sur la construction de votre logique d'application. sur la construction de votre logique d'application. L'audio est transmis sous forme de données PCM linéaires de 16 bits et la vidéo est transmise sous forme d'images de 8 bits aux formats YUV420P, RGB24 ou ARGB32. aux formats YUV420P, RGB24 ou ARGB32, à des fréquences d'échantillonnage, des résolutions et des configurations de canaux configurables.

Important La bibliothèque Python du connecteur vidéo de Vonage est conçue pour les applications côté serveur et nécessite des informations d'identification et des jetons valides de l'API Video de Vonage avec les autorisations appropriées.

Cette rubrique comprend les sections suivantes :

Bêta publique

Vonage Video Connector est en phase bêta et est disponible sur PyPi en tant que vonage-video-connector.

Pour installer la bibliothèque, exécutez :

pip install vonage-video-connector

Exigences

Cette bibliothèque nécessite Python 3.13 sous Linux AMD64 et ARM64. Nous recommandons d'utiliser Debian Bookworm car c'est la distribution où elle a été testée de la manière la plus complète.

Structures de données

La bibliothèque Python du connecteur vidéo de Vonage utilise plusieurs structures de données clés pour représenter les sessions, les connexions, les flux et les données audio. Il est essentiel de comprendre ces structures pour travailler efficacement avec la bibliothèque.

Session

Représente une session Video API de Vonage à laquelle les clients peuvent se connecter :

from vonage_video_connector.models import Session

# Session object properties
session.id  # str: Unique identifier for the session

Les Session est transmis à diverses fonctions de rappel afin d'identifier la session qui a déclenché l'événement.

Connexion

Représente la connexion d'un participant à une session :

from vonage_video_connector.models import Connection

# Connection object properties
connection.id             # str: Unique identifier for the connection
connection.creation_time  # datetime: When the connection was established
connection.data          # str: Connection data (encoded in the token)

Les données de connexion peuvent être utilisées pour stocker des métadonnées personnalisées sur les participants, telles que les identifiants ou les rôles des utilisateurs.

Flux

Représente un flux média (audio/vidéo) publié par un participant :

from vonage_video_connector.models import Stream

# Stream object properties
stream.id          # str: Unique identifier for the stream
stream.connection  # Connection: The underlying connection that published this stream

Les flux sont créés lorsque les participants publient des médias et sont utilisés pour s'abonner afin de recevoir leurs données audio/vidéo.

Éditeur

Représente le flux publié dans la session :

from vonage_video_connector.models import Publisher

# Publisher object properties
publisher.stream  # Stream: The underlying stream for this publisher

Les Publisher est utilisé dans les rappels liés à la publication et représente votre propre flux de médias publié.

Abonné

Représente un abonnement au flux d'un autre participant :

from vonage_video_connector.models import Subscriber

# Subscriber object properties
subscriber.stream  # Stream: The underlying stream for this subscriber

Les Subscriber est utilisé dans les rappels liés à l'abonnement et représente votre abonnement à la réception des médias d'un autre participant.

Données audio

Représente les données audio transmises ou reçues :

from vonage_video_connector.models import AudioData

# AudioData object properties
audio_data.sample_buffer      # memoryview: 16-bit signed integer audio samples
audio_data.sample_rate        # int: Sample rate (8000-48000 Hz)
audio_data.number_of_channels # int: 1 (mono) or 2 (stereo)
audio_data.number_of_frames   # int: Number of audio frames

Exigences en matière de format audio :

  • Le tampon d'échantillonnage doit contenir des entiers signés de 16 bits
  • Taux d'échantillonnage valables : 8000, 12000, 16000, 24000, 32000, 44100, 48000 Hz
  • Canaux : 1 (mono) ou 2 (stéréo)
  • La taille de la mémoire tampon doit être adaptée : number_of_frames * number_of_channels échantillons

VideoFrame

Représente les données de la trame vidéo en cours de transmission ou de réception :

from vonage_video_connector.models import VideoFrame, VideoResolution

# VideoFrame object properties
video_frame.frame_buffer  # memoryview: 8-bit unsigned char video frame data
video_frame.resolution    # VideoResolution: Width and height in pixels
video_frame.format        # str: Video format (YUV420P, RGB24, or ARGB32)

Exigences en matière de format vidéo :

  • Le tampon de trame doit contenir des caractères non signés de 8 bits
  • Formats valides : YUV420P, RGB24 (BGR), ARGB32 (BGRA)
  • Résolution maximale : 1920x1080 pixels (2 073 600 pixels au total)
  • La taille de la mémoire tampon varie en fonction du format et de la résolution

Résolution vidéo

Représente les dimensions d'une image vidéo :

from vonage_video_connector.models import VideoResolution

# VideoResolution object properties
resolution = VideoResolution(
    width=640,   # int: Width in pixels
    height=480   # int: Height in pixels
)

CaptionsData

Représente les données textuelles de la légende reçues d'un flux abonné :

from vonage_video_connector.models import CaptionsData

# CaptionsData object properties
captions_data.text      # str: The caption text content
captions_data.is_final  # bool: True for final captions, False for interim/partial captions

MediaBufferStats

Fournit des statistiques sur les tampons de média :

from vonage_video_connector.models import MediaBufferStats, AudioBufferStats, VideoBufferStats

# MediaBufferStats object properties
stats.audio  # Optional[AudioBufferStats]: Audio buffer statistics
stats.video  # Optional[VideoBufferStats]: Video buffer statistics

# AudioBufferStats properties
stats.audio.duration  # timedelta: Duration of queued audio

# VideoBufferStats properties
stats.video.duration  # timedelta: Duration of queued video

Structures de configuration

Paramètres de session

Configure le comportement au niveau de la session :

from vonage_video_connector.models import SessionSettings

session_settings = SessionSettings(
    enable_migration=False,  # bool: Enable automatic session migration
    av=av_settings,          # Optional[SessionAVSettings]: Audio/video configuration
    logging=logging_settings # Optional[LoggingSettings]: Logging configuration
)

SessionAVSettings

Configure les paramètres audio et vidéo de la session :

from vonage_video_connector.models import SessionAVSettings, SessionAudioSettings, SessionVideoPublisherSettings

av_settings = SessionAVSettings(
    audio_publisher=SessionAudioSettings(sample_rate=48000, number_of_channels=2),
    audio_subscribers_mix=SessionAudioSettings(sample_rate=48000, number_of_channels=1),
    video_publisher=SessionVideoPublisherSettings(
        resolution=VideoResolution(width=1280, height=720),
        fps=30,
        format="YUV420P"
    )
)

Comprendre la configuration audio :

Les SessionAVSettings vous permet de configurer différents formats audio pour la publication et la réception :

  • éditeur_audio: Définit le format des données audio que vous fournissez par l'intermédiaire de l'application add_audio(). Les données audio que vous envoyez doivent correspondre à la fréquence d'échantillonnage et au nombre de canaux de cette configuration.

  • audio_subscribers_mix: Définit le format de l'audio mixte que vous recevez de tous les flux souscrits via l'application on_audio_data_cb callback. La bibliothèque prend automatiquement en charge le mixage de l'audio de plusieurs abonnés et le rééchantillonnage/la conversion des canaux pour correspondre au format que vous avez spécifié.

Cette séparation vous permet d'optimiser votre cas d'utilisation. Par exemple :

  • Publier en stéréo (2 canaux) pour une sortie de haute qualité tout en recevant un mixage mono (1 canal) pour simplifier le traitement.
  • Publier à 16 kHz pour la parole et recevoir à 48 kHz pour une lecture haute-fidélité
  • Utilisez différentes fréquences d'échantillonnage pour la publication et l'abonnement en fonction des exigences de votre pipeline de traitement audio.

SessionAudioSettings

Configure le format audio pour la publication ou la réception de données audio :

from vonage_video_connector.models import SessionAudioSettings

audio_settings = SessionAudioSettings(
    sample_rate=48000,       # int: Sample rate (8000-48000 Hz)
    number_of_channels=1     # int: Channels - 1 (mono) or 2 (stereo)
)

Paramètres de l'éditeur vidéo de session

Configure les paramètres vidéo pour la publication :

from vonage_video_connector.models import SessionVideoPublisherSettings, VideoResolution

video_settings = SessionVideoPublisherSettings(
    resolution=VideoResolution(width=1280, height=720),  # Resolution in pixels
    fps=30,              # int: Frames per second (1-30)
    format="YUV420P"     # str: Video format (YUV420P, RGB24, or ARGB32)
)

Paramètres de journalisation

Contrôle la verbosité de la journalisation :

from vonage_video_connector.models import LoggingSettings

logging_settings = LoggingSettings(
    level="INFO"  # str: ERROR, WARN, INFO, DEBUG, or TRACE
)

Paramètres de l'éditeur

Configure votre flux publié :

from vonage_video_connector.models import PublisherSettings, PublisherAudioSettings

publisher_settings = PublisherSettings(
    name="My Application",           # str: Name for your published stream (required, min 1 char)
    has_audio=True,                  # bool: Whether to publish audio
    has_video=True,                  # bool: Whether to publish video
    enable_captions=False,           # bool: Whether to enable live captions for this stream (default: False)
    audio_settings=audio_settings    # Optional[PublisherAudioSettings]: Audio configuration
)

Remarque : Au moins un des éléments suivants has_audio ou has_video doit être True.

Remarque : Set (jeu de mots) enable_captions=True pour permettre aux abonnés de recevoir le texte du sous-titre en direct de ce flux via la fonction on_caption_text_cb callback. Les légendes sont désactivées par défaut.

Paramètres audio de l'éditeur

Configure les paramètres audio pour votre flux publié :

from vonage_video_connector.models import PublisherAudioSettings

audio_settings = PublisherAudioSettings(
    enable_stereo_mode=True,  # bool: Publish in stereo (True) or mono (False)
    enable_opus_dtx=False     # bool: Enable discontinuous transmission
)

Transmission discontinue (DTX) arrête l'envoi de paquets audio pendant les silences, ce qui permet d'économiser de la bande passante.

Paramètres de l'abonné

Configure le comportement des abonnés :

from vonage_video_connector.models import SubscriberSettings, SubscriberVideoSettings, VideoResolution

subscriber_settings = SubscriberSettings(
    subscribe_to_audio=True,  # bool: Whether to subscribe to audio
    subscribe_to_video=True,  # bool: Whether to subscribe to video
    video_settings=SubscriberVideoSettings(
        preferred_resolution=VideoResolution(width=640, height=480),
        preferred_framerate=15
    )
)

Remarque : Au moins un des éléments suivants subscribe_to_audio ou subscribe_to_video doit être True.

Paramètres vidéo de l'abonné

Configure les préférences vidéo pour les abonnés :

from vonage_video_connector.models import SubscriberVideoSettings, VideoResolution

video_settings = SubscriberVideoSettings(
    preferred_resolution=VideoResolution(width=640, height=480),  # Optional
    preferred_framerate=15  # Optional: Preferred FPS (1-30)
)

Comprendre les paramètres préférés :

Lors de l'abonnement à des flux acheminés qui utilisent la diffusion simultanée, le SFU (Selective Forwarding Unit) de l'API Video de Vonage peut envoyer différentes couches de qualité de la vidéo. La couche preferred_resolution et preferred_framerate vous permettent de demander une couche de qualité spécifique :

  • résolution_préférée: Demande une couche spatiale spécifique (résolution). Le SFU enverra la couche qui correspond le mieux à votre préférence.
  • débit_préféré: Demande une couche temporelle spécifique (fréquence d'images). Le SFU enverra la couche qui correspond le mieux à votre préférence.

Ces préférences permettent d'optimiser l'utilisation de la bande passante et les exigences de traitement du côté de l'abonné en ne demandant que le niveau de qualité dont vous avez besoin, plutôt que de toujours recevoir la meilleure qualité disponible.

Relations entre les structures de données

Les structures de données sont liées selon la hiérarchie suivante :

Session
├── Connection (multiple participants)
│   └── Stream (participant's published media)
│       ├── Publisher (your published stream)
│       └── Subscriber (your subscription to their stream)
├── AudioData (flowing through streams)
└── VideoFrame (flowing through streams)

Connexion à une session

Connexion de base

Pour vous connecter à une session Video API de Vonage, vous avez besoin de votre identifiant d'application (clé API si vous utilisez Tokbox), de l'identifiant de session et d'un jeton valide :

from vonage_video_connector import VonageVideoClient
from vonage_video_connector.models import SessionSettings, SessionAudioSettings, LoggingSettings

# Create client instance
client = VonageVideoClient()

# Configure session settings
session_settings = SessionSettings(
    enable_migration=False,
    av=SessionAVSettings(
        audio_subscribers_mix=SessionAudioSettings(
            sample_rate=48000,
            number_of_channels=1
        )
    ),
    logging=LoggingSettings(level="INFO")
)

# Connect to session
success = client.connect(
    application_id="your_application_id",
    session_id="your_session_id",
    token="your_token",
    session_settings=session_settings,
    on_connected_cb=on_session_connected,
    on_error_cb=on_session_error
)

Connexion avec tous les rappels

Pour une gestion complète de la session, il faut mettre en œuvre tous les rappels disponibles :

success = client.connect(
    application_id="your_application_id",
    session_id="your_session_id",
    token="your_token",
    session_settings=session_settings,
    on_error_cb=on_session_error,
    on_connected_cb=on_session_connected,
    on_disconnected_cb=on_session_disconnected,
    on_connection_created_cb=on_connection_created,
    on_connection_dropped_cb=on_connection_dropped,
    on_stream_received_cb=on_stream_received,
    on_stream_dropped_cb=on_stream_dropped,
    on_audio_data_cb=on_audio_data,
    on_ready_for_audio_cb=on_ready_for_audio,
    on_media_buffer_drained_cb=on_media_buffer_drained
)

Déconnexion d'une session

Déconnectez-vous de la session lorsque vous avez terminé :

success = client.disconnect()

Paramètres de la session

Configuration audio et vidéo

Configurer les paramètres audio et vidéo de la session pour contrôler le format des données multimédias :

from vonage_video_connector.models import (
    SessionAVSettings, 
    SessionAudioSettings, 
    SessionVideoPublisherSettings,
    VideoResolution
)

# Configure audio for publisher and subscriber mix
audio_publisher = SessionAudioSettings(
    sample_rate=48000,      # Valid: 8000, 12000, 16000, 24000, 32000, 44100, 48000
    number_of_channels=2    # 1 for mono, 2 for stereo
)

audio_subscribers_mix = SessionAudioSettings(
    sample_rate=48000,
    number_of_channels=1
)

# Configure video publisher settings
video_publisher = SessionVideoPublisherSettings(
    resolution=VideoResolution(width=1280, height=720),
    fps=30,
    format="YUV420P"  # Valid: YUV420P, RGB24, ARGB32
)

# Combine into session AV settings
av_settings = SessionAVSettings(
    audio_publisher=audio_publisher,
    audio_subscribers_mix=audio_subscribers_mix,
    video_publisher=video_publisher
)

Configuration de l'enregistrement

Contrôle la verbosité de la journalisation de la console :

from vonage_video_connector.models import LoggingSettings

# Configure logging level
logging_settings = LoggingSettings(
    level="DEBUG"  # Valid: ERROR, WARN, INFO, DEBUG, TRACE
)

Migration de session

Activer la migration automatique des sessions en cas de rotation du SFU :

from vonage_video_connector.models import SessionSettings

session_settings = SessionSettings(
    enable_migration=True,  # Enable automatic migration
    av=av_settings,
    logging=logging_settings
)

Flux de publication

Configuration de l'éditeur

Configurez les paramètres de l'éditeur avant de commencer à publier :

from vonage_video_connector.models import PublisherSettings, PublisherAudioSettings

# Configure publisher audio settings
audio_settings = PublisherAudioSettings(
    enable_stereo_mode=True,   # Publish in stereo
    enable_opus_dtx=False      # Enable discontinuous transmission for bandwidth savings
)

# Create publisher settings for audio and video
publisher_settings = PublisherSettings(
    name="AI Assistant Bot",
    has_audio=True,
    has_video=True,
    enable_captions=True,
    audio_settings=audio_settings
)

# Or audio-only publisher
audio_only_settings = PublisherSettings(
    name="Audio Bot",
    has_audio=True,
    has_video=False,
    enable_captions=False,
    audio_settings=audio_settings
)

Commencer à publier

Commencer à publier un flux dans la session :

success = client.publish(
    settings=publisher_settings,
    on_error_cb=on_publisher_error,
    on_stream_created_cb=on_stream_created,
    on_stream_destroyed_cb=on_stream_destroyed
)

Important Si vous publiez de l'audio (has_audio=True), vous devez attendre que la commande on_ready_for_audio_cb à invoquer avant d'appeler add_audio(). Ce rappel indique que le système audio est initialisé et prêt à accepter des données audio. Cette exigence ne s'applique pas aux scénarios de publication de vidéos uniquement.

# Example: Wait for audio system to be ready
audio_ready = False

def on_ready_for_audio(session):
    global audio_ready
    audio_ready = True
    print("Audio system ready - can now add audio")

# Connect with the callback
client.connect(
    application_id="your_application_id",
    session_id="your_session_id",
    token="your_token",
    session_settings=session_settings,
    on_ready_for_audio_cb=on_ready_for_audio
)

# Publish
client.publish(settings=publisher_settings)

# Wait for audio to be ready before adding audio
while not audio_ready:
    time.sleep(0.01)

# Now safe to add audio
client.add_audio(audio_data)

Ajout de données audio

Envoyez des données audio à votre flux publié :

from vonage_video_connector.models import AudioData

# Create audio data (example with 16-bit PCM samples)
audio_buffer = memoryview(your_audio_samples)  # Must be 16-bit signed integers

audio_data = AudioData(
    sample_buffer=audio_buffer,
    sample_rate=48000,
    number_of_channels=1,
    number_of_frames=960  # 20ms at 48kHz
)

# Add audio to the published stream
success = client.add_audio(audio_data)

Cesser de publier

Arrêtez la publication lorsque vous avez terminé :

success = client.unpublish()

S'abonner à des flux

S'abonner aux flux

Lorsqu'un nouveau flux est reçu, vous pouvez vous y abonner pour recevoir des données audio et/ou vidéo :

from vonage_video_connector.models import SubscriberSettings, SubscriberVideoSettings, VideoResolution

def on_stream_received(session, stream):
    print(f"New stream received: {stream.id}")
    print(f"From connection: {stream.connection.id}")
    
    # Configure subscriber settings (optional)
    subscriber_settings = SubscriberSettings(
        subscribe_to_audio=True,
        subscribe_to_video=True,
        video_settings=SubscriberVideoSettings(
            preferred_resolution=VideoResolution(width=640, height=480),
            preferred_framerate=15
        )
    )
    
    # Subscribe to the stream
    success = client.subscribe(
        stream=stream,
        settings=subscriber_settings,
        on_error_cb=on_subscriber_error,
        on_connected_cb=on_subscriber_connected,
        on_disconnected_cb=on_subscriber_disconnected,
        on_render_frame_cb=on_render_frame,
        on_audio_data_cb=on_subscriber_audio_data,
        on_caption_text_cb=on_caption_text
    )

Réception des médias souscrits

Lorsque vous vous abonnez à des flux, la bibliothèque fournit des données audio et vidéo par le biais de différents rappels :

Données vidéo: Les images vidéo sont fournies individuellement pour chaque flux souscrit par l'intermédiaire de l'interface utilisateur. on_render_frame_cb callback. Chaque invocation d'un rappel comprend l'élément subscriber qui identifie le flux auquel la trame vidéo appartient. Cela vous permet de traiter séparément les vidéos provenant de différents participants.

def on_render_frame(subscriber, video_frame):
    """Called for each subscribed stream's video frames"""
    stream_id = subscriber.stream.id
    width = video_frame.resolution.width
    height = video_frame.resolution.height
    print(f"Video frame from stream {stream_id}: {width}x{height}")
    # Process video for this specific stream

Données audio: L'audio est diffusé sous la forme d'un flux mixte unique par le biais de l'interface utilisateur. on_audio_data_cb enregistré lors de la connect(). La bibliothèque mélange automatiquement l'audio de tous les flux souscrits en un seul flux audio. Il n'est pas possible de distinguer l'audio des participants individuels dans ce rappel.

def on_audio_data(session, audio_data):
    """Called with mixed audio from all subscribed streams"""
    sample_rate = audio_data.sample_rate
    channels = audio_data.number_of_channels
    print(f"Mixed audio from all subscribers: {sample_rate}Hz, {channels} channel(s)")
    # Process the combined audio from all participants

Données de légende: Cette fonctionnalité est actuellement disponible en version bêta. Le texte du sous-titre est diffusé individuellement pour chaque flux souscrit par l'intermédiaire de l'application on_caption_text_cb callback. Chaque invocation comprend l'élément subscriber identifiant le flux source et un objet CaptionsData l'objet contenant le texte et s'il s'agit d'un résultat final ou intermédiaire.

Note Pour les on_caption_text_cb pour recevoir des données de sous-titres, les sous-titres en direct doivent être activés dans la configuration sous-jacente de la session Vonage Video API (en dehors de cette bibliothèque ; voir la documentation Vonage Video API Live Captions) et pour le flux spécifique de l'éditeur qui envoie de l'audio.

def on_caption_text(subscriber, captions_data):
    """Called when caption text is received from a subscribed stream"""
    stream_id = subscriber.stream.id
    status = "final" if captions_data.is_final else "interim"
    print(f"Caption ({status}) from stream {stream_id}: {captions_data.text}")
    # Process interim captions for live display, final captions for storage or further processing

Les légendes peuvent être soit

  • Intérimaire (is_final=False) : Résultats partiels de la reconnaissance qui peuvent être mis à jour au fur et à mesure du traitement de la parole. Utile pour afficher des transcriptions en direct.
  • Finale (is_final=True) : Résultats de reconnaissance terminés qui ne changeront pas. Utilisez-les pour le stockage, le traitement en aval ou la transcription définitive.

Cette conception vous permet de :

  • Traiter la vidéo de chaque participant indépendamment pour des tâches telles que la gestion de la mise en page, l'enregistrement individuel ou les effets vidéo par flux.
  • Recevoir un son pré-mixé optimisé pour la lecture ou le traitement ultérieur sans mixage manuel
  • Configurer le format audio mixte via audio_subscribers_mix en SessionAVSettings pour répondre à vos besoins de traitement
  • Recevoir un texte de légende pour chaque flux souscrit via on_caption_text_cb pour la transcription en direct ou la conversion de la parole en texte

Données audio individuelles

Cette fonctionnalité est actuellement disponible en version bêta. Les flux audio individuels peuvent être récupérés par le biais de la fonction on_audio_data_cb enregistré au moment de l'abonnement par l'intermédiaire de subscribe(). L'audio est livré dans le format reçu du flux - PCM linéaire 16 bits - et ni la fréquence d'échantillonnage ni le nombre de canaux ne peuvent être configurés avant la réception.

def on_subscriber_audio_data(subscriber, audio_data):
    """Called with individual audio from the stream subscribed to"""
    sample_rate = audio_data.sample_rate
    channels = audio_data.number_of_channels
    print(f"Individual audio from stream {subscriber.stream.id}: {sample_rate}Hz, {channels} channel(s)")
    # Process the individual audio from this stream

Se désabonner des flux

Arrêter la réception de médias provenant d'un flux spécifique :

def on_stream_dropped(session, stream):
    print(f"Stream dropped: {stream.id}")
    
    # Unsubscribe from the stream
    success = client.unsubscribe(stream)

Traitement des données audio

Format audio

Les données audio sont fournies sous forme d'entiers signés PCM linéaires de 16 bits avec les caractéristiques suivantes :

  • Taux d'échantillonnage: 8000, 12000, 16000, 24000, 32000, 44100, ou 48000 Hz
  • Canaux: 1 (mono) ou 2 (stéréo)
  • Format: Entiers signés de 16 bits dans un memoryview tampon
  • Taille du cadre: En général, tranches de 20 ms (varie en fonction de la fréquence d'échantillonnage)

Traitement des données audio

Traite l'audio entrant dans le callback des données audio :

def on_audio_data(session, audio_data):
    """Process incoming audio data from subscribed streams"""
    
    # Access audio properties
    sample_rate = audio_data.sample_rate
    channels = audio_data.number_of_channels
    frames = audio_data.number_of_frames
    
    # Access the audio buffer (memoryview of 16-bit signed integers)
    audio_buffer = audio_data.sample_buffer
    
    print(f"Received {frames} frames at {sample_rate}Hz, {channels} channel(s)")
    
    # Convert to bytes if needed
    audio_bytes = audio_buffer.tobytes()
    
    # Process the audio (e.g., transcription, analysis, etc.)
    process_audio(audio_buffer, sample_rate, channels)
    
    # Generate response audio and add it back
    response_audio = generate_response(audio_buffer)
    if response_audio:
        client.add_audio(response_audio)

Création de données audio

Lorsque vous ajoutez de l'audio, créez des fichiers AudioData objets :

import array

# Create 16-bit PCM audio samples (example: sine wave)
sample_rate = 48000
duration_ms = 20  # 20ms frame
num_samples = int(sample_rate * duration_ms / 1000)

# Generate audio samples as 16-bit signed integers
samples = array.array('h')  # 'h' = signed short (16-bit)
for i in range(num_samples):
    # Example: generate a 440Hz sine wave
    sample = int(32767 * 0.5 * math.sin(2 * math.pi * 440 * i / sample_rate))
    samples.append(sample)

# Create AudioData object
audio_data = AudioData(
    sample_buffer=memoryview(samples),
    sample_rate=sample_rate,
    number_of_channels=1,
    number_of_frames=num_samples
)

# Add the audio
client.add_audio(audio_data)

Continuité des données audio

Lorsque vous publiez de l'audio, la bibliothèque gère automatiquement la continuité de l'audio dans plusieurs scénarios :

Publication initiale : Lorsque vous commencez à publier de l'audio (via publish() avec has_audio=True), la bibliothèque envoie automatiquement des silences (trames audio non remplies) jusqu'à ce que vous fournissiez vos premières données audio via la commande add_audio(). Ainsi, le flux audio est immédiatement disponible pour les abonnés sans attendre que votre application génère des données audio.

Tolérance au silence : Si vous cessez temporairement de fournir des données audio via add_audio()la bibliothèque tolère de brèves interruptions en n'envoyant pas de paquets audio. Cette période d'hystérésis permet d'éviter les paquets de silence inutiles pendant les retards de traitement momentanés.

Silence explicite : Après la période de tolérance, si aucune nouvelle donnée audio n'est disponible, la bibliothèque passe à l'envoi de trames de silence explicites (audio rempli à zéro). Cela permet de maintenir le flux audio tout en indiquant qu'aucune donnée audio active n'est fournie.

Vidage de la mémoire tampon : Si vous fournissez moins d'une période complète de données audio, la bibliothèque effacera les données restantes et les remplacera par du silence afin de maintenir la synchronisation correcte et d'éviter la dérive audio.

Meilleures pratiques :

  • Maintenir un débit audio constant en appelant add_audio() à intervalles réguliers correspondant à la fréquence d'échantillonnage configurée
  • Surveiller les statistiques de la mémoire tampon à l'aide de get_media_buffer_stats() pour garantir des données audio adéquates
  • Manipuler les on_media_buffer_drained_cb callback pour détecter l'épuisement de la mémoire tampon audio
  • Envisager la mise en œuvre d'une stratégie de génération audio qui s'adapte à des charges de traitement variables.

Cette gestion automatique de l'audio garantit que le flux audio publié reste continu et correctement synchronisé, même en cas d'interruption temporaire de la disponibilité des données.

Traitement des données vidéo

Format vidéo

Les données vidéo sont fournies sous forme de caractères non signés de 8 bits dans l'un des trois formats suivants :

  • YUV420P: Format YUV planaire avec sous-échantillonnage chromatique 4:2:0
  • RGB24Format BGR 24 bits (8 bits par canal)
  • ARGB32: Format BGRA 32 bits avec canal alpha

Spécifications vidéo :

  • Résolutions: Jusqu'à 1920x1080 (Full HD)
  • Taux de rafraîchissement: 1-30 FPS
  • Format: caractères non signés de 8 bits dans un memoryview tampon

Traitement des images vidéo

Traite les images vidéo entrantes dans le rappel de l'image de rendu :

def on_render_frame(subscriber, video_frame):
    """Process incoming video frames from subscribed streams"""
    
    # Access video properties
    width = video_frame.resolution.width
    height = video_frame.resolution.height
    format = video_frame.format
    
    # Access the video buffer (memoryview of 8-bit unsigned chars)
    frame_buffer = video_frame.frame_buffer
    
    print(f"Received {width}x{height} frame in {format} format")
    
    # Convert to bytes if needed
    frame_bytes = frame_buffer.tobytes()
    
    # Process the video frame (e.g., computer vision, recording, etc.)
    process_video(frame_buffer, width, height, format)

Création d'images vidéo

Lorsque vous publiez une vidéo, créez des images correctement formatées. VideoFrame objets :

import array
from vonage_video_connector.models import VideoFrame, VideoResolution

# Create a video frame (example: solid color in YUV420P format)
width = 640
height = 480

# YUV420P format calculation:
# Y plane: width * height
# U plane: (width/2) * (height/2)
# V plane: (width/2) * (height/2)
y_size = width * height
uv_size = (width // 2) * (height // 2)
total_size = y_size + 2 * uv_size

# Create frame buffer as 8-bit unsigned chars
frame_data = array.array('B', [128] * total_size)  # 'B' = unsigned char (8-bit)

# Create VideoFrame object
video_frame = VideoFrame(
    frame_buffer=memoryview(frame_data),
    resolution=VideoResolution(width=width, height=height),
    format="YUV420P"
)

# Add the video frame
client.add_video(video_frame)

Continuité de l'image vidéo

Lorsque vous publiez une vidéo, la bibliothèque gère automatiquement la continuité des images dans plusieurs scénarios :

Publication initiale : Lorsque vous commencez à publier des vidéos (via publish() avec has_video=True), la bibliothèque envoie automatiquement des images noires jusqu'à ce que vous fournissiez votre première image via add_video(). Ainsi, le flux vidéo est immédiatement disponible pour les abonnés sans attendre que votre application génère des données vidéo.

Répétition de la dernière image : Si vous cessez de fournir des images vidéo via add_video()la bibliothèque répétera automatiquement la dernière image que vous avez fournie. Cela permet aux abonnés de bénéficier d'une lecture fluide et sans interruption. La dernière image sera répétée pendant 2 secondes maximum.

Repli du cadre noir : Après la période de répétition maximale (2 secondes), la bibliothèque passe à la publication de trames noires. Cela indique aux abonnés que les données vidéo ne sont plus fournies activement tout en maintenant le flux vidéo.

Meilleures pratiques :

  • Maintenir une fréquence d'images constante en appelant add_video() à intervalles réguliers en fonction de votre FPS configuré
  • Surveiller les statistiques de la mémoire tampon à l'aide de get_media_buffer_stats() pour garantir des données vidéo adéquates
  • Manipuler les on_media_buffer_drained_cb callback pour détecter l'épuisement de la mémoire tampon vidéo
  • Envisager la mise en œuvre d'une stratégie de génération de trames qui s'adapte à des charges de traitement variables.

Cette gestion automatique des images garantit la continuité du flux vidéo publié, même en cas d'interruption temporaire de la disponibilité des données.

Gestion de la mémoire tampon des médias

Vérification des statistiques de la mémoire tampon

Surveillez l'état de vos mémoires tampons :

# Get current buffer statistics
stats = client.get_media_buffer_stats()

if stats.audio:
    print(f"Audio buffer duration: {stats.audio.duration.total_seconds()}s")

if stats.video:
    print(f"Video buffer duration: {stats.video.duration.total_seconds()}s")

Effacer les mémoires tampons des médias

Effacez les tampons audio et vidéo si nécessaire :

# Clear all media buffers
success = client.clear_media_buffers()

if success:
    print("Media buffers cleared successfully")

Buffer drained callback

Gérer les événements de vidange de la mémoire tampon :

def on_media_buffer_drained(stats):
    """Called when media buffers are drained"""
    print("Media buffers drained")
    
    if stats.audio:
        print(f"Audio buffer: {stats.audio.duration.total_seconds()}s remaining")
    
    if stats.video:
        print(f"Video buffer: {stats.video.duration.total_seconds()}s remaining")

Comprendre les événements de vidange de la mémoire tampon :

Les on_media_buffer_drained_cb est invoquée lorsque les tampons audio ou vidéo internes sont épuisés. Cela se produit lorsque les données multimédias sont transmises à la session à une vitesse supérieure à celle à laquelle de nouvelles données multimédias sont fournies par l'intermédiaire de l'application add_audio() ou add_video() appels.

Ce rappel vous indique que vous devez augmenter votre taux de production de médias ou ajuster votre stratégie de publication pour maintenir un flux continu de médias. Le suivi de ces événements permet d'éviter les lacunes ou les interruptions dans le flux publié.

Comportement de l'hystérésis du rappel :

Le rappel met en œuvre l'hystérésis pour éviter un déclenchement excessif. Après l'événement initial de vidange, le rappel ne sera pas invoqué à nouveau jusqu'à ce que la mémoire tampon soit réapprovisionnée avec de nouvelles données multimédias et qu'elle se vide à nouveau par la suite. Cela permet d'éviter un flot de notifications répétées alors que la mémoire tampon reste vide.

Obtenir des informations sur la connexion

Récupérez vos informations de connexion locale :

# Get the local connection
connection = client.get_connection()

if connection:
    print(f"Connection ID: {connection.id}")
    print(f"Connection data: {connection.data}")
    print(f"Created at: {connection.creation_time}")

Rappels d'événements

Rappels de session

Gérer les événements au niveau de la session :

def on_session_error(session, error_description, error_code):
    """Handle session errors"""
    print(f"Session error: {error_description} (Code: {error_code})")

def on_session_connected(session):
    """Handle successful session connection"""
    print(f"Connected to session: {session.id}")

def on_session_disconnected(session):
    """Handle session disconnection"""
    print(f"Disconnected from session: {session.id}")

def on_ready_for_audio(session):
    """Called when the audio system is ready"""
    print("Audio system ready - can now add audio")

Rappels de connexion

Contrôler les connexions des participants :

def on_connection_created(session, connection):
    """Handle new participant joining"""
    print(f"Participant joined: {connection.id}")
    print(f"Connection data: {connection.data}")
    print(f"Created at: {connection.creation_time}")

def on_connection_dropped(session, connection):
    """Handle participant leaving"""
    print(f"Participant left: {connection.id}")

Rappels de flux

Gérer les événements de flux :

def on_stream_received(session, stream):
    """Handle new streams from other participants"""
    print(f"Stream received: {stream.id} from connection {stream.connection.id}")
    # Decide whether to subscribe based on your application logic

def on_stream_dropped(session, stream):
    """Handle streams being removed"""
    print(f"Stream dropped: {stream.id}")

Rappels de l'éditeur

Gérer les événements de publication :

def on_publisher_error(publisher, error_description, error_code):
    """Handle publisher errors"""
    print(f"Publisher error: {error_description} (Code: {error_code})")

def on_stream_created(publisher):
    """Handle successful stream creation"""
    print(f"Published stream created: {publisher.stream.id}")

def on_stream_destroyed(publisher):
    """Handle stream destruction"""
    print(f"Published stream destroyed: {publisher.stream.id}")

Rappels de l'abonné

Gérer les événements liés à l'abonnement :

def on_subscriber_error(subscriber, error_description, error_code):
    """Handle subscriber errors"""
    print(f"Subscriber error: {error_description} (Code: {error_code})")

def on_subscriber_connected(subscriber):
    """Handle successful subscription"""
    print(f"Subscribed to stream: {subscriber.stream.id}")

def on_subscriber_disconnected(subscriber):
    """Handle subscription disconnection"""
    print(f"Unsubscribed from stream: {subscriber.stream.id}")

def on_render_frame(subscriber, video_frame):
    """Handle incoming video frames"""
    width = video_frame.resolution.width
    height = video_frame.resolution.height
    print(f"Video frame: {width}x{height} in {video_frame.format} format")

def on_caption_text(subscriber, captions_data):
    """Handle incoming caption text"""
    status = "final" if captions_data.is_final else "interim"
    print(f"Caption ({status}) from stream {subscriber.stream.id}: {captions_data.text}")

Rappels de la mémoire tampon des médias

Traite les événements liés à la mémoire tampon des médias :

def on_media_buffer_drained(stats):
    """Handle media buffer drain events"""
    print("Media buffers have been drained")
    
    if stats.audio:
        duration_s = stats.audio.duration.total_seconds()
        print(f"Audio buffer: {duration_s}s")
    
    if stats.video:
        duration_s = stats.video.duration.total_seconds()
        print(f"Video buffer: {duration_s}s")

Nettoyage des ressources

Nettoyez toujours les ressources de manière appropriée :

try:
    # Your application logic
    success = client.connect(...)
    # ... do work ...
    
except Exception as e:
    print(f"Application error: {e}")
    
finally:
    # Clean up resources
    if client.is_publishing():
        client.unpublish()
    
    if client.is_connected():
        client.disconnect()