viam-sdk 0.41.1__py3-none-linux_armv6l.whl → 0.66.0__py3-none-linux_armv6l.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of viam-sdk might be problematic. Click here for more details.
- viam/app/app_client.py +225 -51
- viam/app/billing_client.py +47 -5
- viam/app/data_client.py +771 -234
- viam/app/ml_training_client.py +3 -5
- viam/app/provisioning_client.py +3 -5
- viam/app/viam_client.py +58 -11
- viam/components/arm/arm.py +1 -1
- viam/components/arm/service.py +1 -1
- viam/components/audio_in/__init__.py +24 -0
- viam/components/audio_in/audio_in.py +74 -0
- viam/components/audio_in/client.py +76 -0
- viam/components/audio_in/service.py +83 -0
- viam/components/audio_out/__init__.py +21 -0
- viam/components/audio_out/audio_out.py +72 -0
- viam/components/audio_out/client.py +67 -0
- viam/components/audio_out/service.py +63 -0
- viam/components/base/base.py +1 -1
- viam/components/board/board.py +8 -2
- viam/components/board/client.py +2 -1
- viam/components/board/service.py +1 -0
- viam/components/button/__init__.py +10 -0
- viam/components/button/button.py +41 -0
- viam/components/button/client.py +52 -0
- viam/components/button/service.py +46 -0
- viam/components/camera/camera.py +15 -30
- viam/components/camera/client.py +10 -21
- viam/components/camera/service.py +15 -28
- viam/components/component_base.py +2 -2
- viam/components/gantry/client.py +17 -2
- viam/components/gantry/gantry.py +32 -1
- viam/components/gantry/service.py +21 -5
- viam/components/gripper/__init__.py +2 -0
- viam/components/gripper/client.py +25 -2
- viam/components/gripper/gripper.py +76 -1
- viam/components/gripper/service.py +32 -3
- viam/components/input/input.py +1 -1
- viam/components/motor/motor.py +1 -1
- viam/components/power_sensor/power_sensor.py +1 -1
- viam/components/switch/__init__.py +10 -0
- viam/components/switch/client.py +83 -0
- viam/components/switch/service.py +72 -0
- viam/components/switch/switch.py +98 -0
- viam/gen/app/agent/v1/agent_pb2.py +1 -1
- viam/gen/app/cloudslam/v1/cloud_slam_pb2.py +1 -1
- viam/gen/app/data/v1/data_grpc.py +74 -2
- viam/gen/app/data/v1/data_pb2.py +198 -104
- viam/gen/app/data/v1/data_pb2.pyi +563 -31
- viam/gen/app/datapipelines/__init__.py +0 -0
- viam/gen/app/datapipelines/v1/__init__.py +0 -0
- viam/gen/app/datapipelines/v1/data_pipelines_grpc.py +84 -0
- viam/gen/app/datapipelines/v1/data_pipelines_pb2.py +57 -0
- viam/gen/app/datapipelines/v1/data_pipelines_pb2.pyi +387 -0
- viam/gen/app/dataset/v1/dataset_grpc.py +10 -2
- viam/gen/app/dataset/v1/dataset_pb2.py +8 -4
- viam/gen/app/dataset/v1/dataset_pb2.pyi +36 -1
- viam/gen/app/datasync/v1/data_sync_pb2.py +39 -35
- viam/gen/app/datasync/v1/data_sync_pb2.pyi +21 -8
- viam/gen/app/mlinference/v1/ml_inference_pb2.py +7 -7
- viam/gen/app/mlinference/v1/ml_inference_pb2.pyi +4 -2
- viam/gen/app/mltraining/v1/ml_training_grpc.py +10 -2
- viam/gen/app/mltraining/v1/ml_training_pb2.py +63 -43
- viam/gen/app/mltraining/v1/ml_training_pb2.pyi +112 -7
- viam/gen/app/packages/v1/packages_pb2.py +1 -1
- viam/gen/app/v1/app_grpc.py +74 -3
- viam/gen/app/v1/app_pb2.py +600 -545
- viam/gen/app/v1/app_pb2.pyi +1108 -258
- viam/gen/app/v1/billing_grpc.py +26 -2
- viam/gen/app/v1/billing_pb2.py +52 -36
- viam/gen/app/v1/billing_pb2.pyi +158 -4
- viam/gen/app/v1/end_user_pb2.py +1 -1
- viam/gen/app/v1/robot_pb2.py +95 -89
- viam/gen/app/v1/robot_pb2.pyi +121 -9
- viam/gen/common/v1/common_pb2.py +76 -58
- viam/gen/common/v1/common_pb2.pyi +186 -17
- viam/gen/component/arm/v1/arm_grpc.py +10 -2
- viam/gen/component/arm/v1/arm_pb2.py +5 -3
- viam/gen/component/audioin/__init__.py +0 -0
- viam/gen/component/audioin/v1/__init__.py +0 -0
- viam/gen/component/audioin/v1/audioin_grpc.py +54 -0
- viam/gen/component/audioin/v1/audioin_pb2.py +34 -0
- viam/gen/component/audioin/v1/audioin_pb2.pyi +94 -0
- viam/gen/component/audioinput/v1/audioinput_pb2.py +1 -1
- viam/gen/component/audioout/__init__.py +0 -0
- viam/gen/component/audioout/v1/__init__.py +0 -0
- viam/gen/component/audioout/v1/audioout_grpc.py +54 -0
- viam/gen/component/audioout/v1/audioout_pb2.py +32 -0
- viam/gen/component/audioout/v1/audioout_pb2.pyi +47 -0
- viam/gen/component/base/v1/base_pb2.py +1 -1
- viam/gen/component/board/v1/board_pb2.py +1 -1
- viam/gen/component/button/v1/button_pb2.py +1 -1
- viam/gen/component/camera/v1/camera_grpc.py +1 -0
- viam/gen/component/camera/v1/camera_pb2.py +37 -36
- viam/gen/component/camera/v1/camera_pb2.pyi +31 -4
- viam/gen/component/encoder/v1/encoder_pb2.py +1 -1
- viam/gen/component/gantry/v1/gantry_grpc.py +9 -1
- viam/gen/component/gantry/v1/gantry_pb2.py +5 -3
- viam/gen/component/generic/v1/generic_pb2.py +1 -1
- viam/gen/component/gripper/v1/gripper_grpc.py +18 -2
- viam/gen/component/gripper/v1/gripper_pb2.py +12 -4
- viam/gen/component/gripper/v1/gripper_pb2.pyi +43 -1
- viam/gen/component/inputcontroller/v1/input_controller_pb2.py +1 -1
- viam/gen/component/motor/v1/motor_pb2.py +1 -1
- viam/gen/component/movementsensor/v1/movementsensor_pb2.py +1 -1
- viam/gen/component/posetracker/v1/pose_tracker_pb2.py +1 -1
- viam/gen/component/powersensor/v1/powersensor_pb2.py +1 -1
- viam/gen/component/sensor/v1/sensor_pb2.py +1 -1
- viam/gen/component/servo/v1/servo_pb2.py +1 -1
- viam/gen/component/switch/v1/switch_pb2.py +5 -5
- viam/gen/component/switch/v1/switch_pb2.pyi +9 -2
- viam/gen/component/testecho/v1/testecho_pb2.py +1 -1
- viam/gen/module/v1/module_pb2.py +5 -5
- viam/gen/module/v1/module_pb2.pyi +7 -2
- viam/gen/opentelemetry/__init__.py +0 -0
- viam/gen/opentelemetry/proto/__init__.py +0 -0
- viam/gen/opentelemetry/proto/common/__init__.py +0 -0
- viam/gen/opentelemetry/proto/common/v1/__init__.py +0 -0
- viam/gen/opentelemetry/proto/common/v1/common_grpc.py +0 -0
- viam/gen/opentelemetry/proto/common/v1/common_pb2.py +27 -0
- viam/gen/opentelemetry/proto/common/v1/common_pb2.pyi +208 -0
- viam/gen/opentelemetry/proto/resource/__init__.py +0 -0
- viam/gen/opentelemetry/proto/resource/v1/__init__.py +0 -0
- viam/gen/opentelemetry/proto/resource/v1/resource_grpc.py +0 -0
- viam/gen/opentelemetry/proto/resource/v1/resource_pb2.py +18 -0
- viam/gen/opentelemetry/proto/resource/v1/resource_pb2.pyi +59 -0
- viam/gen/opentelemetry/proto/trace/__init__.py +0 -0
- viam/gen/opentelemetry/proto/trace/v1/__init__.py +0 -0
- viam/gen/opentelemetry/proto/trace/v1/trace_grpc.py +0 -0
- viam/gen/opentelemetry/proto/trace/v1/trace_pb2.py +37 -0
- viam/gen/opentelemetry/proto/trace/v1/trace_pb2.pyi +402 -0
- viam/gen/proto/rpc/examples/echo/v1/echo_pb2.py +1 -1
- viam/gen/proto/rpc/examples/echoresource/v1/echoresource_pb2.py +1 -1
- viam/gen/proto/rpc/v1/auth_pb2.py +1 -1
- viam/gen/proto/rpc/webrtc/v1/grpc_pb2.py +1 -1
- viam/gen/proto/rpc/webrtc/v1/signaling_pb2.py +1 -1
- viam/gen/provisioning/v1/provisioning_grpc.py +10 -2
- viam/gen/provisioning/v1/provisioning_pb2.py +32 -26
- viam/gen/provisioning/v1/provisioning_pb2.pyi +46 -5
- viam/gen/robot/v1/robot_grpc.py +51 -34
- viam/gen/robot/v1/robot_pb2.py +147 -142
- viam/gen/robot/v1/robot_pb2.pyi +153 -86
- viam/gen/service/datamanager/v1/data_manager_grpc.py +11 -2
- viam/gen/service/datamanager/v1/data_manager_pb2.py +15 -8
- viam/gen/service/datamanager/v1/data_manager_pb2.pyi +47 -1
- viam/gen/service/discovery/v1/discovery_pb2.py +1 -1
- viam/gen/service/generic/v1/generic_pb2.py +1 -1
- viam/gen/service/mlmodel/v1/mlmodel_pb2.py +1 -1
- viam/gen/service/motion/v1/motion_pb2.py +92 -62
- viam/gen/service/motion/v1/motion_pb2.pyi +130 -68
- viam/gen/service/navigation/v1/navigation_pb2.py +1 -1
- viam/gen/service/sensors/v1/sensors_pb2.py +1 -1
- viam/gen/service/shell/v1/shell_pb2.py +1 -1
- viam/gen/service/slam/v1/slam_pb2.py +1 -1
- viam/gen/service/slam/v1/slam_pb2.pyi +1 -1
- viam/gen/service/video/__init__.py +0 -0
- viam/gen/service/video/v1/__init__.py +0 -0
- viam/gen/service/video/v1/video_grpc.py +39 -0
- viam/gen/service/video/v1/video_pb2.py +29 -0
- viam/gen/service/video/v1/video_pb2.pyi +72 -0
- viam/gen/service/vision/v1/vision_pb2.py +27 -27
- viam/gen/service/vision/v1/vision_pb2.pyi +28 -3
- viam/gen/service/worldstatestore/__init__.py +0 -0
- viam/gen/service/worldstatestore/v1/__init__.py +0 -0
- viam/gen/service/worldstatestore/v1/world_state_store_grpc.py +55 -0
- viam/gen/service/worldstatestore/v1/world_state_store_pb2.py +39 -0
- viam/gen/service/worldstatestore/v1/world_state_store_pb2.pyi +171 -0
- viam/gen/stream/v1/stream_pb2.py +1 -1
- viam/gen/tagger/v1/tagger_pb2.py +1 -1
- viam/logging.py +9 -8
- viam/media/audio.py +22 -10
- viam/media/utils/pil/__init__.py +5 -1
- viam/media/video.py +54 -40
- viam/module/module.py +85 -16
- viam/module/resource_data_consumer.py +41 -0
- viam/module/service.py +9 -1
- viam/proto/app/__init__.py +68 -0
- viam/proto/app/billing.py +16 -0
- viam/proto/app/data/__init__.py +48 -0
- viam/proto/app/datapipelines/__init__.py +56 -0
- viam/proto/app/dataset/__init__.py +4 -0
- viam/proto/app/mltraining/__init__.py +6 -0
- viam/proto/app/robot.py +6 -0
- viam/proto/common/__init__.py +14 -0
- viam/proto/component/audioin/__init__.py +16 -0
- viam/proto/component/audioout/__init__.py +15 -0
- viam/proto/component/camera/__init__.py +0 -2
- viam/proto/component/gripper/__init__.py +4 -0
- viam/proto/opentelemetry/__init__.py +0 -0
- viam/proto/opentelemetry/proto/__init__.py +0 -0
- viam/proto/opentelemetry/proto/common/__init__.py +15 -0
- viam/proto/opentelemetry/proto/resource/__init__.py +10 -0
- viam/proto/opentelemetry/proto/trace/__init__.py +15 -0
- viam/proto/provisioning/__init__.py +6 -0
- viam/proto/robot/__init__.py +16 -8
- viam/proto/service/datamanager/__init__.py +8 -1
- viam/proto/service/motion/__init__.py +2 -0
- viam/proto/service/video/__init__.py +15 -0
- viam/proto/service/worldstatestore/__init__.py +32 -0
- viam/resource/easy_resource.py +5 -9
- viam/resource/manager.py +4 -3
- viam/resource/registry.py +2 -2
- viam/resource/types.py +2 -2
- viam/robot/client.py +38 -59
- viam/rpc/dial.py +48 -5
- viam/rpc/libviam_rust_utils.so +0 -0
- viam/rpc/server.py +24 -10
- viam/services/motion/client.py +8 -9
- viam/services/motion/motion.py +48 -46
- viam/services/navigation/navigation.py +2 -2
- viam/services/vision/client.py +1 -1
- viam/services/vision/service.py +5 -8
- viam/services/vision/vision.py +5 -3
- viam/services/worldstatestore/__init__.py +18 -0
- viam/services/worldstatestore/client.py +94 -0
- viam/services/worldstatestore/service.py +55 -0
- viam/services/worldstatestore/worldstatestore.py +90 -0
- viam/sessions_client.py +115 -46
- viam/version_metadata.py +2 -2
- {viam_sdk-0.41.1.dist-info → viam_sdk-0.66.0.dist-info}/METADATA +10 -6
- {viam_sdk-0.41.1.dist-info → viam_sdk-0.66.0.dist-info}/RECORD +221 -152
- {viam_sdk-0.41.1.dist-info → viam_sdk-0.66.0.dist-info}/WHEEL +1 -1
- viam/components/audio_input/__init__.py +0 -18
- viam/components/audio_input/audio_input.py +0 -81
- viam/components/audio_input/client.py +0 -70
- viam/components/audio_input/service.py +0 -114
- {viam_sdk-0.41.1.dist-info → viam_sdk-0.66.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
from viam.resource.registry import Registry, ResourceRegistration
|
|
2
|
-
|
|
3
|
-
from .audio_input import AudioInput
|
|
4
|
-
from .client import AudioInputClient
|
|
5
|
-
from .service import AudioInputRPCService
|
|
6
|
-
|
|
7
|
-
__all__ = [
|
|
8
|
-
"AudioInput",
|
|
9
|
-
]
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
Registry.register_api(
|
|
13
|
-
ResourceRegistration(
|
|
14
|
-
AudioInput,
|
|
15
|
-
AudioInputRPCService,
|
|
16
|
-
lambda name, channel: AudioInputClient(name, channel),
|
|
17
|
-
)
|
|
18
|
-
)
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import abc
|
|
2
|
-
from dataclasses import dataclass
|
|
3
|
-
from datetime import timedelta
|
|
4
|
-
from typing import Final, Optional
|
|
5
|
-
|
|
6
|
-
from google.protobuf.duration_pb2 import Duration
|
|
7
|
-
from typing_extensions import Self
|
|
8
|
-
|
|
9
|
-
from viam.media.audio import Audio, AudioStream
|
|
10
|
-
from viam.proto.component.audioinput import PropertiesResponse
|
|
11
|
-
from viam.resource.types import API, RESOURCE_NAMESPACE_RDK, RESOURCE_TYPE_COMPONENT
|
|
12
|
-
from viam.streams import StreamSource
|
|
13
|
-
|
|
14
|
-
from ..component_base import ComponentBase
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class AudioInput(ComponentBase, StreamSource[Audio]):
|
|
18
|
-
"""AudioInput represents a component that can capture audio.
|
|
19
|
-
|
|
20
|
-
This acts as an abstract base class for any drivers representing specific
|
|
21
|
-
audio input implementations. This cannot be used on its own. If the ``__init__()`` function is
|
|
22
|
-
overridden, it must call the ``super().__init__()`` function.
|
|
23
|
-
"""
|
|
24
|
-
|
|
25
|
-
API: Final = API( # pyright: ignore [reportIncompatibleVariableOverride]
|
|
26
|
-
RESOURCE_NAMESPACE_RDK, RESOURCE_TYPE_COMPONENT, "audio_input"
|
|
27
|
-
)
|
|
28
|
-
|
|
29
|
-
@dataclass
|
|
30
|
-
class Properties:
|
|
31
|
-
channel_count: int
|
|
32
|
-
latency: timedelta
|
|
33
|
-
sample_rate: int
|
|
34
|
-
sample_size: int
|
|
35
|
-
is_big_endian: bool
|
|
36
|
-
is_float: bool
|
|
37
|
-
is_interleaved: bool
|
|
38
|
-
|
|
39
|
-
@property
|
|
40
|
-
def proto(self) -> PropertiesResponse:
|
|
41
|
-
latency = Duration()
|
|
42
|
-
latency.FromTimedelta(self.latency)
|
|
43
|
-
return PropertiesResponse(
|
|
44
|
-
channel_count=self.channel_count,
|
|
45
|
-
latency=latency,
|
|
46
|
-
sample_rate=self.sample_rate,
|
|
47
|
-
sample_size=self.sample_size,
|
|
48
|
-
is_big_endian=self.is_big_endian,
|
|
49
|
-
is_float=self.is_float,
|
|
50
|
-
is_interleaved=self.is_interleaved,
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
@classmethod
|
|
54
|
-
def from_proto(cls, proto: PropertiesResponse) -> Self:
|
|
55
|
-
return cls(
|
|
56
|
-
channel_count=proto.channel_count,
|
|
57
|
-
latency=proto.latency.ToTimedelta(),
|
|
58
|
-
sample_rate=proto.sample_rate,
|
|
59
|
-
sample_size=proto.sample_size,
|
|
60
|
-
is_big_endian=proto.is_big_endian,
|
|
61
|
-
is_float=proto.is_float,
|
|
62
|
-
is_interleaved=proto.is_interleaved,
|
|
63
|
-
)
|
|
64
|
-
|
|
65
|
-
@abc.abstractmethod
|
|
66
|
-
async def stream(self, *, timeout: Optional[float] = None, **kwargs) -> AudioStream:
|
|
67
|
-
"""Stream audio samples from the audio input of the underlying robot
|
|
68
|
-
|
|
69
|
-
Returns:
|
|
70
|
-
Stream[Audio]: The stream of audio chunks
|
|
71
|
-
"""
|
|
72
|
-
...
|
|
73
|
-
|
|
74
|
-
@abc.abstractmethod
|
|
75
|
-
async def get_properties(self, *, timeout: Optional[float] = None, **kwargs) -> Properties:
|
|
76
|
-
"""Get the properties of the audio input of the underlying robot
|
|
77
|
-
|
|
78
|
-
Returns:
|
|
79
|
-
Properties: The audio input properties
|
|
80
|
-
"""
|
|
81
|
-
...
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
from typing import Any, AsyncIterator, Dict, List, Mapping, Optional, Union
|
|
2
|
-
|
|
3
|
-
from grpclib.client import Channel
|
|
4
|
-
|
|
5
|
-
from viam.media.audio import Audio
|
|
6
|
-
from viam.proto.common import DoCommandRequest, DoCommandResponse, Geometry
|
|
7
|
-
from viam.proto.component.audioinput import (
|
|
8
|
-
AudioInputServiceStub,
|
|
9
|
-
ChunksRequest,
|
|
10
|
-
ChunksResponse,
|
|
11
|
-
PropertiesRequest,
|
|
12
|
-
PropertiesResponse,
|
|
13
|
-
SampleFormat,
|
|
14
|
-
)
|
|
15
|
-
from viam.resource.rpc_client_base import ReconfigurableResourceRPCClientBase
|
|
16
|
-
from viam.streams import Stream, StreamWithIterator
|
|
17
|
-
from viam.utils import ValueTypes, dict_to_struct, get_geometries, struct_to_dict
|
|
18
|
-
|
|
19
|
-
from .audio_input import AudioInput
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class AudioInputClient(AudioInput, ReconfigurableResourceRPCClientBase):
|
|
23
|
-
"""
|
|
24
|
-
gRPC client for the AudioInput component.
|
|
25
|
-
"""
|
|
26
|
-
|
|
27
|
-
def __init__(self, name: str, channel: Channel):
|
|
28
|
-
self.channel = channel
|
|
29
|
-
self.client = AudioInputServiceStub(channel)
|
|
30
|
-
super().__init__(name)
|
|
31
|
-
|
|
32
|
-
async def stream(self, *, timeout: Optional[float] = None, **kwargs) -> Stream[Audio]:
|
|
33
|
-
async def read() -> AsyncIterator[Audio]:
|
|
34
|
-
md = kwargs.get("metadata", self.Metadata()).proto
|
|
35
|
-
async with self.client.Chunks.open(timeout=timeout, metadata=md) as chunks_stream:
|
|
36
|
-
await chunks_stream.send_message(
|
|
37
|
-
ChunksRequest(name=self.name, sample_format=SampleFormat.SAMPLE_FORMAT_FLOAT32_INTERLEAVED), end=True
|
|
38
|
-
)
|
|
39
|
-
response: Union[ChunksResponse, None] = await chunks_stream.recv_message()
|
|
40
|
-
if not response:
|
|
41
|
-
await chunks_stream.recv_trailing_metadata() # causes us to throw appropriate gRPC error.
|
|
42
|
-
raise TypeError("Response cannot be empty") # we should never get here, but for typechecking
|
|
43
|
-
assert response.HasField("info")
|
|
44
|
-
info = response.info
|
|
45
|
-
|
|
46
|
-
while True:
|
|
47
|
-
response = await chunks_stream.recv_message()
|
|
48
|
-
if response is None:
|
|
49
|
-
break
|
|
50
|
-
assert response.HasField("chunk")
|
|
51
|
-
audio = Audio(info=info, chunk=response.chunk)
|
|
52
|
-
yield audio
|
|
53
|
-
|
|
54
|
-
return StreamWithIterator(read())
|
|
55
|
-
|
|
56
|
-
async def get_properties(self, *, timeout: Optional[float] = None, **kwargs) -> AudioInput.Properties:
|
|
57
|
-
md = kwargs.get("metadata", self.Metadata()).proto
|
|
58
|
-
request = PropertiesRequest(name=self.name)
|
|
59
|
-
response: PropertiesResponse = await self.client.Properties(request, timeout=timeout, metadata=md)
|
|
60
|
-
return AudioInput.Properties.from_proto(response)
|
|
61
|
-
|
|
62
|
-
async def do_command(self, command: Mapping[str, ValueTypes], *, timeout: Optional[float] = None, **kwargs) -> Mapping[str, ValueTypes]:
|
|
63
|
-
md = kwargs.get("metadata", self.Metadata()).proto
|
|
64
|
-
request = DoCommandRequest(name=self.name, command=dict_to_struct(command))
|
|
65
|
-
response: DoCommandResponse = await self.client.DoCommand(request, timeout=timeout, metadata=md)
|
|
66
|
-
return struct_to_dict(response.result)
|
|
67
|
-
|
|
68
|
-
async def get_geometries(self, *, extra: Optional[Dict[str, Any]] = None, timeout: Optional[float] = None, **kwargs) -> List[Geometry]:
|
|
69
|
-
md = kwargs.get("metadata", self.Metadata())
|
|
70
|
-
return await get_geometries(self.client, self.name, extra, timeout, md)
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import wave
|
|
2
|
-
from datetime import timedelta
|
|
3
|
-
from io import BytesIO
|
|
4
|
-
|
|
5
|
-
from google.api.httpbody_pb2 import HttpBody # type: ignore
|
|
6
|
-
from grpclib import GRPCError, Status
|
|
7
|
-
from grpclib.server import Stream
|
|
8
|
-
|
|
9
|
-
from viam.errors import NotSupportedError
|
|
10
|
-
from viam.proto.common import DoCommandRequest, DoCommandResponse, GetGeometriesRequest, GetGeometriesResponse
|
|
11
|
-
from viam.proto.component.audioinput import (
|
|
12
|
-
AudioInputServiceBase,
|
|
13
|
-
ChunksRequest,
|
|
14
|
-
ChunksResponse,
|
|
15
|
-
PropertiesRequest,
|
|
16
|
-
PropertiesResponse,
|
|
17
|
-
RecordRequest,
|
|
18
|
-
SampleFormat,
|
|
19
|
-
)
|
|
20
|
-
from viam.resource.rpc_service_base import ResourceRPCServiceBase
|
|
21
|
-
from viam.utils import dict_to_struct, struct_to_dict
|
|
22
|
-
|
|
23
|
-
from .audio_input import AudioInput
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
class AudioInputRPCService(AudioInputServiceBase, ResourceRPCServiceBase[AudioInput]):
|
|
27
|
-
"""
|
|
28
|
-
gRPC Service for a generic AudioInput
|
|
29
|
-
"""
|
|
30
|
-
|
|
31
|
-
RESOURCE_TYPE = AudioInput
|
|
32
|
-
|
|
33
|
-
async def Chunks(self, stream: Stream[ChunksRequest, ChunksResponse]) -> None:
|
|
34
|
-
request = await stream.recv_message()
|
|
35
|
-
assert request is not None
|
|
36
|
-
audio_input = self.get_resource(request.name)
|
|
37
|
-
timeout = stream.deadline.time_remaining() if stream.deadline else None
|
|
38
|
-
audio_stream = await audio_input.stream(timeout=timeout, metadata=stream.metadata)
|
|
39
|
-
first_chunk = await audio_stream.__anext__()
|
|
40
|
-
await stream.send_message(ChunksResponse(info=first_chunk.info))
|
|
41
|
-
await stream.send_message(ChunksResponse(chunk=first_chunk.chunk))
|
|
42
|
-
|
|
43
|
-
async for audio in audio_stream:
|
|
44
|
-
await stream.send_message(ChunksResponse(chunk=audio.chunk))
|
|
45
|
-
|
|
46
|
-
async def Properties(self, stream: Stream[PropertiesRequest, PropertiesResponse]) -> None:
|
|
47
|
-
request = await stream.recv_message()
|
|
48
|
-
assert request is not None
|
|
49
|
-
audio_input = self.get_resource(request.name)
|
|
50
|
-
timeout = stream.deadline.time_remaining() if stream.deadline else None
|
|
51
|
-
response = (await audio_input.get_properties(timeout=timeout, metadata=stream.metadata)).proto
|
|
52
|
-
await stream.send_message(response)
|
|
53
|
-
|
|
54
|
-
async def Record(self, stream: Stream[RecordRequest, HttpBody]) -> None: # pyright: ignore [reportInvalidTypeForm]
|
|
55
|
-
raise NotSupportedError("Recording audio input is not supported").grpc_error
|
|
56
|
-
|
|
57
|
-
# TODO: Eventually implement recording
|
|
58
|
-
request = await stream.recv_message()
|
|
59
|
-
assert request is not None
|
|
60
|
-
duration = request.duration.ToTimedelta()
|
|
61
|
-
if duration.total_seconds() == 0:
|
|
62
|
-
duration = timedelta(seconds=1)
|
|
63
|
-
if duration.total_seconds() > 5:
|
|
64
|
-
raise GRPCError(Status.INVALID_ARGUMENT, "Can only record up to 5 seconds")
|
|
65
|
-
|
|
66
|
-
audio_input = self.get_resource(request.name)
|
|
67
|
-
audio_stream = await audio_input.stream()
|
|
68
|
-
first_chunk = await audio_stream.__anext__()
|
|
69
|
-
num_chunks = int(duration.total_seconds() * float(first_chunk.info.sampling_rate / first_chunk.chunk.length))
|
|
70
|
-
|
|
71
|
-
sample_width: int
|
|
72
|
-
if first_chunk.info.sample_format == SampleFormat.SAMPLE_FORMAT_INT16_INTERLEAVED:
|
|
73
|
-
sample_width = 2
|
|
74
|
-
elif first_chunk.info.sample_format == SampleFormat.SAMPLE_FORMAT_FLOAT32_INTERLEAVED:
|
|
75
|
-
sample_width = 4
|
|
76
|
-
else:
|
|
77
|
-
raise GRPCError(Status.INVALID_ARGUMENT, "Unspecified type of audio buffer")
|
|
78
|
-
|
|
79
|
-
output = BytesIO()
|
|
80
|
-
wav_file = wave.open(output, "w")
|
|
81
|
-
wav_file.setnchannels(first_chunk.info.channels)
|
|
82
|
-
wav_file.setframerate(first_chunk.info.sampling_rate)
|
|
83
|
-
wav_file.setsampwidth(sample_width)
|
|
84
|
-
try:
|
|
85
|
-
wav_file.writeframes(first_chunk.chunk.data)
|
|
86
|
-
for _ in range(num_chunks - 1):
|
|
87
|
-
chunk = await audio_stream.__anext__()
|
|
88
|
-
wav_file.writeframes(chunk.chunk.data)
|
|
89
|
-
finally:
|
|
90
|
-
wav_file.close()
|
|
91
|
-
output.close()
|
|
92
|
-
|
|
93
|
-
output.seek(0)
|
|
94
|
-
response = HttpBody(data=output.read(), content_type="audio/wav")
|
|
95
|
-
|
|
96
|
-
await stream.send_message(response)
|
|
97
|
-
|
|
98
|
-
async def DoCommand(self, stream: Stream[DoCommandRequest, DoCommandResponse]) -> None:
|
|
99
|
-
request = await stream.recv_message()
|
|
100
|
-
assert request is not None
|
|
101
|
-
audio_input = self.get_resource(request.name)
|
|
102
|
-
timeout = stream.deadline.time_remaining() if stream.deadline else None
|
|
103
|
-
result = await audio_input.do_command(command=struct_to_dict(request.command), timeout=timeout, metadata=stream.metadata)
|
|
104
|
-
response = DoCommandResponse(result=dict_to_struct(result))
|
|
105
|
-
await stream.send_message(response)
|
|
106
|
-
|
|
107
|
-
async def GetGeometries(self, stream: Stream[GetGeometriesRequest, GetGeometriesResponse]) -> None:
|
|
108
|
-
request = await stream.recv_message()
|
|
109
|
-
assert request is not None
|
|
110
|
-
audio_input = self.get_resource(request.name)
|
|
111
|
-
timeout = stream.deadline.time_remaining() if stream.deadline else None
|
|
112
|
-
geometries = await audio_input.get_geometries(extra=struct_to_dict(request.extra), timeout=timeout)
|
|
113
|
-
response = GetGeometriesResponse(geometries=geometries)
|
|
114
|
-
await stream.send_message(response)
|
|
File without changes
|