Files
Android-pyApi/android_pyapi/android/speech_tts.py
T
shuiyu1123 bfe27fdc08 feat: Android-pyApi v1.0 - 全面翻译 Android SDK API 为 Python
52 个模块覆盖 Android + Java + org.json 标准库
2026-06-24 11:16:16 +00:00

401 lines
13 KiB
Python

"""
Android Speech/TTS 组件 — TextToSpeech, Voice, SynthesisCallback 等
方法签名完全对齐 Android SDK
"""
import os
import sys
import locale as _locale
from typing import Any, Dict, List, Optional, Set, Tuple, Union
from .._core import (
Stub, AndroidOnlyError, android_context,
resolve_android_path, to_android_path,
_sdcard_root, _app_data_dir, _package_name,
)
# ═══════════════════════════════════════════════════════════════
# TextToSpeech.OnInitListener
# ═══════════════════════════════════════════════════════════════
class TextToSpeechOnInitListener(Stub):
"""OnInitListener — 初始化监听器"""
def onInit(self, status: int):
pass
# ═══════════════════════════════════════════════════════════════
# UtteranceProgressListener
# ═══════════════════════════════════════════════════════════════
class UtteranceProgressListener(Stub):
"""UtteranceProgressListener — 发音进度监听器"""
def onStart(self, utterance_id: str):
pass
def onDone(self, utterance_id: str):
pass
def onError(self, utterance_id: str, error_code: int = -1):
pass
def onStop(self, utterance_id: str, interrupted: bool = False):
pass
def onBeginSynthesis(self, utterance_id: str, sample_rate_in_hz: int,
audio_format: int, channel_count: int):
pass
def onRangeStart(self, utterance_id: str, start: int, end: int, frame: int):
pass
class TextToSpeechOnUtteranceCompletedListener(Stub):
"""OnUtteranceCompletedListener — 旧版发音完成监听器"""
def onUtteranceCompleted(self, utterance_id: str):
pass
# ═══════════════════════════════════════════════════════════════
# SynthesisRequest
# ═══════════════════════════════════════════════════════════════
class SynthesisRequest(Stub):
"""SynthesisRequest — 合成请求"""
def __init__(self):
super().__init__()
self._text: str = ""
self._speech_rate: float = 1.0
self._voice: Optional["Voice"] = None
self._calling_uid: int = 0
self._country: str = ""
self._language: str = ""
self._variant: str = ""
self._params: Dict[str, str] = {}
def getText(self) -> str:
return self._text
def getSpeechRate(self) -> float:
return self._speech_rate
def getVoice(self) -> Optional["Voice"]:
return self._voice
def getCallingUid(self) -> int:
return self._calling_uid
def getCountry(self) -> str:
return self._country
def getLanguage(self) -> str:
return self._language
def getVariant(self) -> str:
return self._variant
def getParams(self) -> Dict[str, str]:
return dict(self._params)
# ═══════════════════════════════════════════════════════════════
# SynthesisCallback
# ═══════════════════════════════════════════════════════════════
class SynthesisCallback(Stub):
"""SynthesisCallback — 合成回调"""
def start(self, sample_rate_in_hz: int, audio_format: int, channel_count: int) -> int:
return 0
def getMaxBufferSize(self) -> int:
return 8192
def getChannelCount(self) -> int:
return 1
def getAudioFormat(self) -> int:
return 1
def getSampleRate(self) -> int:
return 22050
def availableBuffer(self, buffer_size: int) -> int:
return buffer_size
def audioAvailable(self, audio: bytes) -> int:
return len(audio)
def done(self) -> int:
return 0
def error(self) -> int:
return -1
def hasStarted(self) -> bool:
return False
def hasFinished(self) -> bool:
return False
# ═══════════════════════════════════════════════════════════════
# Voice
# ═══════════════════════════════════════════════════════════════
class Voice(Stub):
"""Voice — 语音"""
QUALITY_DEFAULT = -1
QUALITY_VERY_LOW = 100
QUALITY_LOW = 200
QUALITY_NORMAL = 300
QUALITY_HIGH = 400
QUALITY_VERY_HIGH = 500
LATENCY_DEFAULT = -1
LATENCY_VERY_LOW = 100
LATENCY_LOW = 200
LATENCY_NORMAL = 300
LATENCY_HIGH = 400
LATENCY_VERY_HIGH = 500
def __init__(self, name: str = "", locale: Any = None,
quality: int = QUALITY_NORMAL, latency: int = LATENCY_NORMAL,
requires_network: bool = False,
features: Optional[List[str]] = None):
super().__init__()
self._name = name
self._locale = locale or _locale.getdefaultlocale()[0]
self._quality = quality
self._latency = latency
self._requires_network = requires_network
self._features = features or []
def getName(self) -> str:
return self._name
def getLocale(self) -> Any:
return self._locale
def getQuality(self) -> int:
return self._quality
def getLatency(self) -> int:
return self._latency
def isNetworkConnectionRequired(self) -> bool:
return self._requires_network
def getFeatures(self) -> List[str]:
return list(self._features)
def toString(self) -> str:
return f"Voice(name={self._name}, locale={self._locale})"
# ═══════════════════════════════════════════════════════════════
# TextToSpeech.Engine
# ═══════════════════════════════════════════════════════════════
class TextToSpeechEngine(Stub):
"""TextToSpeech.Engine — TTS 引擎元数据"""
ACTION_CHECK_TTS_DATA = "android.speech.tts.engine.CHECK_TTS_DATA"
ACTION_INSTALL_TTS_DATA = "android.speech.tts.engine.INSTALL_TTS_DATA"
ACTION_GET_SAMPLE_TEXT = "android.speech.tts.engine.GET_SAMPLE_TEXT"
KEY_PARAM_STREAM = "streamType"
KEY_PARAM_VOLUME = "volume"
KEY_PARAM_PAN = "pan"
KEY_PARAM_UTTERANCE_ID = "utteranceId"
KEY_PARAM_SESSION_ID = "sessionId"
KEY_FEATURE_NETWORK_SYNTHESIS = "networkSynthesis"
KEY_FEATURE_EMBEDDED_SYNTHESIS = "embeddedSynthesis"
KEY_FEATURE_NOT_INSTALLED = "notInstalled"
DEFAULT_STREAM = 3
DEFAULT_LANG = "eng"
DEFAULT_COUNTRY = "USA"
DEFAULT_VARIANT = ""
@staticmethod
def getLocaleLang(lang: str) -> str:
return lang[:3] if len(lang) >= 3 else lang
@staticmethod
def getLocaleCountry(lang: str) -> str:
return lang[3:6] if len(lang) >= 6 else ""
@staticmethod
def getLocaleVariant(lang: str) -> str:
return lang[6:] if len(lang) > 6 else ""
Engine = TextToSpeechEngine
# ═══════════════════════════════════════════════════════════════
# TextToSpeech
# ═══════════════════════════════════════════════════════════════
class TextToSpeech(Stub):
"""TextToSpeech — 文字转语音"""
SUCCESS = 0
ERROR = -1
STOPPED = -2
QUEUE_FLUSH = 0
QUEUE_ADD = 1
LANG_COUNTRY_AVAILABLE = 1
LANG_AVAILABLE = 0
LANG_COUNTRY_VAR_AVAILABLE = 2
LANG_MISSING_DATA = -1
LANG_NOT_SUPPORTED = -2
Engine = TextToSpeechEngine
def __init__(self, context: Any = None, listener: Optional[TextToSpeechOnInitListener] = None):
super().__init__()
self._context = context
self._listener = listener
self._utterance_progress_listener: Optional[UtteranceProgressListener] = None
self._language: str = ""
self._country: str = ""
self._pitch: float = 1.0
self._speech_rate: float = 1.0
self._voice: Optional[Voice] = None
self._voices: List[Voice] = [
Voice("en-us-1", "en_US", Voice.QUALITY_HIGH, Voice.LATENCY_NORMAL),
Voice("en-gb-1", "en_GB", Voice.QUALITY_NORMAL, Voice.LATENCY_NORMAL),
Voice("zh-cn-1", "zh_CN", Voice.QUALITY_HIGH, Voice.LATENCY_NORMAL),
]
self._engine_package: str = ""
self._initialized = False
if listener:
try:
listener.onInit(self.SUCCESS)
except Exception:
pass
self._initialized = True
def speak(self, text: str, queue_mode: int = QUEUE_FLUSH,
params: Any = None, utterance_id: str = "") -> int:
return self.SUCCESS
def stop(self) -> int:
return self.SUCCESS
def shutdown(self):
self._initialized = False
def setLanguage(self, language: str, country: str = "", variant: str = "") -> int:
self._language = language
self._country = country
return self.LANG_AVAILABLE
def getLanguage(self) -> Tuple[str, str, str]:
return (self._language, self._country, "")
def isLanguageAvailable(self, language: str, country: str = "",
variant: str = "") -> int:
return self.LANG_AVAILABLE
def setOnUtteranceProgressListener(self, listener: UtteranceProgressListener):
self._utterance_progress_listener = listener
def setOnUtteranceCompletedListener(self, listener: TextToSpeechOnUtteranceCompletedListener):
pass
def setPitch(self, pitch: float) -> int:
self._pitch = pitch
return self.SUCCESS
def setSpeechRate(self, rate: float) -> int:
self._speech_rate = rate
return self.SUCCESS
def getVoice(self) -> Optional[Voice]:
return self._voice
def setVoice(self, voice: Voice) -> int:
self._voice = voice
return self.SUCCESS
def getVoices(self) -> Set[Voice]:
return set(self._voices)
def addSpeech(self, text: str, filename: str) -> int:
return self.SUCCESS
def addEyes(self, text: str, filename: str) -> int:
return self.SUCCESS
def synthesizeToFile(self, text: str, params: Any, filename: str) -> int:
return self.SUCCESS
def setEngineByPackageName(self, package_name: str):
self._engine_package = package_name
def getDefaultEngine(self) -> Optional[str]:
return "com.android.tts"
def getEngines(self) -> List["EngineInfo"]:
return []
def getFeatures(self, locale: Any) -> Set[str]:
return set()
def areDefaultsEnforced(self) -> bool:
return False
def setQueueMode(self, queue_mode: int):
pass
def isSpeaking(self) -> bool:
return False
def toString(self) -> str:
return f"TextToSpeech(lang={self._language})"
# ═══════════════════════════════════════════════════════════════
# EngineInfo
# ═══════════════════════════════════════════════════════════════
class EngineInfo(Stub):
"""EngineInfo — 引擎信息"""
def __init__(self):
super().__init__()
self.name: str = ""
self.label: str = ""
self.icon: int = 0
self.priority: int = 0
self.system: bool = False
# ═══════════════════════════════════════════════════════════════
# __all__
# ═══════════════════════════════════════════════════════════════
__all__ = [
"TextToSpeech",
"TextToSpeechEngine",
"TextToSpeechOnInitListener",
"TextToSpeechOnUtteranceCompletedListener",
"SynthesisCallback",
"SynthesisRequest",
"Voice",
"UtteranceProgressListener",
"Engine",
"EngineInfo",
]