From 012b2e57c16ed3870913c25a337a55afb28347ac Mon Sep 17 00:00:00 2001 From: oliviamiller <106617921+oliviamiller@users.noreply.github.com> Date: Thu, 14 May 2026 13:41:26 -0400 Subject: [PATCH 1/5] play stream --- , | 0 src/viam/components/audio_out/audio_out.py | 33 ++++- src/viam/components/audio_out/client.py | 31 ++++- src/viam/components/audio_out/service.py | 30 +++++ .../component/audioout/v1/audioout_grpc.py | 95 ++++++++++++++- .../gen/component/audioout/v1/audioout_pb2.py | 68 ++++++++--- .../component/audioout/v1/audioout_pb2.pyi | 114 +++++++++++++++--- src/viam/proto/component/audioout/__init__.py | 13 +- tests/mocks/components.py | 18 +++ tests/test_audio_out.py | 88 +++++++++++++- 10 files changed, 444 insertions(+), 46 deletions(-) create mode 100644 , diff --git a/, b/, new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/viam/components/audio_out/audio_out.py b/src/viam/components/audio_out/audio_out.py index 98ac5ed96b..2d21291a7b 100644 --- a/src/viam/components/audio_out/audio_out.py +++ b/src/viam/components/audio_out/audio_out.py @@ -1,5 +1,5 @@ import abc -from typing import Any, Dict, Final, Optional, TypeAlias +from typing import Any, AsyncIterable, Dict, Final, Optional, TypeAlias from viam.proto.common import GetPropertiesResponse from viam.resource.types import API, RESOURCE_NAMESPACE_RDK, RESOURCE_TYPE_COMPONENT @@ -51,6 +51,37 @@ async def play( info: (optional) information about the audio data such as codec, sample rate, and channel count """ + @abc.abstractmethod + async def play_stream( + self, + info: AudioInfo, + chunks: AsyncIterable[bytes], + *, + extra: Optional[Dict[str, Any]] = None, + timeout: Optional[float] = None, + **kwargs, + ) -> None: + """ + Stream audio chunks to the audio output device for playback. + + The caller provides an async iterable of raw audio bytes. Each chunk + must match the codec and format described by ``info``. Implementations + consume the iterable until it is exhausted, playing chunks as they arrive. + + :: + + async def chunk_source(): + for chunk in pcm_chunks: + yield chunk + + audio_info = AudioInfo(codec="pcm16", sample_rate_hz=22050, num_channels=1) + await my_audio_out.play_stream(audio_info, chunk_source()) + + Args: + info: information about the audio stream such as codec, sample rate, and channel count + chunks: async iterable of audio bytes to play in order + """ + @abc.abstractmethod async def get_properties(self, *, extra: Optional[Dict[str, Any]] = None, timeout: Optional[float] = None, **kwargs) -> Properties: """ diff --git a/src/viam/components/audio_out/client.py b/src/viam/components/audio_out/client.py index dc765afae6..cf84ab2a1c 100644 --- a/src/viam/components/audio_out/client.py +++ b/src/viam/components/audio_out/client.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Mapping, Optional +from typing import Any, AsyncIterable, Dict, List, Mapping, Optional from grpclib.client import Channel @@ -11,7 +11,13 @@ GetStatusRequest, GetStatusResponse, ) -from viam.proto.component.audioout import AudioOutServiceStub, PlayRequest +from viam.proto.component.audioout import ( + AudioOutServiceStub, + PlayRequest, + PlayStreamChunk, + PlayStreamInit, + PlayStreamRequest, +) from viam.resource.rpc_client_base import ReconfigurableResourceRPCClientBase from viam.utils import ValueTypes, dict_to_struct, get_geometries, struct_to_dict @@ -47,6 +53,27 @@ async def play( ) await self.client.Play(request, timeout=timeout, metadata=md) + async def play_stream( + self, + info: AudioInfo, + chunks: AsyncIterable[bytes], + *, + extra: Optional[Dict[str, Any]] = None, + timeout: Optional[float] = None, + **kwargs, + ) -> None: + if extra is None: + extra = {} + + md = kwargs.get("metadata", self.Metadata()).proto + init = PlayStreamRequest(init=PlayStreamInit(name=self.name, audio_info=info, extra=dict_to_struct(extra))) + async with self.client.PlayStream.open(timeout=timeout, metadata=md) as stream: + await stream.send_message(init) + async for chunk in chunks: + await stream.send_message(PlayStreamRequest(audio_chunk=PlayStreamChunk(audio_data=chunk))) + await stream.end() + await stream.recv_message() + async def get_properties( self, *, extra: Optional[Dict[str, Any]] = None, timeout: Optional[float] = None, **kwargs ) -> AudioOut.Properties: diff --git a/src/viam/components/audio_out/service.py b/src/viam/components/audio_out/service.py index b50135e8b8..f840b661aa 100644 --- a/src/viam/components/audio_out/service.py +++ b/src/viam/components/audio_out/service.py @@ -1,3 +1,6 @@ +from typing import AsyncIterator + +from grpclib import GRPCError, Status from grpclib.server import Stream from viam.proto.common import ( @@ -14,6 +17,8 @@ AudioOutServiceBase, PlayRequest, PlayResponse, + PlayStreamRequest, + PlayStreamResponse, ) from viam.resource.rpc_service_base import ResourceRPCServiceBase from viam.utils import dict_to_struct, struct_to_dict @@ -37,6 +42,31 @@ async def Play(self, stream: Stream[PlayRequest, PlayResponse]) -> None: await audio_out.play(request.audio_data, audio_info, extra=struct_to_dict(request.extra), timeout=timeout, metadata=stream.metadata) await stream.send_message(PlayResponse()) + async def PlayStream(self, stream: Stream[PlayStreamRequest, PlayStreamResponse]) -> None: + first = await stream.recv_message() + if first is None: + raise GRPCError(Status.INVALID_ARGUMENT, "PlayStream: stream closed before init message") + if not first.HasField("init"): + raise GRPCError(Status.INVALID_ARGUMENT, "PlayStream: first message must be PlayStreamInit") + init = first.init + audio_out = self.get_resource(init.name) + audio_info = init.audio_info if init.HasField("audio_info") else None + + async def chunks() -> AsyncIterator[bytes]: + async for msg in stream: + if msg.HasField("audio_chunk"): + yield msg.audio_chunk.audio_data + + timeout = stream.deadline.time_remaining() if stream.deadline else None + await audio_out.play_stream( + audio_info, + chunks(), + extra=struct_to_dict(init.extra), + timeout=timeout, + metadata=stream.metadata, + ) + await stream.send_message(PlayStreamResponse()) + async def GetProperties(self, stream: Stream[GetPropertiesRequest, GetPropertiesResponse]) -> None: request = await stream.recv_message() assert request is not None diff --git a/src/viam/gen/component/audioout/v1/audioout_grpc.py b/src/viam/gen/component/audioout/v1/audioout_grpc.py index 6c03fcd77f..a5bc941826 100644 --- a/src/viam/gen/component/audioout/v1/audioout_grpc.py +++ b/src/viam/gen/component/audioout/v1/audioout_grpc.py @@ -1,21 +1,31 @@ +# Generated by the Protocol Buffers compiler. DO NOT EDIT! +# source: component/audioout/v1/audioout.proto +# plugin: __main__ import abc import typing + import grpclib.const import grpclib.client import grpclib.exceptions if typing.TYPE_CHECKING: import grpclib.server + from .... import common import google.api.annotations_pb2 import google.protobuf.struct_pb2 from .... import component + class AudioOutServiceBase(abc.ABC): @abc.abstractmethod async def Play(self, stream: 'grpclib.server.Stream[component.audioout.v1.audioout_pb2.PlayRequest, component.audioout.v1.audioout_pb2.PlayResponse]') -> None: pass + @abc.abstractmethod + async def PlayStream(self, stream: 'grpclib.server.Stream[component.audioout.v1.audioout_pb2.PlayStreamRequest, component.audioout.v1.audioout_pb2.PlayStreamResponse]') -> None: + pass + @abc.abstractmethod async def GetProperties(self, stream: 'grpclib.server.Stream[common.v1.common_pb2.GetPropertiesRequest, common.v1.common_pb2.GetPropertiesResponse]') -> None: pass @@ -33,13 +43,54 @@ async def GetGeometries(self, stream: 'grpclib.server.Stream[common.v1.common_pb pass def __mapping__(self) -> typing.Dict[str, grpclib.const.Handler]: - return {'/viam.component.audioout.v1.AudioOutService/Play': grpclib.const.Handler(self.Play, grpclib.const.Cardinality.UNARY_UNARY, component.audioout.v1.audioout_pb2.PlayRequest, component.audioout.v1.audioout_pb2.PlayResponse), '/viam.component.audioout.v1.AudioOutService/GetProperties': grpclib.const.Handler(self.GetProperties, grpclib.const.Cardinality.UNARY_UNARY, common.v1.common_pb2.GetPropertiesRequest, common.v1.common_pb2.GetPropertiesResponse), '/viam.component.audioout.v1.AudioOutService/DoCommand': grpclib.const.Handler(self.DoCommand, grpclib.const.Cardinality.UNARY_UNARY, common.v1.common_pb2.DoCommandRequest, common.v1.common_pb2.DoCommandResponse), '/viam.component.audioout.v1.AudioOutService/GetStatus': grpclib.const.Handler(self.GetStatus, grpclib.const.Cardinality.UNARY_UNARY, common.v1.common_pb2.GetStatusRequest, common.v1.common_pb2.GetStatusResponse), '/viam.component.audioout.v1.AudioOutService/GetGeometries': grpclib.const.Handler(self.GetGeometries, grpclib.const.Cardinality.UNARY_UNARY, common.v1.common_pb2.GetGeometriesRequest, common.v1.common_pb2.GetGeometriesResponse)} + return { + '/viam.component.audioout.v1.AudioOutService/Play': grpclib.const.Handler( + self.Play, + grpclib.const.Cardinality.UNARY_UNARY, + component.audioout.v1.audioout_pb2.PlayRequest, + component.audioout.v1.audioout_pb2.PlayResponse, + ), + '/viam.component.audioout.v1.AudioOutService/PlayStream': grpclib.const.Handler( + self.PlayStream, + grpclib.const.Cardinality.STREAM_UNARY, + component.audioout.v1.audioout_pb2.PlayStreamRequest, + component.audioout.v1.audioout_pb2.PlayStreamResponse, + ), + '/viam.component.audioout.v1.AudioOutService/GetProperties': grpclib.const.Handler( + self.GetProperties, + grpclib.const.Cardinality.UNARY_UNARY, + common.v1.common_pb2.GetPropertiesRequest, + common.v1.common_pb2.GetPropertiesResponse, + ), + '/viam.component.audioout.v1.AudioOutService/DoCommand': grpclib.const.Handler( + self.DoCommand, + grpclib.const.Cardinality.UNARY_UNARY, + common.v1.common_pb2.DoCommandRequest, + common.v1.common_pb2.DoCommandResponse, + ), + '/viam.component.audioout.v1.AudioOutService/GetStatus': grpclib.const.Handler( + self.GetStatus, + grpclib.const.Cardinality.UNARY_UNARY, + common.v1.common_pb2.GetStatusRequest, + common.v1.common_pb2.GetStatusResponse, + ), + '/viam.component.audioout.v1.AudioOutService/GetGeometries': grpclib.const.Handler( + self.GetGeometries, + grpclib.const.Cardinality.UNARY_UNARY, + common.v1.common_pb2.GetGeometriesRequest, + common.v1.common_pb2.GetGeometriesResponse, + ), + } + class UnimplementedAudioOutServiceBase(AudioOutServiceBase): async def Play(self, stream: 'grpclib.server.Stream[component.audioout.v1.audioout_pb2.PlayRequest, component.audioout.v1.audioout_pb2.PlayResponse]') -> None: raise grpclib.exceptions.GRPCError(grpclib.const.Status.UNIMPLEMENTED) + async def PlayStream(self, stream: 'grpclib.server.Stream[component.audioout.v1.audioout_pb2.PlayStreamRequest, component.audioout.v1.audioout_pb2.PlayStreamResponse]') -> None: + raise grpclib.exceptions.GRPCError(grpclib.const.Status.UNIMPLEMENTED) + async def GetProperties(self, stream: 'grpclib.server.Stream[common.v1.common_pb2.GetPropertiesRequest, common.v1.common_pb2.GetPropertiesResponse]') -> None: raise grpclib.exceptions.GRPCError(grpclib.const.Status.UNIMPLEMENTED) @@ -52,11 +103,43 @@ async def GetStatus(self, stream: 'grpclib.server.Stream[common.v1.common_pb2.Ge async def GetGeometries(self, stream: 'grpclib.server.Stream[common.v1.common_pb2.GetGeometriesRequest, common.v1.common_pb2.GetGeometriesResponse]') -> None: raise grpclib.exceptions.GRPCError(grpclib.const.Status.UNIMPLEMENTED) + class AudioOutServiceStub: def __init__(self, channel: grpclib.client.Channel) -> None: - self.Play = grpclib.client.UnaryUnaryMethod(channel, '/viam.component.audioout.v1.AudioOutService/Play', component.audioout.v1.audioout_pb2.PlayRequest, component.audioout.v1.audioout_pb2.PlayResponse) - self.GetProperties = grpclib.client.UnaryUnaryMethod(channel, '/viam.component.audioout.v1.AudioOutService/GetProperties', common.v1.common_pb2.GetPropertiesRequest, common.v1.common_pb2.GetPropertiesResponse) - self.DoCommand = grpclib.client.UnaryUnaryMethod(channel, '/viam.component.audioout.v1.AudioOutService/DoCommand', common.v1.common_pb2.DoCommandRequest, common.v1.common_pb2.DoCommandResponse) - self.GetStatus = grpclib.client.UnaryUnaryMethod(channel, '/viam.component.audioout.v1.AudioOutService/GetStatus', common.v1.common_pb2.GetStatusRequest, common.v1.common_pb2.GetStatusResponse) - self.GetGeometries = grpclib.client.UnaryUnaryMethod(channel, '/viam.component.audioout.v1.AudioOutService/GetGeometries', common.v1.common_pb2.GetGeometriesRequest, common.v1.common_pb2.GetGeometriesResponse) \ No newline at end of file + self.Play = grpclib.client.UnaryUnaryMethod( + channel, + '/viam.component.audioout.v1.AudioOutService/Play', + component.audioout.v1.audioout_pb2.PlayRequest, + component.audioout.v1.audioout_pb2.PlayResponse, + ) + self.PlayStream = grpclib.client.StreamUnaryMethod( + channel, + '/viam.component.audioout.v1.AudioOutService/PlayStream', + component.audioout.v1.audioout_pb2.PlayStreamRequest, + component.audioout.v1.audioout_pb2.PlayStreamResponse, + ) + self.GetProperties = grpclib.client.UnaryUnaryMethod( + channel, + '/viam.component.audioout.v1.AudioOutService/GetProperties', + common.v1.common_pb2.GetPropertiesRequest, + common.v1.common_pb2.GetPropertiesResponse, + ) + self.DoCommand = grpclib.client.UnaryUnaryMethod( + channel, + '/viam.component.audioout.v1.AudioOutService/DoCommand', + common.v1.common_pb2.DoCommandRequest, + common.v1.common_pb2.DoCommandResponse, + ) + self.GetStatus = grpclib.client.UnaryUnaryMethod( + channel, + '/viam.component.audioout.v1.AudioOutService/GetStatus', + common.v1.common_pb2.GetStatusRequest, + common.v1.common_pb2.GetStatusResponse, + ) + self.GetGeometries = grpclib.client.UnaryUnaryMethod( + channel, + '/viam.component.audioout.v1.AudioOutService/GetGeometries', + common.v1.common_pb2.GetGeometriesRequest, + common.v1.common_pb2.GetGeometriesResponse, + ) diff --git a/src/viam/gen/component/audioout/v1/audioout_pb2.py b/src/viam/gen/component/audioout/v1/audioout_pb2.py index e5a713f62d..1c4112f9c0 100644 --- a/src/viam/gen/component/audioout/v1/audioout_pb2.py +++ b/src/viam/gen/component/audioout/v1/audioout_pb2.py @@ -1,34 +1,62 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: component/audioout/v1/audioout.proto +# Protobuf Python Version: 7.34.1 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool from google.protobuf import runtime_version as _runtime_version from google.protobuf import symbol_database as _symbol_database from google.protobuf.internal import builder as _builder -_runtime_version.ValidateProtobufRuntimeVersion(_runtime_version.Domain.PUBLIC, 6, 33, 5, '', 'component/audioout/v1/audioout.proto') +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 6, + 33, + 5, + '', + 'component/audioout/v1/audioout.proto' +) +# @@protoc_insertion_point(imports) + _sym_db = _symbol_database.Default() + + from ....common.v1 import common_pb2 as common_dot_v1_dot_common__pb2 from google.api import annotations_pb2 as google_dot_api_dot_annotations__pb2 from google.protobuf import struct_pb2 as google_dot_protobuf_dot_struct__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n$component/audioout/v1/audioout.proto\x12\x1aviam.component.audioout.v1\x1a\x16common/v1/common.proto\x1a\x1cgoogle/api/annotations.proto\x1a\x1cgoogle/protobuf/struct.proto"\xa9\x01\n\x0bPlayRequest\x12\x12\n\x04name\x18\x01 \x01(\tR\x04name\x12\x1d\n\naudio_data\x18\x02 \x01(\x0cR\taudioData\x128\n\naudio_info\x18\x03 \x01(\x0b2\x19.viam.common.v1.AudioInfoR\taudioInfo\x12-\n\x05extra\x18c \x01(\x0b2\x17.google.protobuf.StructR\x05extra"\x0e\n\x0cPlayResponse2\xee\x05\n\x0fAudioOutService\x12\x8e\x01\n\x04Play\x12\'.viam.component.audioout.v1.PlayRequest\x1a(.viam.component.audioout.v1.PlayResponse"3\x82\xd3\xe4\x93\x02-"+/viam/api/v1/component/audioout/{name}/play\x12\x97\x01\n\rGetProperties\x12$.viam.common.v1.GetPropertiesRequest\x1a%.viam.common.v1.GetPropertiesResponse"9\x82\xd3\xe4\x93\x023\x121/viam/api/v1/component/audioout/{name}/properties\x12\x89\x01\n\tDoCommand\x12 .viam.common.v1.DoCommandRequest\x1a!.viam.common.v1.DoCommandResponse"7\x82\xd3\xe4\x93\x021"//viam/api/v1/service/audioout/{name}/do_command\x12\x89\x01\n\tGetStatus\x12 .viam.common.v1.GetStatusRequest\x1a!.viam.common.v1.GetStatusResponse"7\x82\xd3\xe4\x93\x021\x12//viam/api/v1/service/audioout/{name}/get_status\x12\x97\x01\n\rGetGeometries\x12$.viam.common.v1.GetGeometriesRequest\x1a%.viam.common.v1.GetGeometriesResponse"9\x82\xd3\xe4\x93\x023\x121/viam/api/v1/component/audioout/{name}/geometriesBG\n\x1ecom.viam.component.audioout.v1Z%go.viam.com/api/component/audioout/v1b\x06proto3') + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n$component/audioout/v1/audioout.proto\x12\x1aviam.component.audioout.v1\x1a\x16\x63ommon/v1/common.proto\x1a\x1cgoogle/api/annotations.proto\x1a\x1cgoogle/protobuf/struct.proto\"\xa9\x01\n\x0bPlayRequest\x12\x12\n\x04name\x18\x01 \x01(\tR\x04name\x12\x1d\n\naudio_data\x18\x02 \x01(\x0cR\taudioData\x12\x38\n\naudio_info\x18\x03 \x01(\x0b\x32\x19.viam.common.v1.AudioInfoR\taudioInfo\x12-\n\x05\x65xtra\x18\x63 \x01(\x0b\x32\x17.google.protobuf.StructR\x05\x65xtra\"\xb0\x01\n\x11PlayStreamRequest\x12@\n\x04init\x18\x01 \x01(\x0b\x32*.viam.component.audioout.v1.PlayStreamInitH\x00R\x04init\x12N\n\x0b\x61udio_chunk\x18\x02 \x01(\x0b\x32+.viam.component.audioout.v1.PlayStreamChunkH\x00R\naudioChunkB\t\n\x07payload\"0\n\x0fPlayStreamChunk\x12\x1d\n\naudio_data\x18\x01 \x01(\x0cR\taudioData\"\x8d\x01\n\x0ePlayStreamInit\x12\x12\n\x04name\x18\x01 \x01(\tR\x04name\x12\x38\n\naudio_info\x18\x02 \x01(\x0b\x32\x19.viam.common.v1.AudioInfoR\taudioInfo\x12-\n\x05\x65xtra\x18\x63 \x01(\x0b\x32\x17.google.protobuf.StructR\x05\x65xtra\"\x0e\n\x0cPlayResponse\"\x14\n\x12PlayStreamResponse2\xdd\x06\n\x0f\x41udioOutService\x12\x8e\x01\n\x04Play\x12\'.viam.component.audioout.v1.PlayRequest\x1a(.viam.component.audioout.v1.PlayResponse\"3\x82\xd3\xe4\x93\x02-\"+/viam/api/v1/component/audioout/{name}/play\x12m\n\nPlayStream\x12-.viam.component.audioout.v1.PlayStreamRequest\x1a..viam.component.audioout.v1.PlayStreamResponse(\x01\x12\x97\x01\n\rGetProperties\x12$.viam.common.v1.GetPropertiesRequest\x1a%.viam.common.v1.GetPropertiesResponse\"9\x82\xd3\xe4\x93\x02\x33\x12\x31/viam/api/v1/component/audioout/{name}/properties\x12\x89\x01\n\tDoCommand\x12 .viam.common.v1.DoCommandRequest\x1a!.viam.common.v1.DoCommandResponse\"7\x82\xd3\xe4\x93\x02\x31\"//viam/api/v1/service/audioout/{name}/do_command\x12\x89\x01\n\tGetStatus\x12 .viam.common.v1.GetStatusRequest\x1a!.viam.common.v1.GetStatusResponse\"7\x82\xd3\xe4\x93\x02\x31\x12//viam/api/v1/service/audioout/{name}/get_status\x12\x97\x01\n\rGetGeometries\x12$.viam.common.v1.GetGeometriesRequest\x1a%.viam.common.v1.GetGeometriesResponse\"9\x82\xd3\xe4\x93\x02\x33\x12\x31/viam/api/v1/component/audioout/{name}/geometriesBG\n\x1e\x63om.viam.component.audioout.v1Z%go.viam.com/api/component/audioout/v1b\x06proto3') + _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'component.audioout.v1.audioout_pb2', _globals) if not _descriptor._USE_C_DESCRIPTORS: - _globals['DESCRIPTOR']._loaded_options = None - _globals['DESCRIPTOR']._serialized_options = b'\n\x1ecom.viam.component.audioout.v1Z%go.viam.com/api/component/audioout/v1' - _globals['_AUDIOOUTSERVICE'].methods_by_name['Play']._loaded_options = None - _globals['_AUDIOOUTSERVICE'].methods_by_name['Play']._serialized_options = b'\x82\xd3\xe4\x93\x02-"+/viam/api/v1/component/audioout/{name}/play' - _globals['_AUDIOOUTSERVICE'].methods_by_name['GetProperties']._loaded_options = None - _globals['_AUDIOOUTSERVICE'].methods_by_name['GetProperties']._serialized_options = b'\x82\xd3\xe4\x93\x023\x121/viam/api/v1/component/audioout/{name}/properties' - _globals['_AUDIOOUTSERVICE'].methods_by_name['DoCommand']._loaded_options = None - _globals['_AUDIOOUTSERVICE'].methods_by_name['DoCommand']._serialized_options = b'\x82\xd3\xe4\x93\x021"//viam/api/v1/service/audioout/{name}/do_command' - _globals['_AUDIOOUTSERVICE'].methods_by_name['GetStatus']._loaded_options = None - _globals['_AUDIOOUTSERVICE'].methods_by_name['GetStatus']._serialized_options = b'\x82\xd3\xe4\x93\x021\x12//viam/api/v1/service/audioout/{name}/get_status' - _globals['_AUDIOOUTSERVICE'].methods_by_name['GetGeometries']._loaded_options = None - _globals['_AUDIOOUTSERVICE'].methods_by_name['GetGeometries']._serialized_options = b'\x82\xd3\xe4\x93\x023\x121/viam/api/v1/component/audioout/{name}/geometries' - _globals['_PLAYREQUEST']._serialized_start = 153 - _globals['_PLAYREQUEST']._serialized_end = 322 - _globals['_PLAYRESPONSE']._serialized_start = 324 - _globals['_PLAYRESPONSE']._serialized_end = 338 - _globals['_AUDIOOUTSERVICE']._serialized_start = 341 - _globals['_AUDIOOUTSERVICE']._serialized_end = 1091 \ No newline at end of file + _globals['DESCRIPTOR']._loaded_options = None + _globals['DESCRIPTOR']._serialized_options = b'\n\036com.viam.component.audioout.v1Z%go.viam.com/api/component/audioout/v1' + _globals['_AUDIOOUTSERVICE'].methods_by_name['Play']._loaded_options = None + _globals['_AUDIOOUTSERVICE'].methods_by_name['Play']._serialized_options = b'\202\323\344\223\002-\"+/viam/api/v1/component/audioout/{name}/play' + _globals['_AUDIOOUTSERVICE'].methods_by_name['GetProperties']._loaded_options = None + _globals['_AUDIOOUTSERVICE'].methods_by_name['GetProperties']._serialized_options = b'\202\323\344\223\0023\0221/viam/api/v1/component/audioout/{name}/properties' + _globals['_AUDIOOUTSERVICE'].methods_by_name['DoCommand']._loaded_options = None + _globals['_AUDIOOUTSERVICE'].methods_by_name['DoCommand']._serialized_options = b'\202\323\344\223\0021\"//viam/api/v1/service/audioout/{name}/do_command' + _globals['_AUDIOOUTSERVICE'].methods_by_name['GetStatus']._loaded_options = None + _globals['_AUDIOOUTSERVICE'].methods_by_name['GetStatus']._serialized_options = b'\202\323\344\223\0021\022//viam/api/v1/service/audioout/{name}/get_status' + _globals['_AUDIOOUTSERVICE'].methods_by_name['GetGeometries']._loaded_options = None + _globals['_AUDIOOUTSERVICE'].methods_by_name['GetGeometries']._serialized_options = b'\202\323\344\223\0023\0221/viam/api/v1/component/audioout/{name}/geometries' + _globals['_PLAYREQUEST']._serialized_start=153 + _globals['_PLAYREQUEST']._serialized_end=322 + _globals['_PLAYSTREAMREQUEST']._serialized_start=325 + _globals['_PLAYSTREAMREQUEST']._serialized_end=501 + _globals['_PLAYSTREAMCHUNK']._serialized_start=503 + _globals['_PLAYSTREAMCHUNK']._serialized_end=551 + _globals['_PLAYSTREAMINIT']._serialized_start=554 + _globals['_PLAYSTREAMINIT']._serialized_end=695 + _globals['_PLAYRESPONSE']._serialized_start=697 + _globals['_PLAYRESPONSE']._serialized_end=711 + _globals['_PLAYSTREAMRESPONSE']._serialized_start=713 + _globals['_PLAYSTREAMRESPONSE']._serialized_end=733 + _globals['_AUDIOOUTSERVICE']._serialized_start=736 + _globals['_AUDIOOUTSERVICE']._serialized_end=1597 +# @@protoc_insertion_point(module_scope) diff --git a/src/viam/gen/component/audioout/v1/audioout_pb2.pyi b/src/viam/gen/component/audioout/v1/audioout_pb2.pyi index ee73e6291e..6bd8cab3a0 100644 --- a/src/viam/gen/component/audioout/v1/audioout_pb2.pyi +++ b/src/viam/gen/component/audioout/v1/audioout_pb2.pyi @@ -2,6 +2,7 @@ @generated by mypy-protobuf. Do not edit manually! isort:skip_file """ + from common.v1 import common_pb2 as _common_pb2 from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message @@ -9,46 +10,129 @@ from google.protobuf import struct_pb2 as _struct_pb2 import builtins as _builtins import sys import typing as _typing + if sys.version_info >= (3, 10): from typing import TypeAlias as _TypeAlias else: from typing_extensions import TypeAlias as _TypeAlias + DESCRIPTOR: _descriptor.FileDescriptor @_typing.final class PlayRequest(_message.Message): DESCRIPTOR: _descriptor.Descriptor + NAME_FIELD_NUMBER: _builtins.int AUDIO_DATA_FIELD_NUMBER: _builtins.int AUDIO_INFO_FIELD_NUMBER: _builtins.int EXTRA_FIELD_NUMBER: _builtins.int name: _builtins.str audio_data: _builtins.bytes - @_builtins.property def audio_info(self) -> _common_pb2.AudioInfo: """Info describing the audio_data""" @_builtins.property - def extra(self) -> _struct_pb2.Struct: - ... + def extra(self) -> _struct_pb2.Struct: ... + def __init__( + self, + *, + name: _builtins.str = ..., + audio_data: _builtins.bytes = ..., + audio_info: _common_pb2.AudioInfo | None = ..., + extra: _struct_pb2.Struct | None = ..., + ) -> None: ... + _HasFieldArgType: _TypeAlias = _typing.Literal["audio_info", b"audio_info", "extra", b"extra"] # noqa: Y015 + def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: ... + _ClearFieldArgType: _TypeAlias = _typing.Literal["audio_data", b"audio_data", "audio_info", b"audio_info", "extra", b"extra", "name", b"name"] # noqa: Y015 + def ClearField(self, field_name: _ClearFieldArgType) -> None: ... + +Global___PlayRequest: _TypeAlias = PlayRequest # noqa: Y015 + +@_typing.final +class PlayStreamRequest(_message.Message): + DESCRIPTOR: _descriptor.Descriptor + + INIT_FIELD_NUMBER: _builtins.int + AUDIO_CHUNK_FIELD_NUMBER: _builtins.int + @_builtins.property + def init(self) -> Global___PlayStreamInit: ... + @_builtins.property + def audio_chunk(self) -> Global___PlayStreamChunk: ... + def __init__( + self, + *, + init: Global___PlayStreamInit | None = ..., + audio_chunk: Global___PlayStreamChunk | None = ..., + ) -> None: ... + _HasFieldArgType: _TypeAlias = _typing.Literal["audio_chunk", b"audio_chunk", "init", b"init", "payload", b"payload"] # noqa: Y015 + def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: ... + _ClearFieldArgType: _TypeAlias = _typing.Literal["audio_chunk", b"audio_chunk", "init", b"init", "payload", b"payload"] # noqa: Y015 + def ClearField(self, field_name: _ClearFieldArgType) -> None: ... + _WhichOneofReturnType_payload: _TypeAlias = _typing.Literal["init", "audio_chunk"] # noqa: Y015 + _WhichOneofArgType_payload: _TypeAlias = _typing.Literal["payload", b"payload"] # noqa: Y015 + def WhichOneof(self, oneof_group: _WhichOneofArgType_payload) -> _WhichOneofReturnType_payload | None: ... + +Global___PlayStreamRequest: _TypeAlias = PlayStreamRequest # noqa: Y015 + +@_typing.final +class PlayStreamChunk(_message.Message): + DESCRIPTOR: _descriptor.Descriptor + + AUDIO_DATA_FIELD_NUMBER: _builtins.int + audio_data: _builtins.bytes + def __init__( + self, + *, + audio_data: _builtins.bytes = ..., + ) -> None: ... + _ClearFieldArgType: _TypeAlias = _typing.Literal["audio_data", b"audio_data"] # noqa: Y015 + def ClearField(self, field_name: _ClearFieldArgType) -> None: ... - def __init__(self, *, name: _builtins.str=..., audio_data: _builtins.bytes=..., audio_info: _common_pb2.AudioInfo | None=..., extra: _struct_pb2.Struct | None=...) -> None: - ... - _HasFieldArgType: _TypeAlias = _typing.Literal['audio_info', b'audio_info', 'extra', b'extra'] +Global___PlayStreamChunk: _TypeAlias = PlayStreamChunk # noqa: Y015 - def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: - ... - _ClearFieldArgType: _TypeAlias = _typing.Literal['audio_data', b'audio_data', 'audio_info', b'audio_info', 'extra', b'extra', 'name', b'name'] +@_typing.final +class PlayStreamInit(_message.Message): + DESCRIPTOR: _descriptor.Descriptor - def ClearField(self, field_name: _ClearFieldArgType) -> None: - ... -Global___PlayRequest: _TypeAlias = PlayRequest + NAME_FIELD_NUMBER: _builtins.int + AUDIO_INFO_FIELD_NUMBER: _builtins.int + EXTRA_FIELD_NUMBER: _builtins.int + name: _builtins.str + @_builtins.property + def audio_info(self) -> _common_pb2.AudioInfo: ... + @_builtins.property + def extra(self) -> _struct_pb2.Struct: ... + def __init__( + self, + *, + name: _builtins.str = ..., + audio_info: _common_pb2.AudioInfo | None = ..., + extra: _struct_pb2.Struct | None = ..., + ) -> None: ... + _HasFieldArgType: _TypeAlias = _typing.Literal["audio_info", b"audio_info", "extra", b"extra"] # noqa: Y015 + def HasField(self, field_name: _HasFieldArgType) -> _builtins.bool: ... + _ClearFieldArgType: _TypeAlias = _typing.Literal["audio_info", b"audio_info", "extra", b"extra", "name", b"name"] # noqa: Y015 + def ClearField(self, field_name: _ClearFieldArgType) -> None: ... + +Global___PlayStreamInit: _TypeAlias = PlayStreamInit # noqa: Y015 @_typing.final class PlayResponse(_message.Message): DESCRIPTOR: _descriptor.Descriptor - def __init__(self) -> None: - ... -Global___PlayResponse: _TypeAlias = PlayResponse \ No newline at end of file + def __init__( + self, + ) -> None: ... + +Global___PlayResponse: _TypeAlias = PlayResponse # noqa: Y015 + +@_typing.final +class PlayStreamResponse(_message.Message): + DESCRIPTOR: _descriptor.Descriptor + + def __init__( + self, + ) -> None: ... + +Global___PlayStreamResponse: _TypeAlias = PlayStreamResponse # noqa: Y015 diff --git a/src/viam/proto/component/audioout/__init__.py b/src/viam/proto/component/audioout/__init__.py index 4f52daa91b..5a264fd963 100644 --- a/src/viam/proto/component/audioout/__init__.py +++ b/src/viam/proto/component/audioout/__init__.py @@ -4,7 +4,14 @@ """ from ....gen.component.audioout.v1.audioout_grpc import AudioOutServiceBase, AudioOutServiceStub, UnimplementedAudioOutServiceBase -from ....gen.component.audioout.v1.audioout_pb2 import PlayRequest, PlayResponse +from ....gen.component.audioout.v1.audioout_pb2 import ( + PlayRequest, + PlayResponse, + PlayStreamChunk, + PlayStreamInit, + PlayStreamRequest, + PlayStreamResponse, +) __all__ = [ "AudioOutServiceBase", @@ -12,4 +19,8 @@ "UnimplementedAudioOutServiceBase", "PlayRequest", "PlayResponse", + "PlayStreamChunk", + "PlayStreamInit", + "PlayStreamRequest", + "PlayStreamResponse", ] diff --git a/tests/mocks/components.py b/tests/mocks/components.py index 1281cc7ed9..ac8baf0ea6 100644 --- a/tests/mocks/components.py +++ b/tests/mocks/components.py @@ -188,6 +188,9 @@ def __init__(self, name: str, properties: AudioOut.Properties): self.geometries = GEOMETRIES self.timeout: Optional[float] = None self.extra: Optional[Dict[str, Any]] = None + self.play_stream_called = False + self.last_streamed_info: Optional[AudioInfo] = None + self.streamed_chunks: list[bytes] = [] async def play( self, @@ -202,6 +205,21 @@ async def play( self.last_audio_data = data self.last_audio_info = info + async def play_stream( + self, + info: AudioInfo, + chunks, + *, + extra: Optional[Dict[str, Any]] = None, + timeout: Optional[float] = None, + **kwargs, + ) -> None: + self.play_stream_called = True + self.last_streamed_info = info + self.streamed_chunks = [] + async for chunk in chunks: + self.streamed_chunks.append(chunk) + async def get_properties(self, *, extra: Optional[Dict[str, Any]] = None, timeout: Optional[float] = None, **kwargs): self.timeout = timeout return self.properties diff --git a/tests/test_audio_out.py b/tests/test_audio_out.py index 75f2742186..422f0cd212 100644 --- a/tests/test_audio_out.py +++ b/tests/test_audio_out.py @@ -11,7 +11,13 @@ GetStatusRequest, GetStatusResponse, ) -from viam.proto.component.audioout import AudioOutServiceStub, PlayRequest +from viam.proto.component.audioout import ( + AudioOutServiceStub, + PlayRequest, + PlayStreamChunk, + PlayStreamInit, + PlayStreamRequest, +) from viam.resource.manager import ResourceManager from viam.utils import dict_to_struct, struct_to_dict @@ -55,6 +61,33 @@ async def test_play_without_audio_info(self, audio_out: MockAudioOut): assert audio_out.last_audio_data == audio_data assert audio_out.last_audio_info is None + @pytest.mark.asyncio + async def test_play_stream(self, audio_out: MockAudioOut): + audio_info = AudioInfo(codec="pcm16", sample_rate_hz=22050, num_channels=1) + chunks = [b"chunk_one", b"chunk_two", b"chunk_three"] + + async def source(): + for c in chunks: + yield c + + await audio_out.play_stream(audio_info, source()) + assert audio_out.play_stream_called + assert audio_out.last_streamed_info == audio_info + assert audio_out.streamed_chunks == chunks + + @pytest.mark.asyncio + async def test_play_stream_no_chunks(self, audio_out: MockAudioOut): + audio_info = AudioInfo(codec="pcm16", sample_rate_hz=48000, num_channels=1) + + async def empty(): + if False: + yield b"" + + await audio_out.play_stream(audio_info, empty()) + assert audio_out.play_stream_called + assert audio_out.last_streamed_info == audio_info + assert audio_out.streamed_chunks == [] + @pytest.mark.asyncio async def test_get_properties(self, audio_out: MockAudioOut): properties = await audio_out.get_properties() @@ -119,6 +152,26 @@ async def test_play_without_audio_info(self, audio_out: MockAudioOut, service: A assert audio_out.last_audio_data == audio_data assert audio_out.last_audio_info is None + @pytest.mark.asyncio + async def test_play_stream(self, audio_out: MockAudioOut, service: AudioOutRPCService): + audio_info = AudioInfo(codec="pcm16", sample_rate_hz=22050, num_channels=1) + chunks = [b"a" * 4, b"b" * 4, b"c" * 4] + + async with ChannelFor([service]) as channel: + client = AudioOutServiceStub(channel) + async with client.PlayStream.open() as stream: + await stream.send_message( + PlayStreamRequest(init=PlayStreamInit(name=audio_out.name, audio_info=audio_info, extra=dict_to_struct({}))) + ) + for c in chunks: + await stream.send_message(PlayStreamRequest(audio_chunk=PlayStreamChunk(audio_data=c))) + await stream.end() + await stream.recv_message() + + assert audio_out.play_stream_called + assert audio_out.last_streamed_info == audio_info + assert audio_out.streamed_chunks == chunks + @pytest.mark.asyncio async def test_get_properties(self, audio_out: MockAudioOut, service: AudioOutRPCService): async with ChannelFor([service]) as channel: @@ -187,6 +240,39 @@ async def test_play_without_audio_info(self, audio_out: MockAudioOut, service: A assert audio_out.last_audio_data == audio_data assert audio_out.last_audio_info is None + @pytest.mark.asyncio + async def test_play_stream(self, audio_out: MockAudioOut, service: AudioOutRPCService): + async with ChannelFor([service]) as channel: + client = AudioOutClient(audio_out.name, channel) + audio_info = AudioInfo(codec="pcm16", sample_rate_hz=22050, num_channels=1) + chunks = [b"hello ", b"world", b"!"] + + async def source(): + for c in chunks: + yield c + + await client.play_stream(audio_info, source()) + + assert audio_out.play_stream_called + assert audio_out.last_streamed_info == audio_info + assert audio_out.streamed_chunks == chunks + + @pytest.mark.asyncio + async def test_play_stream_no_chunks(self, audio_out: MockAudioOut, service: AudioOutRPCService): + async with ChannelFor([service]) as channel: + client = AudioOutClient(audio_out.name, channel) + audio_info = AudioInfo(codec="pcm16", sample_rate_hz=44100, num_channels=2) + + async def empty(): + if False: + yield b"" + + await client.play_stream(audio_info, empty()) + + assert audio_out.play_stream_called + assert audio_out.last_streamed_info == audio_info + assert audio_out.streamed_chunks == [] + @pytest.mark.asyncio async def test_get_properties(self, audio_out: MockAudioOut, service: AudioOutRPCService): async with ChannelFor([service]) as channel: From f8fcdd35bf2250dbb36d21f550faa2d9bb16df7d Mon Sep 17 00:00:00 2001 From: oliviamiller <106617921+oliviamiller@users.noreply.github.com> Date: Thu, 14 May 2026 15:15:49 -0400 Subject: [PATCH 2/5] Delete , --- , | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 , diff --git a/, b/, deleted file mode 100644 index e69de29bb2..0000000000 From 7a8e69ca5270bcb5749a704a513cdf90f1352710 Mon Sep 17 00:00:00 2001 From: oliviamiller <106617921+oliviamiller@users.noreply.github.com> Date: Tue, 19 May 2026 11:37:57 -0400 Subject: [PATCH 3/5] fix --- src/viam/components/audio_out/service.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/viam/components/audio_out/service.py b/src/viam/components/audio_out/service.py index f840b661aa..7fa4abdc1c 100644 --- a/src/viam/components/audio_out/service.py +++ b/src/viam/components/audio_out/service.py @@ -49,8 +49,9 @@ async def PlayStream(self, stream: Stream[PlayStreamRequest, PlayStreamResponse] if not first.HasField("init"): raise GRPCError(Status.INVALID_ARGUMENT, "PlayStream: first message must be PlayStreamInit") init = first.init + if not init.HasField("audio_info"): + raise GRPCError(Status.INVALID_ARGUMENT, "PlayStream: audio_info is required on PlayStreamInit") audio_out = self.get_resource(init.name) - audio_info = init.audio_info if init.HasField("audio_info") else None async def chunks() -> AsyncIterator[bytes]: async for msg in stream: @@ -59,7 +60,7 @@ async def chunks() -> AsyncIterator[bytes]: timeout = stream.deadline.time_remaining() if stream.deadline else None await audio_out.play_stream( - audio_info, + init.audio_info, chunks(), extra=struct_to_dict(init.extra), timeout=timeout, From 3d96d75f3994d293d55731196d891a37f770dc14 Mon Sep 17 00:00:00 2001 From: oliviamiller <106617921+oliviamiller@users.noreply.github.com> Date: Tue, 19 May 2026 11:59:36 -0400 Subject: [PATCH 4/5] add example playstream --- examples/server/v1/components.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/examples/server/v1/components.py b/examples/server/v1/components.py index 73b93cdebe..a64896b399 100644 --- a/examples/server/v1/components.py +++ b/examples/server/v1/components.py @@ -13,7 +13,7 @@ from io import BytesIO from multiprocessing import Lock from pathlib import Path -from typing import Any, Dict, List, Mapping, Optional, Sequence, Tuple +from typing import Any, AsyncIterable, Dict, List, Mapping, Optional, Sequence, Tuple from google.protobuf.timestamp_pb2 import Timestamp from PIL import Image @@ -144,6 +144,28 @@ async def play( self.is_playing = False + async def play_stream( + self, + info: AudioInfo, + chunks: AsyncIterable[bytes], + *, + extra: Optional[Dict[str, Any]] = None, + timeout: Optional[float] = None, + **kwargs, + ) -> None: + """Play streamed audio chunks.""" + + self.is_playing = True + print( + f"Streaming audio: codec={info.codec}, sample_rate={info.sample_rate_hz}, channels={info.num_channels}" + ) + total = 0 + async for chunk in chunks: + total += len(chunk) + await asyncio.sleep(0) + print(f"Stream complete: {total} bytes") + self.is_playing = False + async def get_properties( self, *, extra: Optional[Dict[str, Any]] = None, timeout: Optional[float] = None, **kwargs ) -> AudioOut.Properties: From ed7583c80b36aa7ecb3462d788fea54d331d83e3 Mon Sep 17 00:00:00 2001 From: oliviamiller <106617921+oliviamiller@users.noreply.github.com> Date: Wed, 20 May 2026 14:41:56 -0400 Subject: [PATCH 5/5] fix --- .../component/audioout/v1/audioout_grpc.py | 10 ++-------- .../gen/component/audioout/v1/audioout_pb2.py | 20 ++----------------- .../component/audioout/v1/audioout_pb2.pyi | 13 ++++++++---- 3 files changed, 13 insertions(+), 30 deletions(-) diff --git a/src/viam/gen/component/audioout/v1/audioout_grpc.py b/src/viam/gen/component/audioout/v1/audioout_grpc.py index 702708d088..a6bbefc407 100644 --- a/src/viam/gen/component/audioout/v1/audioout_grpc.py +++ b/src/viam/gen/component/audioout/v1/audioout_grpc.py @@ -1,21 +1,15 @@ -# Generated by the Protocol Buffers compiler. DO NOT EDIT! -# source: component/audioout/v1/audioout.proto -# plugin: __main__ import abc import typing - import grpclib.const import grpclib.client import grpclib.exceptions if typing.TYPE_CHECKING: import grpclib.server - from .... import common import google.api.annotations_pb2 import google.protobuf.struct_pb2 from .... import component - class AudioOutServiceBase(abc.ABC): @abc.abstractmethod @@ -65,12 +59,12 @@ async def GetStatus(self, stream: 'grpclib.server.Stream[common.v1.common_pb2.Ge async def GetGeometries(self, stream: 'grpclib.server.Stream[common.v1.common_pb2.GetGeometriesRequest, common.v1.common_pb2.GetGeometriesResponse]') -> None: raise grpclib.exceptions.GRPCError(grpclib.const.Status.UNIMPLEMENTED) - class AudioOutServiceStub: def __init__(self, channel: grpclib.client.Channel) -> None: self.Play = grpclib.client.UnaryUnaryMethod(channel, '/viam.component.audioout.v1.AudioOutService/Play', component.audioout.v1.audioout_pb2.PlayRequest, component.audioout.v1.audioout_pb2.PlayResponse) + self.PlayStream = grpclib.client.StreamUnaryMethod(channel, '/viam.component.audioout.v1.AudioOutService/PlayStream', component.audioout.v1.audioout_pb2.PlayStreamRequest, component.audioout.v1.audioout_pb2.PlayStreamResponse) self.GetProperties = grpclib.client.UnaryUnaryMethod(channel, '/viam.component.audioout.v1.AudioOutService/GetProperties', common.v1.common_pb2.GetPropertiesRequest, common.v1.common_pb2.GetPropertiesResponse) self.DoCommand = grpclib.client.UnaryUnaryMethod(channel, '/viam.component.audioout.v1.AudioOutService/DoCommand', common.v1.common_pb2.DoCommandRequest, common.v1.common_pb2.DoCommandResponse) self.GetStatus = grpclib.client.UnaryUnaryMethod(channel, '/viam.component.audioout.v1.AudioOutService/GetStatus', common.v1.common_pb2.GetStatusRequest, common.v1.common_pb2.GetStatusResponse) - self.GetGeometries = grpclib.client.UnaryUnaryMethod(channel, '/viam.component.audioout.v1.AudioOutService/GetGeometries', common.v1.common_pb2.GetGeometriesRequest, common.v1.common_pb2.GetGeometriesResponse) + self.GetGeometries = grpclib.client.UnaryUnaryMethod(channel, '/viam.component.audioout.v1.AudioOutService/GetGeometries', common.v1.common_pb2.GetGeometriesRequest, common.v1.common_pb2.GetGeometriesResponse) \ No newline at end of file diff --git a/src/viam/gen/component/audioout/v1/audioout_pb2.py b/src/viam/gen/component/audioout/v1/audioout_pb2.py index 78e043b1f3..1a52f77c2d 100644 --- a/src/viam/gen/component/audioout/v1/audioout_pb2.py +++ b/src/viam/gen/component/audioout/v1/audioout_pb2.py @@ -1,27 +1,11 @@ -# -*- coding: utf-8 -*- -# Generated by the protocol buffer compiler. DO NOT EDIT! -# NO CHECKED-IN PROTOBUF GENCODE -# source: component/audioout/v1/audioout.proto -# Protobuf Python Version: 7.34.1 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool from google.protobuf import runtime_version as _runtime_version from google.protobuf import symbol_database as _symbol_database from google.protobuf.internal import builder as _builder -_runtime_version.ValidateProtobufRuntimeVersion( - _runtime_version.Domain.PUBLIC, - 6, - 33, - 5, - '', - 'component/audioout/v1/audioout.proto' -) -# @@protoc_insertion_point(imports) - +_runtime_version.ValidateProtobufRuntimeVersion(_runtime_version.Domain.PUBLIC, 6, 33, 5, '', 'component/audioout/v1/audioout.proto') _sym_db = _symbol_database.Default() - - from ....common.v1 import common_pb2 as common_dot_v1_dot_common__pb2 from google.api import annotations_pb2 as google_dot_api_dot_annotations__pb2 from google.protobuf import struct_pb2 as google_dot_protobuf_dot_struct__pb2 @@ -57,4 +41,4 @@ _globals['_PLAYSTREAMRESPONSE']._serialized_start = 713 _globals['_PLAYSTREAMRESPONSE']._serialized_end = 733 _globals['_AUDIOOUTSERVICE']._serialized_start = 736 - _globals['_AUDIOOUTSERVICE']._serialized_end = 1651 + _globals['_AUDIOOUTSERVICE']._serialized_end = 1651 \ No newline at end of file diff --git a/src/viam/gen/component/audioout/v1/audioout_pb2.pyi b/src/viam/gen/component/audioout/v1/audioout_pb2.pyi index 733567bb39..e5007b446f 100644 --- a/src/viam/gen/component/audioout/v1/audioout_pb2.pyi +++ b/src/viam/gen/component/audioout/v1/audioout_pb2.pyi @@ -2,7 +2,6 @@ @generated by mypy-protobuf. Do not edit manually! isort:skip_file """ - from common.v1 import common_pb2 as _common_pb2 from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message @@ -10,24 +9,22 @@ from google.protobuf import struct_pb2 as _struct_pb2 import builtins as _builtins import sys import typing as _typing - if sys.version_info >= (3, 10): from typing import TypeAlias as _TypeAlias else: from typing_extensions import TypeAlias as _TypeAlias - DESCRIPTOR: _descriptor.FileDescriptor @_typing.final class PlayRequest(_message.Message): DESCRIPTOR: _descriptor.Descriptor - NAME_FIELD_NUMBER: _builtins.int AUDIO_DATA_FIELD_NUMBER: _builtins.int AUDIO_INFO_FIELD_NUMBER: _builtins.int EXTRA_FIELD_NUMBER: _builtins.int name: _builtins.str audio_data: _builtins.bytes + @_builtins.property def audio_info(self) -> _common_pb2.AudioInfo: """Info describing the audio_data""" @@ -128,3 +125,11 @@ class PlayResponse(_message.Message): def __init__(self) -> None: ... Global___PlayResponse: _TypeAlias = PlayResponse + +@_typing.final +class PlayStreamResponse(_message.Message): + DESCRIPTOR: _descriptor.Descriptor + + def __init__(self) -> None: + ... +Global___PlayStreamResponse: _TypeAlias = PlayStreamResponse \ No newline at end of file