Video-Connector für Python
Mit der Python-Bibliothek Vonage Video Connector können Sie programmatisch an Vonage Video API-Sitzungen teilnehmen als serverseitiger Teilnehmer teilzunehmen. Diese Bibliothek ermöglicht es Ihnen, sich mit Videositzungen zu verbinden, Streams zu veröffentlichen und zu abonnieren sowie die Verarbeitung von Audio- und Videodaten in Echtzeit.
Wichtig Die Python-Bibliothek des Vonage Video Connectors ist für serverseitige Anwendungen konzipiert und erfordert gültige Vonage Video API-Anmeldedaten und Token mit entsprechenden Berechtigungen.
Diese Seite befasst sich mit der Python-API. Informationen zu den Concepts, Medienformaten und dem Laufzeitverhalten, die allen Video Connector-Bibliotheken gemeinsam sind, finden Sie unter Video-Anschluss Leitfaden.
Dieses Thema umfasst die folgenden Abschnitte:
Erste Schritte
Vonage Video Connector Server SDK ist auf PyPI verfügbar als vonage-video-connector.
Um die Bibliothek zu installieren, führen Sie aus:
Anforderungen
Diese Bibliothek erfordert Python 3.13 auf Linux AMD64 und ARM64 Plattformen. Wir empfehlen die Verwendung von Debian Bookworm, da dies die Distribution ist, in der sie am gründlichsten getestet wurde.
Datenstrukturen
Die Vonage Video Connector Python-Bibliothek verwendet mehrere wichtige Datenstrukturen, um Sitzungen, Verbindungen, Streams und Audiodaten darzustellen. Das Verständnis dieser Strukturen ist für die effektive Arbeit mit der Bibliothek unerlässlich.
Sitzung
Stellt eine Vonage Video API-Sitzung dar, mit der sich Clients verbinden können:
from vonage_video_connector.models import Session
# Session object properties
session.id # str: Unique identifier for the session
Die Session Objekt wird an verschiedene Callback-Funktionen übergeben, um festzustellen, welche Sitzung das Ereignis ausgelöst hat.
Verbindung
Stellt die Verbindung eines Teilnehmers zu einer Sitzung dar:
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)
Verbindungsdaten können verwendet werden, um benutzerdefinierte Metadaten über Teilnehmer zu speichern, z. B. Benutzer-IDs oder Rollen.
Stream
Stellt einen Medienstrom (Audio/Video) dar, der von einem Teilnehmer veröffentlicht wurde:
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
Streams werden erstellt, wenn Teilnehmer Medien veröffentlichen, und dienen zum Abonnieren ihrer Audio-/Videodaten.
Herausgeber
Stellt Ihren veröffentlichten Stream in der Sitzung dar:
from vonage_video_connector.models import Publisher
# Publisher object properties
publisher.stream # Stream: The underlying stream for this publisher
Die Publisher Objekt wird in verlagsbezogenen Callbacks verwendet und stellt Ihren eigenen veröffentlichten Medienstrom dar.
Abonnent
Stellt ein Abonnement für den Stream eines anderen Teilnehmers dar:
from vonage_video_connector.models import Subscriber
# Subscriber object properties
subscriber.stream # Stream: The underlying stream for this subscriber
Die Subscriber Objekt wird in abonnentenbezogenen Rückrufen verwendet und stellt Ihr Abonnement für den Empfang der Medien eines anderen Teilnehmers dar.
AudioDaten
Stellt die gesendeten oder empfangenen Audiodaten dar:
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
Anforderungen an das Audioformat:
- Probenpuffer muss 16-Bit-Ganzzahlen mit Vorzeichen enthalten
- Gültige Abtastraten: 8000, 12000, 16000, 24000, 32000, 44100, 48000 Hz
- Kanäle: 1 (Mono) oder 2 (Stereo)
- Die Puffergröße muss passen:
number_of_frames * number_of_channelsProben
VideoFrame
Stellt die gesendeten oder empfangenen Videobilddaten dar:
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)
Anforderungen an das Videoformat:
- Rahmenpuffer muss 8-Bit-Zeichen ohne Vorzeichen enthalten
- Gültige Formate: YUV420P, RGB24, ARGB32
- Maximale Auflösung: 1920x1080 Pixel (2.073.600 Pixel insgesamt)
- Die Puffergröße variiert je nach Format und Auflösung
VideoAuflösung
Stellt die Abmessungen eines Videobildes dar:
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
)
Beide Werte müssen positive ganze Zahlen sein, und die Gesamtanzahl der Pixel darf 1920 × 1080 (2.073.600) nicht überschreiten.
BildunterschriftenDaten
Stellt die von einem abonnierten Stream empfangenen Beschriftungstextdaten dar:
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
Liefert Statistiken über Medienpuffer:
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
Konfiguration der Strukturen
SessionSettings
Konfiguriert das Verhalten auf Sitzungsebene:
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
Konfiguriert die Audio- und Videoeinstellungen für die Sitzung:
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"
)
)
- audio_verlag: Definiert das Format für Audiodaten, die Sie über
add_audio(). Die gesendeten Audiodaten müssen mit der Samplerate und der Anzahl der Kanäle dieser Konfiguration übereinstimmen. - audio_abonnenten_mix: Legt das Format für das gemischte Audio fest, das Sie von allen abonnierten Streams über den
on_audio_data_cbRückruf. Die Bibliothek übernimmt automatisch das Mischen der Audiodaten mehrerer Teilnehmer und die Neuabtastung/Kanalumwandlung in das von Ihnen angegebene Format.
Hinweise zur Auswahl dieser Formate finden Sie unter Audio zum Veröffentlichen im Vergleich zum Abonnieren.
SessionAudioSettings
Konfiguriert das Audioformat für die Veröffentlichung oder den Empfang von Audiodaten:
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
)
SessionVideoPublisherSettings
Konfiguriert die Videoeinstellungen für die Veröffentlichung:
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"
)
Im Gegensatz zu den anderen Modellansätzen, resolution ist erforderlich. VideoResolution Die Standardeinstellung beträgt 640 × 480.
LoggingSettings
Steuert die Ausführlichkeit der Protokollierung:
from vonage_video_connector.models import LoggingSettings
logging_settings = LoggingSettings(
level="INFO" # str: Optional, ERROR, WARN, INFO, DEBUG, or TRACE, defaults to WARN
)
PublisherSettings
Konfiguriert Ihren veröffentlichten Stream:
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
)
Anmerkung: Mindestens eine der has_audio oder has_video muss sein True.
Anmerkung: Satz enable_captions=True um den Abonnenten die Möglichkeit zu geben, den Untertiteltext dieses Streams live über die on_caption_text_cb Rückruf. Untertitel sind standardmäßig deaktiviert.
PublisherAudioSettings
Konfiguriert die Audioeinstellungen für Ihren veröffentlichten Stream:
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
)
Diskontinuierliche Übertragung (DTX) sendet bei Stille keine Audiopakete mehr, um Bandbreite zu sparen.
SubscriberSettings
Konfiguriert das Teilnehmerverhalten:
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
)
)
Anmerkung: Mindestens eine der subscribe_to_audio oder subscribe_to_video muss sein True.
Anmerkung: Satz subscribe_to_captions=True um Untertitel aus diesem Stream über den
on_caption_text_cb Callback. Untertitel müssen zudem auf der Veröffentlichungsseite aktiviert sein.
SubscriberVideoSettings
Konfiguriert die Videoeinstellungen für Abonnenten:
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)
)
Diese Einstellungen fordern eine bestimmte Simulcast-Qualitätsstufe von der Vonage Video API SFU an. Eine Erläuterung dazu, wie die SFU diese Einstellungen umsetzt, finden Sie unter Bevorzugte Auflösung und Bildfrequenz für Abonnenten.
Verbinden mit einer Sitzung
Grundlegende Verbindung
Um eine Verbindung zu einer Vonage Video API-Sitzung herzustellen, benötigen Sie Ihre Anwendungs-ID (API-Schlüssel bei Verwendung von Tokbox), die Sitzungs-ID und ein gültiges Token:
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() ist asynchron und kehrt zurück, sobald der Verbindungsversuch gestartet wurde. Ein Rückgabewert von
True bedeutet, dass die Anfrage angenommen und weitergeleitet wurde, nicht dass der Client mit der Sitzung verbunden ist. Warten Sie
auf on_connected_cb muss aufgerufen werden, bevor die Sitzung als verbunden behandelt wird und bevor eine Veröffentlichung oder
ein Abonnement erfolgt.
Ein Rückgabewert von False bedeutet, dass die Anfrage vor ihrer Übermittlung abgelehnt wurde, beispielsweise weil der Client
bereits mit einer Sitzung verbunden ist oder die Sitzungsinformationen unvollständig sind. Fehler, die nach der
Übermittlung der Anfrage auftreten, wie beispielsweise ein abgelaufenes oder ungültiges Token, werden an on_error_cb anstatt
über den Rückgabewert.
Verbindung mit allen Rückrufen
Für eine vollständige Sitzungsverwaltung müssen alle verfügbaren Rückrufe implementiert werden:
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
)
Trennen der Verbindung zu einer Sitzung
Trennen Sie die Verbindung, wenn die Sitzung beendet ist:
success = client.disconnect()
disconnect() gibt zurück. True sobald alles abgerissen ist, und kehrt auch zurück True falls der Client
von vornherein nicht mit einer Sitzung verbunden war.
Verbindungsstatus prüfen
if client.is_connected():
print("Still connected")
Einstellungen der Sitzung
Audio- und Videokonfiguration
Konfigurieren Sie die Audio- und Videoeinstellungen für die Sitzung, um das Format der Mediendaten zu steuern:
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
)
Konfiguration der Protokollierung
Steuern Sie die Ausführlichkeit der Konsolenprotokollierung:
from vonage_video_connector.models import LoggingSettings
# Configure logging level
logging_settings = LoggingSettings(
level="DEBUG" # Valid: ERROR, WARN, INFO, DEBUG, TRACE
)
Migration von Sitzungen
Aktivieren Sie die automatische Sitzungsmigration im Falle einer SFU-Rotation:
from vonage_video_connector.models import SessionSettings
session_settings = SessionSettings(
enable_migration=True, # Enable automatic migration
av=av_settings,
logging=logging_settings
)
Veröffentlichung von Datenströmen
Konfiguration des Herausgebers
Konfigurieren Sie die Publisher-Einstellungen, bevor Sie mit der Veröffentlichung beginnen:
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
)
Veröffentlichung beginnen
Beginn der Veröffentlichung eines Streams in der Sitzung:
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
)
Wichtig
Wenn Sie Audio veröffentlichen (has_audio=True), müssen Sie auf die on_ready_for_audio_cb Callback, der vor dem Aufruf von add_audio(). Dieser Callback zeigt an, dass das Audiosystem initialisiert und bereit ist, Audiodaten zu akzeptieren. Diese Anforderung gilt nicht für reine Videoveröffentlichungsszenarien.
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)
Hinzufügen von Audiodaten
Senden Sie Audiodaten an Ihren veröffentlichten Stream:
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() gibt zurück. True wenn der Frame akzeptiert wurde, und False falls die Veröffentlichungspipeline noch nicht bereit ist oder
der native Aufruf fehlschlägt. Das Erstellen der AudioData wirft ein ValidationError wenn der Frame fehlerhaft ist – zum
Beispiel, wenn der Puffer für die deklarierte Frame-Geometrie zu klein ist.
Veröffentlichung stoppen
Beenden Sie die Veröffentlichung, wenn Sie fertig sind:
success = client.unpublish()
Veröffentlichungsstatus prüfen
if client.is_publishing():
print("Still publishing")
Abonnieren von Streams
Streams abonnieren
Wenn ein neuer Stream empfangen wird, abonnieren Sie ihn, um Audio- und/oder Videodaten zu empfangen:
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
)
Empfang von abonnierten Medien
Wenn Sie Streams abonnieren, liefert die Bibliothek Audio- und Videodaten über verschiedene Callbacks. Die Gründe für dieses Design finden Sie unter Abonnieren von Streams im Video-Connector-Handbuch.
Wichtig
Die memoryview innerhalb eines AudioData oder VideoFrame Die an einen Callback übergebene Mediendatei ist nur für die Dauer dieses Callbacks gültig. Wenn Sie die Mediendatei über den Callback hinaus behalten müssen – um sie in die Warteschlange zu stellen oder asynchron zu verarbeiten –, kopieren Sie sie zunächst, beispielsweise mit audio_data.sample_buffer.tobytes() oder bytes(video_frame.frame_buffer).
Video-Daten: Die Videobilder werden einzeln pro abonniertem Stream über die on_render_frame_cb Rückruf. Jeder Callback-Aufruf enthält die subscriber Objekt, das angibt, zu welchem Stream das Videobild gehört. So können Sie Videos von verschiedenen Teilnehmern getrennt verarbeiten.
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
Audio-Daten: Audio wird als ein einziger gemischter Stream über die on_audio_data_cb Callback registriert während connect(). Die Bibliothek mischt automatisch die Audiosignale aller abonnierten Streams zu einem einzigen Audiostrom zusammen. Sie können bei diesem Rückruf nicht zwischen den Audios der einzelnen Teilnehmer unterscheiden.
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
Daten zur Beschriftung: Diese Funktion ist derzeit als Beta-Funktion verfügbar. Der Untertiteltext wird für jeden abonnierten Stream einzeln über die on_caption_text_cb Rückruf. Jeder Aufruf enthält die subscriber Objekt, das den Quellstrom identifiziert, und ein CaptionsData Objekt, das den Text enthält, und ob es sich um ein End- oder Zwischenergebnis handelt.
Hinweis
Für die on_caption_text_cb Callback zum Empfangen von Untertiteldaten: Live-Untertitel müssen in der zugrunde liegenden Konfiguration der Vonage Video API-Sitzung aktiviert sein (außerhalb dieser Bibliothek; siehe die Vonage Video API Live-Unterschriften (Dokumentation) und für den jeweiligen Publisher-Stream, der Audio sendet. Setze subscribe_to_captions=True in den Abonnenteneinstellungen, um diese zu erhalten.
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
Einzelne Audiodaten
Diese Funktion ist derzeit als Beta-Funktion verfügbar. Einzelne Audio-Streams können über die Funktion on_audio_data_cb Callback, der zum Zeitpunkt der Anmeldung über subscribe(). Audio wird in dem vom Stream empfangenen Format geliefert - Linear PCM 16-Bit - und weder die Abtastrate noch die Anzahl der Kanäle können vor dem Empfang konfiguriert werden.
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
Abbestellen von Streams
Beenden Sie den Empfang von Medien aus einem bestimmten Stream:
def on_stream_dropped(session, stream):
print(f"Stream dropped: {stream.id}")
# Unsubscribe from the stream
success = client.unsubscribe(stream)
Verarbeitung von Audiodaten
Audioformat
Die Audiodaten werden als lineare PCM-Ganzzahlen mit 16 Bit und Vorzeichen mit den folgenden Eigenschaften geliefert:
- Musterpreise8000, 12000, 16000, 24000, 32000, 44100, oder 48000 Hz
- Kanäle: 1 (Mono) oder 2 (Stereo)
- Format: 16-Bit-Ganzzahlen mit Vorzeichen in einer
memoryviewPuffer - Rahmengröße: In der Regel 20ms-Blöcke (variiert je nach Abtastrate)
Verarbeitung von Audiodaten
Behandeln Sie eingehende Audiodaten im Audiodaten-Callback:
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)
Erstellen von Audiodaten
Erstellen Sie beim Hinzufügen von Audio ordnungsgemäß formatierte AudioData Objekte:
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)
Kontinuität der Audiodaten
Wenn Sie Audio veröffentlichen, sendet die Bibliothek Stille, bis Ihr erster add_audio() call toleriert kurze Lücken
ohne das Senden von Paketen, greift dann auf explizite Stille-Frames zurück und füllt Teilperioden auf, um eine Abweichung zu verhindern.
Siehe Audio-Kontinuität um das gesamte Verhalten zu verstehen.
Bewährte Praktiken:
- Behalten Sie eine konsistente Audiorate bei, indem Sie
add_audio()in regelmäßigen Abständen entsprechend der eingestellten Abtastrate - Pufferstatistiken überwachen mit
get_media_buffer_stats()um angemessene Audiodaten zu gewährleisten - Behandeln Sie die
on_media_buffer_drained_cbCallback, um zu erkennen, wenn der Audiopuffer erschöpft ist - Erwägen Sie die Implementierung einer Audiogenerierungsstrategie, die sich an unterschiedliche Verarbeitungslasten anpasst
Verarbeitung von Videodaten
Video-Format
Die Videodaten werden als 8-Bit-Zeichen ohne Vorzeichen in einem von drei Formaten geliefert:
- YUV420P: Planares YUV-Format mit 4:2:0 Chroma-Unterabtastung
- RGB24: Packed RGB, 8 Bit pro Kanal
- ARGB32: ARGB-Daten im komprimierten Format, 8 Bit pro Kanal einschließlich Alpha-Kanal
Video-Spezifikationen:
- Entschließungen: Bis zu 1920x1080 (Full HD)
- Bildfrequenzen: 1-30 FPS
- Format: 8-Bit-Zeichen ohne Vorzeichen in einem
memoryviewPuffer
Verarbeitung von Videobildern
Behandelt eingehende Videobilder im Rendering-Frame-Callback:
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)
Erstellen von Videobildern
Wenn Sie ein Video veröffentlichen, erstellen Sie richtig formatierte VideoFrame Objekte:
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() gibt zurück. True wenn der Frame akzeptiert wurde, und False falls die Veröffentlichungspipeline noch nicht bereit ist oder
der native Aufruf fehlschlägt. Das Erstellen der VideoFrame wirft ein ValidationError wenn der Frame fehlerhaft ist – ein
unbekanntes Format, eine nicht-positive Abmessung, eine Pixelanzahl von mehr als 1920×1080 oder ein Puffer, der für die angegebene
Auflösung zu klein ist.
Kontinuität der Videobilder
Wenn Sie ein Video veröffentlichen, sendet die Bibliothek schwarze Bilder, bis Ihr erstes add_video() call wiederholt Ihren letzten
Frame bis zu 2 Sekunden lang, wenn Sie keine Frames mehr liefern, und wechselt dann zu schwarzen Frames. Siehe
Videokontinuität um das gesamte Verhalten zu verstehen.
Bewährte Praktiken:
- Behalten Sie eine konstante Bildrate bei, indem Sie
add_video()in regelmäßigen Abständen entsprechend Ihrer konfigurierten FPS - Pufferstatistiken überwachen mit
get_media_buffer_stats()um ausreichende Videodaten zu gewährleisten - Behandeln Sie die
on_media_buffer_drained_cbCallback, um zu erkennen, wenn der Videopuffer erschöpft ist - Erwägen Sie die Implementierung einer Strategie zur Generierung von Frames, die sich an unterschiedliche Verarbeitungslasten anpasst.
Verwaltung der Medienpuffer
Überprüfung der Pufferstatistik
Überwachen Sie den Zustand Ihrer Medienpuffer:
# 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")
Jedes Feld ist None wenn kein Herausgeber dieses Medientyps aktiv ist.
Löschen von Medienpuffern
Löschen Sie bei Bedarf sowohl Audio- als auch Videopuffer:
# Clear all media buffers
success = client.clear_media_buffers()
if success:
print("Media buffers cleared successfully")
Puffer entleert Rückruf
Behandlung von Pufferentleerungsereignissen:
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")
Die on_media_buffer_drained_cb Der Callback wird aufgerufen, wenn die internen Audio- oder Videopuffer leer sind, und
implementiert eine Hysterese, damit er nicht wiederholt ausgelöst wird, solange der Puffer leer bleibt. Siehe
Puffer-Drain-Ereignisse für Einzelheiten.
Verbindungsinformationen abrufen
Rufen Sie Ihre lokalen Verbindungsinformationen ab:
# 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() gibt zurück. None wenn der Client nicht verbunden ist.
Ereignis-Rückrufe
Session-Rückrufe
Eingetragen in connect():
| Rückruf | Unterschrift |
|---|---|
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 |
Behandeln Sie Ereignisse auf Sitzungsebene:
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}")
Verleger-Rückrufe
Eingetragen in publish():
| Rückruf | Unterschrift |
|---|---|
on_error_cb |
(publisher: Publisher, description: str, code: int) -> None |
on_stream_created_cb |
(publisher: Publisher) -> None |
on_stream_destroyed_cb |
(publisher: Publisher) -> None |
Handhabung von Veröffentlichungsereignissen:
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}")
Rückrufe von Abonnenten
Eingetragen in subscribe():
| Rückruf | Unterschrift |
|---|---|
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 |
Behandeln Sie Abonnement-Ereignisse:
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}")
Fehlerbehandlung
Die Bibliothek meldet Probleme auf vier verschiedene Arten.
ValidationError wenn ein Modell erstellt wird. Jedes Einstellungs- und Medienmodell ist ein
pydantic Ein Modell, das seine eigenen Felder validiert, sodass ungültige Werte bereits bei der
Erstellung des Objekts zurückgewiesen werden und nicht erst, wenn es an den Client übergeben wird. Abtastraten, Kanalanzahl, Protokollstufen,
Pixelformate, Bildraten, Auflösungen, Pufferelementgröße und Pufferkapazität werden alle überprüft.
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}")
Beachten Sie, dass format und level Bei den Werten wird die Groß-/Kleinschreibung nicht berücksichtigt, und sie werden auf Großbuchstaben normiert, daher
format="yuv420p" und LoggingSettings(level="info") sind beide zulässig.
TypeError und AttributeError aus Client-Methoden. Die native Ebene liest die benötigten Attribute aus den
von Ihnen übergebenen Objekten aus. Sie löst AttributeError wenn ein erwartetes Attribut fehlt, und TypeError wenn ein
Argument oder Attribut den falschen Typ hat, einschließlich der Fälle, in denen ein Callback nicht aufrufbar ist.
try:
client.add_audio(audio_data)
except (TypeError, AttributeError) as e:
print(f"Malformed audio data: {e}")
False Rückgabewerte bei fehlgeschlagenen Operationen. Jede Client-Methode gibt einen bool anstatt aufgrund
eines Betriebsausfalls. connect() gibt zurück. False Wenn der Client bereits mit einer Sitzung verbunden ist, publish()
Erträge False wenn es bereits veröffentlicht wird, und add_audio() und add_video() Zurück False falls die
Veröffentlichungspipeline noch nicht bereit ist. Überprüfen Sie das Ergebnis, anstatt von einem Erfolg auszugehen.
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 Callbacks für Laufzeitfehler. Fehler, die nach der Annahme eines Anrufs auftreten – einschließlich
des Scheiterns des Verbindungsaufbaus selbst – werden an die on_error_cb für diesen Geltungsbereich registriert, mit einer
Beschreibung und einem numerischen Code. Die Geltungsbereiche „Session“, „Publisher“ und „Subscriber“ verfügen jeweils über eigene Codes.
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,
)
Bereinigung von Ressourcen
Reinigen Sie die Ressourcen immer ordnungsgemäß:
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()