ビデオコネクター

Vonage Video Connector Python ライブラリを使用すると、Vonage Video API セッションにサーバ側の参加者としてプログラム的に参加することができます。 セッションに参加できるようになります。このライブラリは、ビデオセッションへの接続、ストリームの公開と購読を可能にします、 そしてリアルタイムのオーディオとビデオデータを処理することができます。

このライブラリは、WebRTC接続、メディア処理、セッション管理を自動的に処理するため、アプリケーション・ロジックの構築に集中できます。 アプリケーションロジックの構築に集中できます。オーディオはリニアPCM 16ビット・データとして、ビデオはYUV420P、RGB24、ARGB32フォーマットの8ビット・フレームとして配信されます。 YUV420P、RGB24、またはARGB32フォーマットで、すべて設定可能なサンプル・レート、解像度、チャンネル構成で配信されます。

重要 Vonage Video Connector Python ライブラリはサーバサイド・アプリケーション用に設計されており、有効な Vonage Video API 認証情報とトークン、および適切なパーミッションが必要です。

このトピックには以下のセクションが含まれます:

パブリックベータ

Vonage Video Connectorはベータ版で、PyPiで利用可能です。 ビデオコネクタ.

ライブラリをインストールするには

pip install vonage-video-connector

必要条件

このライブラリには、Linux AMD64およびARM64プラットフォームで動作するPython 3.13が必要です。 Debian Bookwormを使用することをお勧めします。

データ構造

Vonage Video Connector Python ライブラリは、セッション、接続、ストリーム、およびオーディオデータを表現するために、いくつかの主要なデータ構造を使用します。これらの構造を理解することは、ライブラリを効果的に使用するために不可欠です。

セッション

クライアントが接続できる Vonage Video API セッションを表します:

from vonage_video_connector.models import Session

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

について 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)

接続データは、ユーザーIDやロールなど、参加者に関するカスタム・メタデータを保存するために使用できる。

ストリーム

参加者によって公開されたメディアストリーム(オーディオ/ビデオ)を表します:

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

ストリームは、参加者がメディアを公開するときに作成され、参加者のオーディオ/ビデオデータを受信するために購読するために使用されます。

出版社

セッション内の公開ストリームを表します:

from vonage_video_connector.models import Publisher

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

について Publisher オブジェクトはパブリッシャー関連のコールバックで使用され、あなた自身の公開メディアストリームを表します。

購読者

他の参加者のストリームへのサブスクリプションを表します:

from vonage_video_connector.models import Subscriber

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

について Subscriber オブジェクトは購読者関連のコールバックで使用され、他の参加者のメディアを受信する購読を表します。

オーディオデータ

送受信されるオーディオデータを表す:

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

オーディオフォーマットの要件:

  • サンプル・バッファは16ビット符号付き整数でなければならない。
  • 有効なサンプルレート8000、12000、16000、24000、32000、44100、48000 Hz
  • チャンネル1(モノラル)または2(ステレオ)
  • バッファーの大きさ number_of_frames * number_of_channels サンプル

ビデオフレーム

送受信されるビデオフレームデータを表す:

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)

ビデオフォーマットの要件

  • フレーム・バッファには8ビットの符号なし文字が含まれていなければならない。
  • 有効なフォーマットyuv420p、rgb24(bgr)、argb32(bgra)
  • 最大解像度1920x1080ピクセル(合計207万3600ピクセル)
  • バッファサイズはフォーマットと解像度によって異なる

ビデオ解像度

ビデオフレームの寸法を表す:

from vonage_video_connector.models import VideoResolution

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

キャプションデータ

購読ストリームから受信したキャプションテキストデータを表す:

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

メディアバッファ統計

メディアバッファに関する統計情報を提供する:

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

構成構造

セッション設定

セッションレベルの動作を設定する:

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
)

セッションAV設定

セッションのオーディオとビデオの設定を行います:

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"
    )
)

オーディオコンフィギュレーションを理解する

