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
- Exigences
- Structures de données
- Connexion à une session
- Paramètres de la session
- Flux de publication
- S'abonner à des flux
- Traitement des données audio
- Traitement des données vidéo
- Gestion de la mémoire tampon des médias
- Rappels d'événements
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 :
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_cbcallback. 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_mixenSessionAVSettingspour répondre à vos besoins de traitement - Recevoir un texte de légende pour chaque flux souscrit via
on_caption_text_cbpour 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
memoryviewtampon - 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_cbcallback 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
memoryviewtampon
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_cbcallback 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()