2025-08-21 14:05:27 +08:00
|
|
|
import grpc
|
|
|
|
|
from typing import Tuple
|
|
|
|
|
|
|
|
|
|
from .enums import CMVRErrorCode
|
|
|
|
|
from .models import SpeakerState
|
|
|
|
|
|
|
|
|
|
class SpeakerClient:
|
|
|
|
|
"""扬声器客户端"""
|
|
|
|
|
|
|
|
|
|
def __init__(self, device_id: str, stub):
|
|
|
|
|
self.device_id = device_id
|
|
|
|
|
self.stub = stub
|
2025-08-25 10:34:44 +08:00
|
|
|
self.generated = None # 推迟导入
|
|
|
|
|
|
|
|
|
|
def _import_generated(self):
|
|
|
|
|
"""推迟导入 generated"""
|
|
|
|
|
if self.generated is None:
|
|
|
|
|
try:
|
|
|
|
|
# 从正确的路径导入生成的模块
|
|
|
|
|
from generated.cmvr.api import common_pb2, speaker_command_pb2
|
|
|
|
|
self.generated = type('GeneratedModules', (), {
|
|
|
|
|
'common_pb2': common_pb2,
|
|
|
|
|
'speaker_command_pb2': speaker_command_pb2
|
|
|
|
|
})
|
|
|
|
|
except ImportError as e:
|
|
|
|
|
print(f"导入生成的模块失败: {e}")
|
|
|
|
|
print("请确保已生成 protobuf 代码")
|
|
|
|
|
raise
|
|
|
|
|
return self.generated
|
2025-08-21 14:05:27 +08:00
|
|
|
|
|
|
|
|
def _create_command_header(self):
|
|
|
|
|
"""创建命令头"""
|
2025-08-25 10:34:44 +08:00
|
|
|
generated = self._import_generated()
|
2025-08-21 14:05:27 +08:00
|
|
|
header = generated.common_pb2.CommandHeader.Request()
|
|
|
|
|
header.device_id = self.device_id
|
|
|
|
|
header.timestamp.GetCurrentTime()
|
|
|
|
|
return header
|
|
|
|
|
|
|
|
|
|
def get_status(self) -> Tuple[CMVRErrorCode, SpeakerState]:
|
|
|
|
|
"""获取扬声器状态"""
|
|
|
|
|
try:
|
2025-08-25 10:34:44 +08:00
|
|
|
generated = self._import_generated()
|
|
|
|
|
request = generated.speaker_command_pb2.GetSpeakerStateCommand.Request()
|
2025-08-21 14:05:27 +08:00
|
|
|
request.header.CopyFrom(self._create_command_header())
|
|
|
|
|
|
|
|
|
|
response = self.stub.GetStatus(request)
|
|
|
|
|
|
|
|
|
|
if not response.header.success:
|
|
|
|
|
return CMVRErrorCode.CMVR_RPC_FAILED, SpeakerState()
|
|
|
|
|
|
|
|
|
|
state = SpeakerState(
|
|
|
|
|
is_initialized=response.state.is_initialized,
|
|
|
|
|
is_running=response.state.is_running,
|
|
|
|
|
is_decoding=response.state.is_decoding,
|
|
|
|
|
is_paused=response.state.is_paused,
|
|
|
|
|
volume=response.state.volume
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
return CMVRErrorCode.CMVR_SUCCESS, state
|
|
|
|
|
|
|
|
|
|
except grpc.RpcError as e:
|
|
|
|
|
print(f"获取扬声器状态失败: {e}")
|
|
|
|
|
return CMVRErrorCode.CMVR_RPC_FAILED, SpeakerState()
|
|
|
|
|
|
|
|
|
|
def play_audio(self, audio_path: str) -> CMVRErrorCode:
|
|
|
|
|
"""播放音频"""
|
|
|
|
|
try:
|
2025-08-25 10:34:44 +08:00
|
|
|
generated = self._import_generated()
|
|
|
|
|
request = generated.speaker_command_pb2.PlayAudioCommand.Request()
|
2025-08-21 14:05:27 +08:00
|
|
|
request.header.CopyFrom(self._create_command_header())
|
|
|
|
|
request.audio_path = audio_path
|
|
|
|
|
|
|
|
|
|
response = self.stub.PlayAudio(request)
|
|
|
|
|
|
|
|
|
|
return CMVRErrorCode.CMVR_SUCCESS if response.header.success else CMVRErrorCode.CMVR_RPC_FAILED
|
|
|
|
|
|
|
|
|
|
except grpc.RpcError as e:
|
|
|
|
|
print(f"播放音频失败: {e}")
|
|
|
|
|
return CMVRErrorCode.CMVR_RPC_FAILED
|
|
|
|
|
|
|
|
|
|
def pause_audio(self) -> CMVRErrorCode:
|
|
|
|
|
"""暂停播放"""
|
|
|
|
|
try:
|
2025-08-25 10:34:44 +08:00
|
|
|
generated = self._import_generated()
|
|
|
|
|
request = generated.speaker_command_pb2.PauseSpeakerCommand.Request()
|
2025-08-21 14:05:27 +08:00
|
|
|
request.header.CopyFrom(self._create_command_header())
|
|
|
|
|
|
|
|
|
|
response = self.stub.PausePlayback(request)
|
|
|
|
|
|
|
|
|
|
return CMVRErrorCode.CMVR_SUCCESS if response.header.success else CMVRErrorCode.CMVR_RPC_FAILED
|
|
|
|
|
|
|
|
|
|
except grpc.RpcError as e:
|
|
|
|
|
print(f"暂停播放失败: {e}")
|
|
|
|
|
return CMVRErrorCode.CMVR_RPC_FAILED
|
|
|
|
|
|
|
|
|
|
def resume_audio(self) -> CMVRErrorCode:
|
|
|
|
|
"""继续播放"""
|
|
|
|
|
try:
|
2025-08-25 10:34:44 +08:00
|
|
|
generated = self._import_generated()
|
|
|
|
|
request = generated.speaker_command_pb2.ResumeSpeakerCommand.Request()
|
2025-08-21 14:05:27 +08:00
|
|
|
request.header.CopyFrom(self._create_command_header())
|
|
|
|
|
|
|
|
|
|
response = self.stub.ResumePlayback(request)
|
|
|
|
|
|
|
|
|
|
return CMVRErrorCode.CMVR_SUCCESS if response.header.success else CMVRErrorCode.CMVR_RPC_FAILED
|
|
|
|
|
|
|
|
|
|
except grpc.RpcError as e:
|
|
|
|
|
print(f"继续播放失败: {e}")
|
|
|
|
|
return CMVRErrorCode.CMVR_RPC_FAILED
|
|
|
|
|
|
|
|
|
|
def stop_audio(self) -> CMVRErrorCode:
|
|
|
|
|
"""停止播放"""
|
|
|
|
|
try:
|
2025-08-25 10:34:44 +08:00
|
|
|
generated = self._import_generated()
|
|
|
|
|
request = generated.speaker_command_pb2.StopSpeakerCommand.Request()
|
2025-08-21 14:05:27 +08:00
|
|
|
request.header.CopyFrom(self._create_command_header())
|
|
|
|
|
|
|
|
|
|
response = self.stub.StopPlayback(request)
|
|
|
|
|
|
|
|
|
|
return CMVRErrorCode.CMVR_SUCCESS if response.header.success else CMVRErrorCode.CMVR_RPC_FAILED
|
|
|
|
|
|
|
|
|
|
except grpc.RpcError as e:
|
|
|
|
|
print(f"停止播放失败: {e}")
|
|
|
|
|
return CMVRErrorCode.CMVR_RPC_FAILED
|
|
|
|
|
|
|
|
|
|
def set_volume(self, volume: float) -> CMVRErrorCode:
|
|
|
|
|
"""设置音量"""
|
|
|
|
|
try:
|
2025-08-25 10:34:44 +08:00
|
|
|
generated = self._import_generated()
|
|
|
|
|
request = generated.speaker_command_pb2.SetSpeakerVolumeCommand.Request()
|
2025-08-21 14:05:27 +08:00
|
|
|
request.header.CopyFrom(self._create_command_header())
|
|
|
|
|
request.volume = volume
|
|
|
|
|
|
|
|
|
|
response = self.stub.SetVolume(request)
|
|
|
|
|
|
|
|
|
|
return CMVRErrorCode.CMVR_SUCCESS if response.header.success else CMVRErrorCode.CMVR_RPC_FAILED
|
|
|
|
|
|
|
|
|
|
except grpc.RpcError as e:
|
|
|
|
|
print(f"设置音量失败: {e}")
|
|
|
|
|
return CMVRErrorCode.CMVR_RPC_FAILED
|
|
|
|
|
|
|
|
|
|
def get_volume(self) -> Tuple[CMVRErrorCode, float]:
|
|
|
|
|
"""获取音量"""
|
|
|
|
|
try:
|
2025-08-25 10:34:44 +08:00
|
|
|
generated = self._import_generated()
|
|
|
|
|
request = generated.speaker_command_pb2.GetSpeakerVolumeCommand.Request()
|
2025-08-21 14:05:27 +08:00
|
|
|
request.header.CopyFrom(self._create_command_header())
|
|
|
|
|
|
|
|
|
|
response = self.stub.GetVolume(request)
|
|
|
|
|
|
|
|
|
|
if not response.header.success:
|
|
|
|
|
return CMVRErrorCode.CMVR_RPC_FAILED, 0.0
|
|
|
|
|
|
|
|
|
|
return CMVRErrorCode.CMVR_SUCCESS, response.volume
|
|
|
|
|
|
|
|
|
|
except grpc.RpcError as e:
|
|
|
|
|
print(f"获取音量失败: {e}")
|
|
|
|
|
return CMVRErrorCode.CMVR_RPC_FAILED, 0.0
|