について SessionAVSettings を使用すると、公開と受信用に異なるオーディオフォーマットを設定できます:

  • オーディオ・パブリッシャー:を介して提供するオーディオデータのフォーマットを定義します。 add_audio().送信するオーディオデータは、このコンフィギュレーションのサンプルレートとチャンネル数と一致していなければなりません。

  • audio_subscribers_mix(オーディオ・サブスクライバーズ・ミックス:を経由して、すべての契約ストリームから受信するミックス音声のフォーマットを定義します。 on_audio_data_cb をコールバックします。このライブラリーは、複数のサブスクライバーのオーディオのミキシングと、指定したフォーマットに合わせたリサンプリング/チャンネル変換を自動的に処理する。

このように分けることで、ユースケースに合わせて最適化することができる。例えば

  • モノ・ミックス(1チャンネル)を受信して処理を簡素化しながら、ステレオ(2チャンネル)でパブリッシュして高品質な出力を実現
  • 音声は16kHzでパブリッシュ、受信は48kHzでハイファイ再生
  • オーディオ処理パイプラインの要件に基づき、パブリッシングとサブスクリプションで異なるサンプルレートを使用します。

セッションオーディオ設定

オーディオデータを公開または受信するためのオーディオフォーマットを設定します:

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)
)

セッション動画パブリッシャー設定

パブリッシングのためのビデオ設定を行います:

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)
)

ロギング設定

ロギングの冗長性を制御する:

from vonage_video_connector.models import LoggingSettings

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

パブリッシャー設定

公開ストリームを設定します:

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
)

注: 少なくとも1つ has_audio または has_video でなければならない。 True.

注: セット enable_captions=True を使って、購読者がこのストリームからライブ・キャプション・テキストを受信できるようにする。 on_caption_text_cb コールバックを使用します。デフォルトではキャプションは無効になっています。

パブリッシャーオーディオ設定

公開ストリームのオーディオ設定を行います:

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
)

不連続伝送(DTX) 無音時のオーディオパケット送信を停止し、帯域幅を節約。

購読者設定

加入者の動作を設定する:

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
    )
)

注: 少なくとも1つ subscribe_to_audio または subscribe_to_video でなければならない。 True.

加入者ビデオ設定

加入者のビデオ設定を行う:

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)
)

好みのセッティングを理解する

サイマルキャストを使用するルーティングストリームを購読する場合、Vonage Video API SFU(Selective Forwarding Unit)は、ビデオの異なる品質レイヤーを送信できます。この場合 preferred_resolution そして preferred_framerate 設定では、特定の品質レイヤーを要求することができます:

  • 優先解像度:特定の空間レイヤー(解像度)を要求します。SFUは希望に最も近いレイヤーを送信します。
  • 優先フレームレート:特定の時間レイヤー(フレームレート)を要求します。SFUは最も希望に近いレイヤーを送信する。

これらの設定は、常に利用可能な最高品質を受信するのではなく、必要な品質レベルのみを要求することで、帯域幅の使用と加入者側の処理要件を最適化するのに役立ちます。

データ構造の関係

データ構造は次のような階層構造になっている:

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)

セッションへの接続

基本接続

Vonage Video APIセッションに接続するには、アプリケーションID(Tokboxを使用している場合はAPIキー)、セッションID、および有効なトークンが必要です:

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
)

すべてのコールバックとの接続

完全なセッション管理のためには、利用可能なすべてのコールバックを実装する:

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
)

セッションからの切断

終了したらセッションを切断する:

success = client.disconnect()

セッション設定

オーディオとビデオの設定

セッションのオーディオとビデオの設定を行い、メディアデータのフォーマットを制御する:

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
)

ロギング設定

コンソールロギングの冗長性を制御する:

from vonage_video_connector.models import LoggingSettings

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

セッション移行

SFUのローテーション時にセッションの自動移行を有効にする:

from vonage_video_connector.models import SessionSettings

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

パブリッシング・ストリーム

発行者構成

パブリッシングを開始する前に、パブリッシャー設定を行います:

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
)

出版開始

セッションへのストリームの公開を開始する:

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
)

重要 オーディオをパブリッシュする場合(has_audio=True)、次のようになります。 on_ready_for_audio_cb を呼び出す前に呼び出される。 add_audio().このコールバックは、オーディオシステムが初期化され、オーディオデータを受け入れる準備ができていることを示します。この要件は、ビデオのみのパブリッシングシナリオには適用されません。

# 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)

オーディオデータの追加

公開ストリームにオーディオデータを送信します:

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)

出版中止

終了したら公開を中止する:

success = client.unpublish()

ストリームの購読

ストリームを購読する

新しいストリームを受信したら、そのストリームに登録し、オーディオやビデオデータを受信する:

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
    )

購読メディアの受信

ストリームを購読すると、ライブラリは異なるコールバックを通じてオーディオとビデオのデータを配信する:

