Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions livekit-rtc/livekit/rtc/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,28 +40,29 @@ def task_done_logger(task: asyncio.Task) -> None:
return


def _buffer_supported_or_raise(
def _ensure_compatible_buffer(
data: Union[bytes, bytearray, memoryview],
) -> None:
"""Validate a buffer for FFI use.
) -> Union[bytes, bytearray, memoryview]:
"""Validate and normalize a buffer for FFI use.

Raises clear errors for non-contiguous or sliced memoryviews.
Sliced memoryviews are materialized because get_address cannot
reliably resolve their offset for all buffer types.
"""
if isinstance(data, memoryview):
if not data.contiguous:
raise ValueError("memoryview must be contiguous")
if data.nbytes != len(data.obj): # type: ignore[arg-type]
raise ValueError("sliced memoryviews are not supported")
return bytearray(data) if not data.readonly else bytes(data)
elif not isinstance(data, (bytes, bytearray)):
raise TypeError(f"expected bytes, bytearray, or memoryview, got {type(data)}")
return data


def get_address(data) -> int:
def get_address(data: Union[bytes, bytearray, memoryview]) -> int:
if isinstance(data, memoryview):
_buffer_supported_or_raise(data)
if not data.readonly:
return ctypes.addressof(ctypes.c_char.from_buffer(data))
data = data.obj
data = data.obj # type: ignore[assignment]
if isinstance(data, bytearray):
return ctypes.addressof(ctypes.c_char.from_buffer(data))
if isinstance(data, bytes):
Expand Down
4 changes: 2 additions & 2 deletions livekit-rtc/livekit/rtc/audio_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import ctypes
from ._ffi_client import FfiHandle
from ._proto import audio_frame_pb2 as proto_audio
from ._utils import _buffer_supported_or_raise, get_address
from ._utils import _ensure_compatible_buffer, get_address
from typing import Any, Union


Expand Down Expand Up @@ -49,7 +49,7 @@ def __init__(
Raises:
ValueError: If the length of `data` is smaller than the required size.
"""
_buffer_supported_or_raise(data)
data = _ensure_compatible_buffer(data)

min_size = num_channels * samples_per_channel * ctypes.sizeof(ctypes.c_int16)
data_len = len(data)
Expand Down
4 changes: 2 additions & 2 deletions livekit-rtc/livekit/rtc/video_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from ._proto import ffi_pb2 as proto
from typing import List, Optional
from ._ffi_client import FfiClient, FfiHandle
from ._utils import _buffer_supported_or_raise, get_address
from ._utils import _ensure_compatible_buffer, get_address

from typing import Any

Expand Down Expand Up @@ -48,7 +48,7 @@ def __init__(
(e.g., RGBA, BGRA, RGB24, etc.).
data (Union[bytes, bytearray, memoryview]): The raw pixel data for the video frame.
"""
_buffer_supported_or_raise(data)
data = _ensure_compatible_buffer(data)

self._width = width
self._height = height
Expand Down
Loading