Conector de vídeo
La biblioteca Python de Vonage Video Connector te permite participar mediante programación en las sesiones de la API de video de Vonage como participante del lado del servidor. Esta biblioteca te permite conectarte a sesiones de video, publicar y suscribirte a streams y procesar datos de audio y video en tiempo real.
La biblioteca se encarga de la conectividad WebRTC, el procesamiento de medios y la gestión de sesiones de forma automática, lo que le permite centrarse en la creación de la lógica de su aplicación. en crear la lógica de su aplicación. El audio se transmite como datos PCM lineales de 16 bits, y el vídeo como fotogramas de 8 bits en formatos YUV420P, RGB24 o ARGB32. en formatos YUV420P, RGB24 o ARGB32, todo ello con frecuencias de muestreo, resoluciones y configuraciones de canal configurables.
Importante La biblioteca Python de Vonage Video Connector está diseñada para aplicaciones del lado del servidor y requiere credenciales y tokens válidos de Vonage Video API con los permisos adecuados.
Este tema incluye las siguientes secciones:
- Beta pública
- Requisitos
- Estructuras de datos
- Conectarse a una sesión
- Configuración de la sesión
- Flujos de publicación
- Suscripción a flujos
- Tratamiento de datos de audio
- Tratamiento de datos de vídeo
- Gestión de la memoria intermedia
- Reactivación de eventos
Beta pública
Vonage Video Connector se encuentra en fase beta y está disponible en PyPi como vonage-vídeo-conector.
Para instalar la biblioteca, ejecute
Requisitos
Esta biblioteca requiere Python 3.13 para plataformas Linux AMD64 y ARM64. Recomendamos utilizar Debian Bookworm, ya que es la distribución en la que se ha probado más a fondo.
Estructuras de datos
La biblioteca Python de Vonage Video Connector utiliza varias estructuras de datos clave para representar sesiones, conexiones, secuencias y datos de audio. Comprender estas estructuras es esencial para trabajar con la biblioteca de manera eficaz.
Sesión
Representa una sesión de la Video API de Vonage a la que se pueden conectar los clientes:
from vonage_video_connector.models import Session
# Session object properties
session.id # str: Unique identifier for the session
En Session se pasa a varias funciones de llamada de retorno para identificar qué sesión desencadenó el evento.
Conexión
Representa la conexión de un participante a una sesión:
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)
Los datos de conexión pueden utilizarse para almacenar metadatos personalizados sobre los participantes, como ID de usuario o funciones.
Corriente
Representa un flujo multimedia (audio/vídeo) publicado por un participante:
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
Los flujos se crean cuando los participantes publican medios y se utilizan para suscribirse a la recepción de sus datos de audio/vídeo.
Editorial
Representa su flujo publicado en la sesión:
from vonage_video_connector.models import Publisher
# Publisher object properties
publisher.stream # Stream: The underlying stream for this publisher
En Publisher se utiliza en las retrollamadas relacionadas con la publicación y representa su propio flujo multimedia publicado.
Abonado
Representa una suscripción al flujo de otro participante:
from vonage_video_connector.models import Subscriber
# Subscriber object properties
subscriber.stream # Stream: The underlying stream for this subscriber
En Subscriber se utiliza en las retrollamadas relacionadas con los suscriptores y representa su suscripción para recibir los medios de otro participante.
AudioData
Representa los datos de audio que se transmiten o reciben:
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
Requisitos de formato de audio:
- El búfer de muestra debe contener enteros con signo de 16 bits
- Frecuencias de muestreo válidas: 8000, 12000, 16000, 24000, 32000, 44100, 48000 Hz
- Canales: 1 (mono) o 2 (estéreo)
- El tamaño del búfer debe ser adecuado:
number_of_frames * number_of_channelsmuestras
VideoFrame
Representa los datos de fotogramas de vídeo que se están transmitiendo o recibiendo:
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)
Requisitos de formato de vídeo:
- La memoria intermedia debe contener caracteres de 8 bits sin signo
- Formatos válidos: YUV420P, RGB24 (BGR), ARGB32 (BGRA)
- Resolución máxima: 1920x1080 píxeles (2.073.600 píxeles en total)
- El tamaño del búfer varía según el formato y la resolución
Resolución de vídeo
Representa las dimensiones de un fotograma de vídeo:
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
Representa los datos de texto de los subtítulos recibidos de un flujo suscrito:
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
Proporciona estadísticas sobre las memorias intermedias:
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
Estructuras de configuración
Configuración de la sesión
Configura el comportamiento a nivel de sesión:
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
)
SesiónAVSettings
Configura los parámetros de audio y vídeo de la sesión:
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"
)
)
Comprender la configuración de audio:
En SessionAVSettings permite configurar distintos formatos de audio para la publicación y la recepción:
audio_publisher: Define el formato de los datos de audio que se proporcionan a través de
add_audio(). Los datos de audio que envíes deben coincidir con la frecuencia de muestreo y el número de canales de esta configuración.audio_subscribers_mix: Define el formato del audio mezclado que recibe de todos los flujos suscritos a través del
on_audio_data_cbcallback. La biblioteca se encarga automáticamente de mezclar el audio de varios abonados y de remuestrear/convertir los canales para que coincidan con el formato especificado.
Esta separación le permite optimizar para su caso de uso. Por ejemplo:
- Publica en estéreo (2 canales) para obtener una salida de alta calidad mientras recibes una mezcla mono (1 canal) para simplificar el procesamiento
- Publicación a 16 kHz para voz y recepción a 48 kHz para reproducción de alta fidelidad
- Utiliza distintas frecuencias de muestreo para la publicación y la suscripción en función de los requisitos de tu canal de procesamiento de audio
SessionAudioSettings
Configura el formato de audio para publicar o recibir datos de 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)
)
SessionVideoPublisherSettings
Configura los ajustes de vídeo para la publicación:
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)
)
LoggingSettings
Controla la verbosidad del registro:
from vonage_video_connector.models import LoggingSettings
logging_settings = LoggingSettings(
level="INFO" # str: ERROR, WARN, INFO, DEBUG, or TRACE
)
PublisherSettings
Configura el flujo publicado:
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
)
Nota: Al menos uno de has_audio o has_video debe ser True.
Nota: Establecer enable_captions=True para permitir que los abonados reciban subtítulos en directo de este flujo a través de la función on_caption_text_cb callback. Los subtítulos están desactivados por defecto.
PublisherAudioSettings
Configura los ajustes de audio para su flujo publicado:
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
)
Transmisión discontinua (DTX) deja de enviar paquetes de audio durante el silencio, ahorrando ancho de banda.
Configuración del abonado
Configura el comportamiento de los abonados:
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
)
)
Nota: Al menos uno de subscribe_to_audio o subscribe_to_video debe ser True.
SubscriberVideoSettings
Configura las preferencias de vídeo de los abonados:
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)
)
Comprender las configuraciones preferidas:
Al suscribirse a transmisiones enrutadas que utilizan la transmisión simultánea, la SFU (unidad de reenvío selectivo) de la Video API de Vonage puede enviar diferentes capas de calidad del video. El sitio preferred_resolution y preferred_framerate le permiten solicitar una capa de calidad específica:
- resolución_preferida: Solicita una capa espacial específica (resolución). La SFU enviará la capa que más se ajuste a sus preferencias.
- velocidad_preferida: Solicita una capa temporal específica (frecuencia de imagen). La SFU enviará la capa que más se acerque a sus preferencias.
Estas preferencias ayudan a optimizar el uso del ancho de banda y los requisitos de procesamiento en el lado del abonado solicitando sólo el nivel de calidad que necesita, en lugar de recibir siempre la máxima calidad disponible.
Relaciones entre estructuras de datos
Las estructuras de datos se relacionan en la siguiente jerarquía:
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)
Conectarse a una sesión
Conexión básica
Para conectarte a una sesión de la Video API de Vonage, necesitas tu ID de aplicación (clave de API si usas Tokbox), ID de sesión y un token válido:
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
)
Conexión con todas las devoluciones de llamada
Para una gestión completa de la sesión, implemente todas las retrollamadas 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
)
Desconexión de una sesión
Desconéctese de la sesión cuando haya terminado:
success = client.disconnect()
Configuración de la sesión
Configuración de audio y vídeo
Configure las opciones de audio y vídeo de la sesión para controlar el formato de los datos multimedia:
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
)
Configuración del registro
Controla la verbosidad del registro de la consola:
from vonage_video_connector.models import LoggingSettings
# Configure logging level
logging_settings = LoggingSettings(
level="DEBUG" # Valid: ERROR, WARN, INFO, DEBUG, TRACE
)
Migración de sesiones
Activar la migración automática de sesiones en caso de rotación de SFU:
from vonage_video_connector.models import SessionSettings
session_settings = SessionSettings(
enable_migration=True, # Enable automatic migration
av=av_settings,
logging=logging_settings
)
Flujos de publicación
Configuración del editor
Configure los ajustes del editor antes de empezar a publicar:
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
)
Empezar a publicar
Comienza a publicar un flujo en la sesión:
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
)
Importante
Si va a publicar audio (has_audio=True), debe esperar a que se publique el archivo on_ready_for_audio_cb que se invocará antes de llamar a add_audio(). Esta llamada de retorno indica que el sistema de audio está inicializado y listo para aceptar datos de audio. Este requisito no se aplica a los escenarios de publicación de solo vídeo.
# 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)
Añadir datos de audio
Envíe datos de audio a su flujo publicado:
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)
Dejar de publicar
Deje de publicar cuando haya terminado:
success = client.unpublish()
Suscripción a flujos
Suscribirse a los flujos
Cuando reciba un nuevo flujo, suscríbase a él para recibir datos de audio y/o vídeo:
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
)
Recepción de medios suscritos
Cuando te suscribes a streams, la biblioteca entrega datos de audio y vídeo a través de diferentes callbacks:
Datos de vídeo: Los fotogramas de vídeo se entregan individualmente por flujo suscrito a través del on_render_frame_cb devolución de llamada. Cada invocación de devolución de llamada incluye el parámetro subscriber que identifica a qué flujo pertenece el fotograma de vídeo. Esto le permite procesar vídeo de distintos participantes por separado.
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
Datos de audio: El audio se transmite como un único flujo mixto a través del on_audio_data_cb registrada durante connect(). La biblioteca mezcla automáticamente el audio de todos los flujos suscritos en un único flujo de audio. No se puede distinguir entre el audio de los participantes individuales en esta devolución de llamada.
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
Datos del pie de foto: Esta función está disponible actualmente en versión beta. El texto de los subtítulos se entrega individualmente por flujo suscrito a través de la función on_caption_text_cb devolución de llamada. Cada invocación incluye el subscriber que identifica el flujo de origen y un CaptionsData que contiene el texto y si se trata de un resultado final o provisional.
Nota
Para el on_caption_text_cb para recibir datos de subtítulos, los subtítulos en vivo deben estar habilitados en la configuración de la sesión subyacente de la API de Video de Vonage (fuera de esta biblioteca; consulta la documentación sobre subtítulos en vivo de la API de Video de Vonage) y para el flujo editor específico que está enviando 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
Los pies de foto pueden ser
- Provisional (
is_final=False): Resultados parciales del reconocimiento que pueden actualizarse a medida que se procesa más habla. Útil para mostrar transcripciones en directo. - Final (
is_final=True): Resultados de reconocimiento finalizados que no cambiarán. Utilícelos para almacenamiento, procesamiento posterior o salida de transcripción definitiva.
Este diseño le permite:
- Procese el vídeo de cada participante de forma independiente para tareas como la gestión del diseño, la grabación individual o los efectos de vídeo por secuencia.
- Recibe audio premezclado optimizado para su reproducción o procesamiento posterior sin necesidad de mezclarlo manualmente
- Configure el formato de audio mixto mediante
audio_subscribers_mixenSessionAVSettingspara responder a sus necesidades de tratamiento - Recibir texto de subtítulos por flujo suscrito a través de
on_caption_text_cbpara transcripciones en directo o casos de uso de voz a texto
Datos de audio individuales
Esta función está disponible actualmente en versión beta. El audio de un flujo individual puede recuperarse a través de la función on_audio_data_cb registrada en el momento de la suscripción a través de subscribe(). El audio se entrega en el formato recibido del flujo - PCM lineal de 16 bits - y ni la frecuencia de muestreo ni el número de canales pueden configurarse antes de la recepción.
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
Darse de baja de streams
Detener la recepción de medios de un flujo específico:
def on_stream_dropped(session, stream):
print(f"Stream dropped: {stream.id}")
# Unsubscribe from the stream
success = client.unsubscribe(stream)
Tratamiento de datos de audio
Formato de audio
Los datos de audio se entregan como enteros con signo PCM lineal de 16 bits con las siguientes características:
- Tasas de muestreo: 8000, 12000, 16000, 24000, 32000, 44100 o 48000 Hz
- Canales: 1 (mono) o 2 (estéreo)
- Formato: enteros con signo de 16 bits en un
memoryviewbúfer - Tamaño del marco: Típicamente 20ms trozos (varía según la frecuencia de muestreo)
Procesamiento de datos de audio
Maneja el audio entrante en el callback de datos de 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)
Creación de datos de audio
Al añadir audio, cree archivos con el formato adecuado AudioData objetos:
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)
Continuidad de los datos de audio
Al publicar audio, la biblioteca gestiona automáticamente la continuidad del audio en varios escenarios:
Publicación inicial:
Cuando empiece a publicar audio (a través de publish() con has_audio=True), la biblioteca envía automáticamente silencio (fotogramas de audio sin relleno) hasta que usted proporcione sus primeros datos de audio a través de add_audio(). Esto garantiza que el flujo de audio esté disponible inmediatamente para los abonados sin esperar a que su aplicación genere datos de audio.
Tolerancia al silencio:
Si deja temporalmente de proporcionar datos de audio a través de add_audio()la biblioteca tolera breves lagunas no enviando ningún paquete de audio. Este periodo de histéresis evita paquetes de silencio innecesarios durante retrasos momentáneos en el procesamiento.
Silencio explícito: Tras el periodo de tolerancia, si no hay nuevos datos de audio disponibles, la biblioteca pasa a enviar tramas de silencio explícito (audio relleno de cero). Esto mantiene el flujo de audio al tiempo que indica que no se está proporcionando audio activo.
Descarga del búfer: Si proporciona menos de un periodo completo de datos de audio, la biblioteca eliminará los datos restantes y los rellenará con silencio para mantener la sincronización correcta y evitar la desviación de audio.
Buenas prácticas:
- Mantener una tasa de audio constante llamando
add_audio()a intervalos regulares que coincidan con la frecuencia de muestreo configurada. - Supervisar las estadísticas del búfer mediante
get_media_buffer_stats()para garantizar unos datos de audio adecuados - Manejar el
on_media_buffer_drained_cbcallback para detectar cuándo se agota el búfer de audio - Considera la posibilidad de implantar una estrategia de generación de audio que se adapte a las distintas cargas de procesamiento
Esta gestión automática del audio garantiza que el flujo de audio publicado se mantenga continuo y con la sincronización adecuada, incluso durante las interrupciones temporales en la disponibilidad de datos.
Tratamiento de datos de vídeo
Formato de vídeo
Los datos de vídeo se entregan como caracteres sin signo de 8 bits en uno de estos tres formatos:
- YUV420P: Formato YUV planar con submuestreo de croma 4:2:0
- RGB24Formato BGR de 24 bits (8 bits por canal)
- ARGB32: Formato BGRA de 32 bits con canal alfa
Especificaciones de vídeo:
- Resoluciones: Hasta 1920x1080 (Full HD)
- Frecuencia de imagen: 1-30 FPS
- FormatoCaracteres de 8 bits sin signo en un
memoryviewbúfer
Procesamiento de fotogramas de vídeo
Maneja los fotogramas de vídeo entrantes en la llamada de retorno del fotograma renderizado:
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)
Creación de fotogramas de vídeo
Al publicar vídeo, cree un formato adecuado VideoFrame objetos:
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)
Continuidad de fotogramas de vídeo
Al publicar vídeo, la biblioteca gestiona automáticamente la continuidad de fotogramas en varios escenarios:
Publicación inicial:
Cuando empiece a publicar vídeo (a través de publish() con has_video=True), la biblioteca envía automáticamente fotogramas negros hasta que usted proporcione su primer fotograma mediante add_video(). Esto garantiza que el flujo de vídeo esté disponible inmediatamente para los abonados sin esperar a que su aplicación genere datos de vídeo.
Repetición del último fotograma:
Si deja de proporcionar fotogramas de vídeo a través de add_video()la biblioteca repetirá automáticamente el último fotograma proporcionado. Esto garantiza una reproducción fluida y sin interrupciones para los abonados. El último fotograma se repetirá durante un máximo de 2 segundos.
Retroceso del marco negro: Tras el periodo máximo de repetición (2 segundos), la biblioteca pasa a publicar fotogramas negros. Esto indica a los abonados que ya no se proporcionan activamente datos de vídeo mientras se mantiene el flujo de vídeo.
Buenas prácticas:
- Mantener una velocidad de fotogramas constante llamando a
add_video()a intervalos regulares que coincidan con los FPS configurados - Supervisar las estadísticas del búfer mediante
get_media_buffer_stats()para garantizar unos datos de vídeo adecuados - Manejar el
on_media_buffer_drained_cbcallback para detectar cuándo se agota el búfer de vídeo - Considere la posibilidad de aplicar una estrategia de generación de fotogramas que se adapte a las distintas cargas de procesamiento.
Esta gestión automática de fotogramas garantiza que el flujo de vídeo publicado se mantenga continuo incluso durante las interrupciones temporales en la disponibilidad de datos.
Gestión de la memoria intermedia
Comprobación de las estadísticas del búfer
Supervisa el estado de tus buffers multimedia:
# 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")
Borrado de memorias intermedias
Borra los búferes de audio y vídeo cuando sea necesario:
# Clear all media buffers
success = client.clear_media_buffers()
if success:
print("Media buffers cleared successfully")
Retrollamada de vaciado del búfer
Manejar eventos de drenaje del buffer:
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")
Comprensión de los eventos de drenaje del búfer:
En on_media_buffer_drained_cb se invoca cuando se agotan los búferes internos de audio o vídeo. Esto ocurre cuando los datos multimedia se transmiten a la sesión a una velocidad superior a la velocidad a la que se proporcionan nuevos datos multimedia a través de add_audio() o add_video() llamadas.
Esta devolución de llamada sirve como notificación de que debe aumentar su ritmo de producción de medios o ajustar su estrategia de publicación para mantener un flujo continuo de medios. La supervisión de estos eventos ayuda a evitar lagunas o interrupciones en el flujo publicado.
Comportamiento de la histéresis de devolución de llamada:
La llamada de retorno implementa histéresis para evitar un disparo excesivo. Tras el evento de vaciado inicial, la llamada de retorno no volverá a invocarse hasta que el búfer se reponga con nuevos datos multimedia y, posteriormente, vuelva a vaciarse. Esto evita una avalancha de notificaciones repetidas mientras el búfer permanece vacío.
Obtener información de conexión
Recupera la información de tu conexión local:
# 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}")
Reactivación de eventos
Llamadas de sesión
Manejar eventos a nivel de sesión:
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")
Devoluciones de llamada de conexión
Supervisar las conexiones de los participantes:
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}")
Llamadas de retorno
Manejar eventos de flujo:
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}")
Llamadas de retorno de editores
Gestiona los eventos de publicación:
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}")
Llamadas de retorno a abonados
Gestiona los eventos de suscripción:
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}")
Llamadas al búfer de medios
Gestiona los eventos de la memoria intermedia:
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")
Limpieza de recursos
Limpie siempre los recursos adecuadamente:
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()