ビデオデータ:ビデオフレームは、ストリームごとに個別に配信されます。 on_render_frame_cb コールバックを呼び出します。各コールバック呼び出しには subscriber オブジェクトは、ビデオフレームがどのストリームに属するかを識別します。これにより、異なる参加者からのビデオを個別に処理できます。

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

音声データ:音声は、単一のミックスストリームとして配信されます。 on_audio_data_cb コールバックは connect().ライブラリは、購読しているすべてのストリームの音声を1つの音声ストリームに自動的にミックスします。このコールバックでは、個々の参加者の音声を区別することはできません。

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

キャプションデータ: この機能は現在ベータ版として提供されている。 キャプション・テキストは、購読しているストリームごとに、以下の方法で個別に配信されます。 on_caption_text_cb コールバック。それぞれの呼び出しには subscriber ソースストリームを識別するオブジェクトと CaptionsData オブジェクトにテキストが含まれ、それが最終結果か中間結果かを示す。

については on_caption_text_cb コールバックでキャプションデータを受け取るには、Vonage Video API セッション設定 (このライブラリの外; Vonage Video API Live Captions documentation を参照) と、音声を送信している特定のパブリッシャーストリームでライブキャプションを有効にする必要があります。

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

キャプションはどちらでもよい:

  • 中間 (is_final=False):音声が処理されるにつれて更新される可能性のある、部分的な認識結果。ライブ文字起こしを表示するのに便利です。
  • 決勝 (is_final=True):完成した認識結果。保存、下流処理、または確定転写出力に使用する。

この設計により、次のことが可能になる:

  • レイアウト管理、個別録画、ストリームごとのビデオエフェクトなどのタスクのために、各参加者のビデオを個別に処理します。
  • 手動でミキシングすることなく、再生や追加処理用に最適化されたミキシング済みオーディオを受信
  • ミックスオーディオフォーマットは audio_subscribers_mixSessionAVSettings お客様の処理要件に合わせて
  • 購読しているストリームごとにキャプションテキストを受信する on_caption_text_cb ライブテープ起こしや音声読み上げの使用例

個別の音声データ

この機能は現在ベータ版として提供されている。 個々のストリーム音声は on_audio_data_cb を通じてサブスクリプション時に登録される。 subscribe().音声はストリームから受信したフォーマット(リニアPCM 16ビット)で配信され、サンプルレートやチャンネル数は受信前に設定することはできません。

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

ストリームの配信停止

特定のストリームからのメディア受信を停止する:

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

オーディオデータの取り扱い

オーディオ・フォーマット

オーディオデータは、リニアPCMの16ビット符号付き整数として配信され、以下の特性を持つ:

  • サンプルレート8000、12000、16000、24000、32000、44100、または48000 Hz
  • チャンネル:1(モノラル)または2(ステレオ)
  • フォーマット:の16ビット符号付き整数 memoryview バッファ
  • フレームサイズ:通常20msチャンク(サンプルレートにより異なる)

オーディオデータの処理

オーディオ・データ・コールバックで受信オーディオを処理する:

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)

オーディオデータの作成

オーディオを追加する場合は、適切なフォーマットで AudioData オブジェクトがある:

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)

オーディオ・データの連続性

オーディオを公開する際、ライブラリはいくつかのシナリオでオーディオの連続性を自動的に管理します:

初公開: オーディオのパブリッシュを開始する際、( publish()has_audio=Trueを経由して最初のオーディオデータを提供するまで、ライブラリは自動的に無音(ゼロフィルされたオーディオフレーム)を送信します。 add_audio().これにより、アプリケーションがオーディオデータを生成するのを待つことなく、オーディオストリームを即座に加入者が利用できるようになります。

沈黙の寛容: による音声データの提供を一時的に停止する場合 add_audio()の場合、ライブラリはオーディオパケットを送信しないことで、短時間のギャップを許容する。このヒステリシス期間により、一瞬の処理遅延による不要な無音パケットを防ぐことができます。

明白な沈黙: 許容期間の後、新しいオーディオデータが利用できない場合、ライブラリは明示的な無音フレーム(ゼロフィル・オーディオ)の送信に切り替わります。これにより、アクティブなオーディオが提供されていないことを示しながら、オーディオストリームが維持されます。

バッファフラッシュ: オーディオデータが1周期分より少ない場合、ライブラリーは残りのデータをフラッシュし、正しいタイミングを維持しオーディオのドリフトを防ぐために無音でパッドします。

ベストプラクティス:

  • 通話で安定した音声レートを維持する add_audio() 設定したサンプルレートに合わせて一定間隔で
  • を使用してバッファ統計を監視する。 get_media_buffer_stats() 十分なオーディオデータを確保する
  • を扱う。 on_media_buffer_drained_cb オーディオバッファが枯渇したことを検出するコールバック
  • さまざまな処理負荷に適応するオーディオ生成ストラテジーの導入を検討する

この自動オーディオ管理により、データの一時的な欠落があっても、公開されたオーディオ・ストリームは継続し、適切なタイミングが保たれます。

ビデオデータの取り扱い

ビデオフォーマット

ビデオデータは、8ビットの符号なし文字として、3つのフォーマットのうちの1つで配信される:

  • YUV420P:4:2:0クロマサブサンプリングによるプレーナーYUVフォーマット
  • RGB2424ビットBGRフォーマット(各チャンネル8ビット)
  • ARGB32:アルファチャンネル付き32ビットBGRAフォーマット

ビデオ仕様:

  • 決議:最大1920x1080(フルHD)
  • フレームレート:1-30 FPS
  • フォーマットの8ビット符号なし文字。 memoryview バッファ

ビデオフレームの処理

レンダー・フレーム・コールバックで、入力されるビデオ・フレームを処理する:

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)

