Skip to content

Commit d58fb8b

Browse files
committed
support sliced memoryviews in AudioFrame and VideoFrame
1 parent 3d8f6b4 commit d58fb8b

File tree

3 files changed

+13
-12
lines changed

3 files changed

+13
-12
lines changed

livekit-rtc/livekit/rtc/_utils.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,28 +40,29 @@ def task_done_logger(task: asyncio.Task) -> None:
4040
return
4141

4242

43-
def _buffer_supported_or_raise(
43+
def _ensure_compatible_buffer(
4444
data: Union[bytes, bytearray, memoryview],
45-
) -> None:
46-
"""Validate a buffer for FFI use.
45+
) -> Union[bytes, bytearray, memoryview]:
46+
"""Validate and normalize a buffer for FFI use.
4747
48-
Raises clear errors for non-contiguous or sliced memoryviews.
48+
Sliced memoryviews are materialized because get_address cannot
49+
reliably resolve their offset for all buffer types.
4950
"""
5051
if isinstance(data, memoryview):
5152
if not data.contiguous:
5253
raise ValueError("memoryview must be contiguous")
5354
if data.nbytes != len(data.obj): # type: ignore[arg-type]
54-
raise ValueError("sliced memoryviews are not supported")
55+
return bytearray(data) if not data.readonly else bytes(data)
5556
elif not isinstance(data, (bytes, bytearray)):
5657
raise TypeError(f"expected bytes, bytearray, or memoryview, got {type(data)}")
58+
return data
5759

5860

59-
def get_address(data) -> int:
61+
def get_address(data: Union[bytes, bytearray, memoryview]) -> int:
6062
if isinstance(data, memoryview):
61-
_buffer_supported_or_raise(data)
6263
if not data.readonly:
6364
return ctypes.addressof(ctypes.c_char.from_buffer(data))
64-
data = data.obj
65+
data = data.obj # type: ignore[assignment]
6566
if isinstance(data, bytearray):
6667
return ctypes.addressof(ctypes.c_char.from_buffer(data))
6768
if isinstance(data, bytes):

livekit-rtc/livekit/rtc/audio_frame.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
import ctypes
1616
from ._ffi_client import FfiHandle
1717
from ._proto import audio_frame_pb2 as proto_audio
18-
from ._utils import _buffer_supported_or_raise, get_address
18+
from ._utils import _ensure_compatible_buffer, get_address
1919
from typing import Any, Union
2020

2121

@@ -49,7 +49,7 @@ def __init__(
4949
Raises:
5050
ValueError: If the length of `data` is smaller than the required size.
5151
"""
52-
_buffer_supported_or_raise(data)
52+
data = _ensure_compatible_buffer(data)
5353

5454
min_size = num_channels * samples_per_channel * ctypes.sizeof(ctypes.c_int16)
5555
data_len = len(data)

livekit-rtc/livekit/rtc/video_frame.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from ._proto import ffi_pb2 as proto
1919
from typing import List, Optional
2020
from ._ffi_client import FfiClient, FfiHandle
21-
from ._utils import _buffer_supported_or_raise, get_address
21+
from ._utils import _ensure_compatible_buffer, get_address
2222

2323
from typing import Any
2424

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

5353
self._width = width
5454
self._height = height

0 commit comments

Comments
 (0)