1717from collections import deque
1818import ctypes
1919import random
20- from typing import Callable , Generator , Generic , List , TypeVar
20+ from typing import Callable , Generator , Generic , List , TypeVar , Union
2121
2222logger = logging .getLogger ("livekit" )
2323
@@ -40,8 +40,35 @@ def task_done_logger(task: asyncio.Task) -> None:
4040 return
4141
4242
43- def get_address (mv : memoryview ) -> int :
44- return ctypes .addressof (ctypes .c_char .from_buffer (mv ))
43+ def _buffer_supported_or_raise (
44+ data : Union [bytes , bytearray , memoryview ],
45+ ) -> None :
46+ """Validate a buffer for FFI use.
47+
48+ Raises clear errors for non-contiguous or sliced memoryviews.
49+ """
50+ if isinstance (data , memoryview ):
51+ if not data .contiguous :
52+ raise ValueError ("memoryview must be contiguous" )
53+ if data .nbytes != len (data .obj ): # type: ignore[arg-type]
54+ raise ValueError ("sliced memoryviews are not supported" )
55+ elif not isinstance (data , (bytes , bytearray )):
56+ raise TypeError (f"expected bytes, bytearray, or memoryview, got { type (data )} " )
57+
58+
59+ def get_address (data ) -> int :
60+ if isinstance (data , memoryview ):
61+ _buffer_supported_or_raise (data )
62+ if not data .readonly :
63+ return ctypes .addressof (ctypes .c_char .from_buffer (data ))
64+ data = data .obj
65+ if isinstance (data , bytearray ):
66+ return ctypes .addressof (ctypes .c_char .from_buffer (data ))
67+ if isinstance (data , bytes ):
68+ addr = ctypes .cast (ctypes .c_char_p (data ), ctypes .c_void_p ).value
69+ assert addr is not None
70+ return addr
71+ raise TypeError (f"expected bytes, bytearray, or memoryview, got { type (data )} " )
4572
4673
4774T = TypeVar ("T" )
0 commit comments