ビデオフレームの作成

動画を公開する場合は、適切なフォーマットで作成してください。 VideoFrame オブジェクトがある:

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)

ビデオフレームの連続性

ビデオを公開すると、ライブラリはいくつかのシナリオでフレームの連続性を自動的に管理します:

初公開: ビデオの公開を開始する場合、次のようになります。 publish()has_video=True) を使って最初のフレームを提供するまで、ライブラリは自動的に黒いフレームを送信します。 add_video().これにより、アプリケーションがビデオデータを生成するのを待つことなく、加入者がビデオストリームをすぐに利用できるようになります。

最後のフレームの繰り返し: によるビデオフレームの提供を停止した場合 add_video()この場合、ライブラリーは、あなたが提供した最後のフレームを自動的に繰り返します。これにより、加入者は途切れることなくスムーズに再生することができます。最後のフレームは最大2秒間繰り返されます。

黒枠フォールバック: 最大反復期間(2秒)が経過すると、ライブラリはブラックフレームの公開に切り替わる。これは、ビデオストリームを維持しながら、ビデオデータがアクティブに提供されなくなったことを加入者に示す。

ベストプラクティス:

  • フレームレートを一定に保つには add_video() 設定したFPSと同じ間隔で
  • を使用してバッファ統計を監視する。 get_media_buffer_stats() 十分なビデオデータを確保する
  • を扱う。 on_media_buffer_drained_cb ビデオバッファが枯渇したことを検出するコールバック。
  • さまざまな処理負荷に適応するフレーム生成戦略の導入を検討する。

この自動フレーム管理により、データ可用性の一時的なギャップがあっても、公開されたビデオストリームは継続的に維持されます。

メディア・バッファ管理

バッファ統計のチェック

メディアバッファの状態を監視する:

# 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")

メディアバッファのクリア

必要に応じて、オーディオとビデオの両方のバッファをクリアする:

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

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

バッファ排出コールバック

バッファドレインイベントを処理する:

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")

バッファードレインイベントを理解する

について on_media_buffer_drained_cb コールバックは、内部オーディオバッファまたはビデオバッファが枯渇したときに呼び出される。これは、メディアデータがセッションに送信される速度が、新しいメディアデータが add_audio() または add_video() のコール。

このコールバックは、継続的なメディアフローを維持するために、メディア制作レートを上げるか、パブリッシング戦略を調整する必要があることを通知する役割を果たします。これらのイベントを監視することで、公開ストリームのギャップや中断を防ぐことができます。

コールバックのヒステリシス動作:

コールバックは、過剰なトリガーを防ぐためにヒステリシスを実装している。最初の枯渇イベントの後、バッファに新しいメディアデータが補充され、その後再び枯渇するまで、コールバックは再度呼び出されることはありません。これにより、バッファが空のまま繰り返し通知されることを防ぎます。

接続情報の取得

ローカル接続情報を取得する:

# 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}")

イベント・コールバック

セッション・コールバック

セッションレベルのイベントを処理する:

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}")
    print(f"Created at: {connection.creation_time}")

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}")

発行者コールバック

パブリッシング・イベントを処理する:

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}")

サブスクライバーのコールバック

購読イベントを処理する:

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}")

メディア・バッファ・コールバック

メディア・バッファ・イベントを処理する:

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")

資源のクリーンアップ

資源の後始末は常に適切に:

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()