Connecteur vidéo pour Python
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.
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 page présente l'API Python. Pour en savoir plus sur les concepts, les formats multimédias et le comportement d'exécution communs à toutes les bibliothèques Video Connector, consultez la Connecteur vidéo guide.
Cette rubrique comprend les sections suivantes :
Pour commencer
Le SDK de Vonage Video Connector Server 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 pris en charge : YUV420P, RGB24, ARGB32
- 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, defaults to 640
height=480 # int: Height in pixels, defaults to 480
)
Ces deux nombres doivent être des entiers positifs, et le nombre total de pixels ne doit pas dépasser 1 920 × 1 080 (2 073 600).
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,
VideoResolution,
)
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"
)
)
- é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é.
Pour obtenir des conseils sur le choix de ces formats, consultez Contenu audio destiné à la publication ou à l'abonnement.
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: Optional, defaults to 48000
number_of_channels=1 # int: Optional, 1 (mono) or 2 (stereo), defaults to 2
)
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), # Required: resolution in pixels
fps=30, # int: Optional, 1-30, defaults to 30
format="YUV420P" # str: Optional, defaults to "YUV420P"
)
Contrairement aux autres modèles de paramètres, resolution est obligatoire. VideoResolution La résolution par défaut est de 640 × 480.
Paramètres de journalisation
Contrôle la verbosité de la journalisation :
from vonage_video_connector.models import LoggingSettings
logging_settings = LoggingSettings(
level="INFO" # str: Optional, ERROR, WARN, INFO, DEBUG, or TRACE, defaults to WARN
)
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
subscribe_to_captions=False, # bool: Whether to subscribe to live captions (default: False)
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.
Remarque : Set (jeu de mots) subscribe_to_captions=True pour recevoir le texte des sous-titres de ce flux via le
on_caption_text_cb rappel. Les sous-titres doivent également être activés du côté de la publication.
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)
)
Ces paramètres demandent au SFU de la Video API une couche de qualité de diffusion simultanée spécifique. Pour savoir comment le SFU les prend en compte, consultez Résolution et fréquence d'images recommandées pour les abonnés.
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,
SessionAVSettings,
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
connecting = 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
)
connect() est asynchrone et renvoie un résultat dès que la tentative de connexion a été lancée. Une valeur de retour de
True signifie que la demande a été acceptée et transmise, pas que le client soit connecté à la session. Attendre
que on_connected_cb à appeler avant de considérer la session comme connectée, et avant de publier ou
de s'abonner.
Une valeur de retour de False signifie que la requête a été rejetée avant d’être envoyée, par exemple parce que le client
est déjà connecté à une session ou que les informations relatives à la session sont incomplètes. Les échecs survenant après l’
envoi de la requête, tels qu’un jeton expiré ou non valide, sont signalés à on_error_cb plutôt que
par le biais de la valeur de retour.
Connexion avec tous les rappels
Pour une gestion complète de la session, il faut mettre en œuvre tous les rappels disponibles :
connecting = 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()
disconnect() retours True une fois que tout aura été démoli, et revient également True si le client n'était pas
déjà connecté à une session.
Vérification de l'état de la connexion
if client.is_connected():
print("Still connected")
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.
import time
# 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)
add_audio() retours True si la trame a été acceptée, et False si le pipeline de publication n'est pas prêt ou
si l'appel natif échoue. La construction du AudioData soulève une ValidationError si la trame est mal formée — par
exemple si la mémoire tampon est trop petite pour la géométrie de trame déclarée.
Cesser de publier
Arrêtez la publication lorsque vous avez terminé :
success = client.unpublish()
Vérification de l'état de publication
if client.is_publishing():
print("Still publishing")
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,
subscribe_to_captions=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 transmet les données audio et vidéo via différents callbacks. Pour comprendre le raisonnement qui sous-tend cette conception, consultez S'abonner à des flux dans le guide « Video Connector ».
Important
Le memoryview à l'intérieur d'un AudioData ou VideoFrame Le contenu transmis à une fonction de rappel n'est valide que pendant la durée de cette fonction. Si vous devez conserver le média au-delà de la fonction de rappel — pour le mettre en file d'attente ou le traiter de manière asynchrone —, copiez-le d'abord, par exemple à l'aide de audio_data.sample_buffer.tobytes() ou bytes(video_frame.frame_buffer).
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 que la fonction de rappel puisse recevoir les données de sous-titrage, les sous-titres en direct doivent être activés dans la configuration de la session de la Video API Vonage sous-jacente (en dehors de cette bibliothèque ; voir la Video API Vonage Sous-titres en direct (documentation) et pour le flux de diffusion spécifique qui transmet le son. Définir subscribe_to_captions=True dans les paramètres d'abonnement pour les recevoir.
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
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
import math
from vonage_video_connector.models import AudioData
# 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 un fichier audio, la bibliothèque diffuse un silence jusqu'à votre premier add_audio() appel, tolère de brèves interruptions
sans envoyer de paquets, puis revient à des trames de silence explicites et complète les périodes partielles pour éviter toute dérive.
Voir Continuité audio pour connaître le fonctionnement complet.
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.
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
- RGB24: RVB compressé, 8 bits par canal
- ARGB32: ARGB compressé, 8 bits par canal, alpha compris
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
success = client.add_video(video_frame)
add_video() retours True si la trame a été acceptée, et False si le pipeline de publication n'est pas prêt ou
si l'appel natif échoue. La construction du VideoFrame soulève une ValidationError si la trame est mal formée — un
format inconnu, une dimension non positive, un nombre de pixels supérieur à 1920x1080, ou un tampon trop petit pour la
résolution déclarée.
Continuité de l'image vidéo
Lorsque vous publiez une vidéo, la bibliothèque envoie des images noires jusqu'à ce que votre première add_video() La fonction « call » répète votre dernière
image pendant 2 secondes maximum si vous cessez de fournir des images, puis affiche des images noires. Voir
Continuité vidéo pour connaître le fonctionnement complet.
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.
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")
Chaque champ est None lorsqu'aucun éditeur de ce type de média n'est actif.
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")
Les on_media_buffer_drained_cb La fonction de rappel est appelée lorsque les tampons audio ou vidéo internes sont vides, et
elle intègre un mécanisme d'hystérésis afin de ne pas se déclencher de manière répétée tant que le tampon reste vide. Voir
Événements de vidange du tampon pour plus de détails.
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}")
get_connection() retours None lorsque le client n'est pas connecté.
Rappels d'événements
Rappels de session
Enregistré à connect():
| Rappel | Signature |
|---|---|
on_error_cb |
(session: Session, description: str, code: int) -> None |
on_connected_cb |
(session: Session) -> None |
on_disconnected_cb |
(session: Session) -> None |
on_connection_created_cb |
(session: Session, connection: Connection) -> None |
on_connection_dropped_cb |
(session: Session, connection: Connection) -> None |
on_stream_received_cb |
(session: Session, stream: Stream) -> None |
on_stream_dropped_cb |
(session: Session, stream: Stream) -> None |
on_audio_data_cb |
(session: Session, audio_data: AudioData) -> None |
on_ready_for_audio_cb |
(session: Session) -> None |
on_media_buffer_drained_cb |
(stats: MediaBufferStats) -> None |
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")
def on_connection_created(session, connection):
"""Handle new participant joining"""
print(f"Participant joined: {connection.id}")
print(f"Connection data: {connection.data}")
def on_connection_dropped(session, connection):
"""Handle participant leaving"""
print(f"Participant left: {connection.id}")
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
Enregistré à publish():
| Rappel | Signature |
|---|---|
on_error_cb |
(publisher: Publisher, description: str, code: int) -> None |
on_stream_created_cb |
(publisher: Publisher) -> None |
on_stream_destroyed_cb |
(publisher: Publisher) -> None |
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é
Enregistré à subscribe():
| Rappel | Signature |
|---|---|
on_error_cb |
(subscriber: Subscriber, description: str, code: int) -> None |
on_connected_cb |
(subscriber: Subscriber) -> None |
on_disconnected_cb |
(subscriber: Subscriber) -> None |
on_render_frame_cb |
(subscriber: Subscriber, video_frame: VideoFrame) -> None |
on_audio_data_cb |
(subscriber: Subscriber, audio_data: AudioData) -> None |
on_caption_text_cb |
(subscriber: Subscriber, captions_data: CaptionsData) -> None |
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}")
Gestion des erreurs
La bibliothèque signale les problèmes de quatre manières différentes.
ValidationError lorsqu'un modèle est élaboré. Chaque modèle de paramètres et de médias est un
pydantic modèle qui valide ses propres champs, de sorte que les valeurs non valides sont rejetées au moment de
la création de l'objet plutôt qu'au moment où celui-ci est transmis au client. Les fréquences d'échantillonnage, le nombre de canaux, les niveaux de journalisation,
les formats de pixels, les fréquences d'images, les résolutions, la taille des éléments de la mémoire tampon et la capacité de la mémoire tampon sont tous vérifiés.
from pydantic import ValidationError
from vonage_video_connector.models import PublisherSettings, SessionAudioSettings
try:
publisher_settings = PublisherSettings(name="Bot", has_audio=False, has_video=False)
except ValidationError as e:
# "At least one of has_audio(False) or has_video (False) must be set to true."
print(f"Invalid publisher settings: {e}")
try:
audio_settings = SessionAudioSettings(sample_rate=44000)
except ValidationError as e:
# "44000 is not one of the allowed: [8000, 12000, 16000, 24000, 32000, 44100, 48000]"
print(f"Invalid audio settings: {e}")
Il convient de noter que format et level Les valeurs ne tiennent pas compte de la casse et sont converties en majuscules, donc
format="yuv420p" et LoggingSettings(level="info") sont toutes les deux acceptées.
TypeError et AttributeError à partir des méthodes du client. La couche native lit les attributs dont elle a besoin à partir des
objets que vous lui transmettez. Elle déclenche AttributeError lorsqu'un attribut attendu est manquant, et TypeError lorsqu'un
argument ou un attribut est d'un type incorrect, y compris lorsqu'une fonction de rappel n'est pas invoquable.
try:
client.add_audio(audio_data)
except (TypeError, AttributeError) as e:
print(f"Malformed audio data: {e}")
False valeurs de retour pour les opérations ayant échoué. Chaque méthode cliente renvoie un bool plutôt que de mettre en avant
une défaillance opérationnelle. connect() retours False si le client est déjà connecté à une session, publish()
rendements False s'il est déjà en cours de publication, et add_audio() et add_video() retour False si le
processus de publication n'est pas prêt. Vérifiez le résultat plutôt que de partir du principe que l'opération a réussi.
if not client.connect(
application_id="your_application_id",
session_id="your_session_id",
token="your_token",
session_settings=session_settings,
):
print("Failed to start connecting - the client may already be connected")
on_error_cb fonctions de rappel en cas d'erreurs d'exécution. Les échecs survenant après l'acceptation d'un appel — y compris
l'échec de la tentative de connexion elle-même — sont signalés au on_error_cb enregistrés pour ce périmètre, accompagnés d'une
description et d'un code numérique. Les périmètres « session », « éditeur » et « abonné » ont chacun les leurs.
def on_session_error(session, error_description, error_code):
print(f"Session error: {error_description} (Code: {error_code})")
client.connect(
application_id="your_application_id",
session_id="your_session_id",
token="your_token",
on_error_cb=on_session_error,
)
Nettoyage des ressources
Nettoyez toujours les ressources de manière appropriée :
try:
# Your application logic
connecting = client.connect(
application_id="your_application_id",
session_id="your_session_id",
token="your_token",
session_settings=session_settings,
)
# ... 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()