新增模块覆盖: 系统层 (14): system, security, print, opengl, renderscript, transition, test, service_notification, service_controls, service_quicksettings, service_wallpaper, service_autofill, service_dreams, service_vr 应用层 (13): app_admin, app_backup, app_job, app_usage, app_role, app_people, appwidget, companion, credentials, mtp, sip, telecom, speech 硬件媒体层 (15): hardware_display, hardware_fingerprint, hardware_usb, hardware_input, media_audiofx, media_browse, media_session, media_tv, media_midi, media_projection, uwb, se, view_autofill, view_textclassifier, view_translation 总计 94 个模块,75,342 行代码
370 lines
13 KiB
Python
370 lines
13 KiB
Python
"""
|
|
Android Speech API — SpeechRecognizer, RecognitionListener, RecognitionService, RecognizerIntent
|
|
方法签名完全对齐 Android SDK
|
|
"""
|
|
|
|
import sys
|
|
import threading
|
|
import time
|
|
from typing import Any, Dict, List, Optional, Set, Tuple, Callable
|
|
|
|
from .._core import Stub, AndroidOnlyError
|
|
from ..java.lang import RuntimeException
|
|
|
|
|
|
IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
|
|
|
|
__all__ = [
|
|
"SpeechRecognizer",
|
|
"RecognitionListener",
|
|
"RecognitionService",
|
|
"RecognizerIntent",
|
|
"RecognizerResultsIntent",
|
|
]
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# SpeechRecognizer
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class SpeechRecognizer(Stub):
|
|
"""SpeechRecognizer — 语音识别器 (桌面麦克风模拟)"""
|
|
|
|
RESULTS_RECOGNITION = "results_recognition"
|
|
CONFIDENCE_SCORES = "confidence_scores"
|
|
|
|
ERROR_NETWORK_TIMEOUT = 1
|
|
ERROR_NETWORK = 2
|
|
ERROR_AUDIO = 3
|
|
ERROR_SERVER = 4
|
|
ERROR_CLIENT = 5
|
|
ERROR_SPEECH_TIMEOUT = 6
|
|
ERROR_NO_MATCH = 7
|
|
ERROR_RECOGNIZER_BUSY = 8
|
|
ERROR_INSUFFICIENT_PERMISSIONS = 9
|
|
ERROR_TOO_MANY_REQUESTS = 10
|
|
ERROR_LANGUAGE_NOT_SUPPORTED = 11
|
|
ERROR_LANGUAGE_UNAVAILABLE = 12
|
|
ERROR_SERVER_DISCONNECTED = 13
|
|
|
|
def __init__(self, context: Any = None):
|
|
super().__init__()
|
|
self._context = context
|
|
self._listener: Optional["RecognitionListener"] = None
|
|
self._is_listening = False
|
|
self._destroyed = False
|
|
self._simulate_timer: Optional[threading.Timer] = None
|
|
|
|
@staticmethod
|
|
def createSpeechRecognizer(context: Any) -> "SpeechRecognizer":
|
|
"""创建语音识别器"""
|
|
return SpeechRecognizer(context)
|
|
|
|
@staticmethod
|
|
def isRecognitionAvailable(context: Any) -> bool:
|
|
"""检查语音识别是否可用"""
|
|
try:
|
|
import speech_recognition as sr
|
|
return True
|
|
except ImportError:
|
|
try:
|
|
import whisper # noqa: F401
|
|
return True
|
|
except ImportError:
|
|
pass
|
|
return False
|
|
|
|
def setRecognitionListener(self, listener: "RecognitionListener"):
|
|
"""设置识别监听器"""
|
|
self._listener = listener
|
|
|
|
def startListening(self, intent: Any):
|
|
"""开始语音识别"""
|
|
if self._destroyed:
|
|
return
|
|
|
|
self._is_listening = True
|
|
|
|
# 使用简单识别模拟
|
|
if self._listener:
|
|
self._listener.onReadyForSpeech(None)
|
|
self._listener.onBeginningOfSpeech()
|
|
|
|
# 模拟麦克风音量变化
|
|
for i in range(3):
|
|
self._listener.onRmsChanged(5.0 + i * 2.0)
|
|
time.sleep(0.05)
|
|
|
|
self._listener.onBufferReceived(bytearray(1024))
|
|
self._listener.onEndOfSpeech()
|
|
|
|
# 模拟识别结果
|
|
results = {self.RESULTS_RECOGNITION: ["hello world"], self.CONFIDENCE_SCORES: [0.95]}
|
|
self._listener.onResults(results)
|
|
|
|
def stopListening(self):
|
|
"""停止语音识别"""
|
|
self._is_listening = False
|
|
if self._simulate_timer:
|
|
self._simulate_timer.cancel()
|
|
self._simulate_timer = None
|
|
|
|
def cancel(self):
|
|
"""取消语音识别"""
|
|
self._is_listening = False
|
|
if self._simulate_timer:
|
|
self._simulate_timer.cancel()
|
|
self._simulate_timer = None
|
|
if self._listener:
|
|
self._listener.onError(self.ERROR_NO_MATCH)
|
|
|
|
def destroy(self):
|
|
"""销毁语音识别器"""
|
|
self._destroyed = True
|
|
self._is_listening = False
|
|
if self._simulate_timer:
|
|
self._simulate_timer.cancel()
|
|
self._simulate_timer = None
|
|
self._listener = None
|
|
|
|
def toString(self) -> str:
|
|
return f"SpeechRecognizer(listening={self._is_listening})"
|
|
|
|
def equals(self, other) -> bool:
|
|
return self is other
|
|
|
|
def hashCode(self) -> int:
|
|
return id(self) & 0x7FFFFFFF
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# RecognitionListener
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class RecognitionListener(Stub):
|
|
"""RecognitionListener — 语音识别监听器"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
def onReadyForSpeech(self, params: Any):
|
|
"""准备开始语音识别回调"""
|
|
pass
|
|
|
|
def onBeginningOfSpeech(self):
|
|
"""开始说话回调"""
|
|
pass
|
|
|
|
def onRmsChanged(self, rmsdB: float):
|
|
"""音量变化回调"""
|
|
pass
|
|
|
|
def onBufferReceived(self, buffer: bytearray):
|
|
"""接收音频缓冲区回调"""
|
|
pass
|
|
|
|
def onEndOfSpeech(self):
|
|
"""说话结束回调"""
|
|
pass
|
|
|
|
def onError(self, error: int):
|
|
"""错误回调"""
|
|
pass
|
|
|
|
def onResults(self, results: Dict[str, Any]):
|
|
"""识别结果回调"""
|
|
pass
|
|
|
|
def onPartialResults(self, partialResults: Dict[str, Any]):
|
|
"""部分识别结果回调"""
|
|
pass
|
|
|
|
def onSegmentResults(self, segmentResults: Dict[str, Any]):
|
|
"""分段结果回调"""
|
|
pass
|
|
|
|
def onEndOfSegmentedSession(self, sessionId: int):
|
|
"""分段会话结束回调"""
|
|
pass
|
|
|
|
def onLanguageDetection(self, language: str):
|
|
"""语言检测回调"""
|
|
pass
|
|
|
|
def onEvent(self, eventType: int, params: Any):
|
|
"""事件回调"""
|
|
pass
|
|
|
|
def toString(self) -> str:
|
|
return f"RecognitionListener@{hex(id(self))}"
|
|
|
|
def equals(self, other) -> bool:
|
|
return self is other
|
|
|
|
def hashCode(self) -> int:
|
|
return id(self) & 0x7FFFFFFF
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# RecognitionService
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class RecognitionService(Stub):
|
|
"""RecognitionService — 语音识别服务"""
|
|
|
|
SERVICE_INTERFACE = "android.speech.RecognitionService"
|
|
SERVICE_META_DATA = "android.speech"
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._callback: Optional["RecognitionService.Callback"] = None
|
|
|
|
def onStartListening(self, intent: Any, listener: "RecognitionService.Callback"):
|
|
"""开始监听回调"""
|
|
pass
|
|
|
|
def onCancel(self, listener: "RecognitionService.Callback"):
|
|
"""取消回调"""
|
|
pass
|
|
|
|
def onStopListening(self, listener: "RecognitionService.Callback"):
|
|
"""停止监听回调"""
|
|
pass
|
|
|
|
def onDestroy(self):
|
|
"""销毁回调"""
|
|
pass
|
|
|
|
def oneShotListening(self, intent: Any, listener: "RecognitionService.Callback"):
|
|
"""一次性监听"""
|
|
if listener:
|
|
listener.readyForSpeech(None)
|
|
listener.beginningOfSpeech()
|
|
listener.endOfSpeech()
|
|
results = {SpeechRecognizer.RESULTS_RECOGNITION: ["hello"]}
|
|
listener.results(results)
|
|
|
|
def getCurrentCallback(self) -> Optional["RecognitionService.Callback"]:
|
|
return self._callback
|
|
|
|
# ═══════════════════════════════════════════════════════════
|
|
# Callback
|
|
# ═══════════════════════════════════════════════════════════
|
|
|
|
class Callback(Stub):
|
|
"""RecognitionService.Callback — 识别服务回调"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
def results(self, results: Dict[str, Any]):
|
|
"""返回识别结果"""
|
|
pass
|
|
|
|
def partialResults(self, partialResults: Dict[str, Any]):
|
|
"""返回部分结果"""
|
|
pass
|
|
|
|
def error(self, error: int):
|
|
"""返回错误"""
|
|
pass
|
|
|
|
def beginningOfSpeech(self):
|
|
"""开始说话回调"""
|
|
pass
|
|
|
|
def bufferReceived(self, buffer: bytearray):
|
|
"""接收音频缓冲区回调"""
|
|
pass
|
|
|
|
def endOfSpeech(self):
|
|
"""说话结束回调"""
|
|
pass
|
|
|
|
def readyForSpeech(self, params: Any):
|
|
"""准备开始语音识别"""
|
|
pass
|
|
|
|
def rmsChanged(self, rmsdB: float):
|
|
"""音量变化回调"""
|
|
pass
|
|
|
|
def toString(self) -> str:
|
|
return f"RecognitionService.Callback@{hex(id(self))}"
|
|
|
|
def equals(self, other) -> bool:
|
|
return self is other
|
|
|
|
def hashCode(self) -> int:
|
|
return id(self) & 0x7FFFFFFF
|
|
|
|
def toString(self) -> str:
|
|
return f"RecognitionService@{hex(id(self))}"
|
|
|
|
def equals(self, other) -> bool:
|
|
return self is other
|
|
|
|
def hashCode(self) -> int:
|
|
return id(self) & 0x7FFFFFFF
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# RecognizerIntent
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class RecognizerIntent(Stub):
|
|
"""RecognizerIntent — 识别器 Intent 常量"""
|
|
|
|
ACTION_RECOGNIZE_SPEECH = "android.speech.action.RECOGNIZE_SPEECH"
|
|
ACTION_WEB_SEARCH = "android.speech.action.WEB_SEARCH"
|
|
ACTION_VOICE_SEARCH_HANDS_FREE = "android.speech.action.VOICE_SEARCH_HANDS_FREE"
|
|
ACTION_GET_LANGUAGE_DETAILS = "android.speech.action.GET_LANGUAGE_DETAILS"
|
|
|
|
EXTRA_LANGUAGE_MODEL = "android.speech.extra.LANGUAGE_MODEL"
|
|
EXTRA_LANGUAGE = "android.speech.extra.LANGUAGE"
|
|
EXTRA_MAX_RESULTS = "android.speech.extra.MAX_RESULTS"
|
|
EXTRA_PARTIAL_RESULTS = "android.speech.extra.PARTIAL_RESULTS"
|
|
EXTRA_CALLING_PACKAGE = "android.speech.extra.CALLING_PACKAGE"
|
|
EXTRA_PROMPT = "android.speech.extra.PROMPT"
|
|
EXTRA_SPEECH_INPUT_MINIMUM_LENGTH_MILLIS = "android.speech.extra.SPEECH_INPUT_MINIMUM_LENGTH_MILLIS"
|
|
EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS = "android.speech.extra.SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS"
|
|
EXTRA_SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS = "android.speech.extra.SPEECH_INPUT_POSSIBLY_COMPLETE_SILENCE_LENGTH_MILLIS"
|
|
EXTRA_CONFIDENCE_SCORES = "android.speech.extra.CONFIDENCE_SCORES"
|
|
EXTRA_RESULTS = "android.speech.extra.RESULTS"
|
|
EXTRA_SECURE = "android.speech.extra.SECURE"
|
|
EXTRA_SUPPORTED_LANGUAGES = "android.speech.extra.SUPPORTED_LANGUAGES"
|
|
EXTRA_LANGUAGE_PREFERENCE = "android.speech.extra.LANGUAGE_PREFERENCE"
|
|
EXTRA_ONLY_RETURN_LANGUAGE_PREFERENCE = "android.speech.extra.ONLY_RETURN_LANGUAGE_PREFERENCE"
|
|
EXTRA_LANGUAGE_DETAILS = "android.speech.extra.LANGUAGE_DETAILS"
|
|
|
|
LANGUAGE_MODEL_FREE_FORM = "free_form"
|
|
LANGUAGE_MODEL_WEB_SEARCH = "web_search"
|
|
|
|
RESULT_AUDIO_ERROR = 1
|
|
RESULT_CLIENT_ERROR = 2
|
|
RESULT_NETWORK_ERROR = 3
|
|
RESULT_SERVER_ERROR = 4
|
|
RESULT_NO_MATCH = 5
|
|
|
|
DETAIL_META_DATA = "android.speech.DETAIL_META_DATA"
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# RecognizerResultsIntent
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class RecognizerResultsIntent(Stub):
|
|
"""RecognizerResultsIntent — 识别结果 Intent 常量"""
|
|
|
|
ACTION_VOICE_SEARCH_RESULTS = "android.speech.action.VOICE_SEARCH_RESULTS"
|
|
EXTRA_VOICE_SEARCH_RESULT_STRINGS = "android.speech.extra.VOICE_SEARCH_RESULT_STRINGS"
|
|
EXTRA_VOICE_SEARCH_RESULT_URLS = "android.speech.extra.VOICE_SEARCH_RESULT_URLS"
|
|
EXTRA_VOICE_SEARCH_RESULT_HTML = "android.speech.extra.VOICE_SEARCH_RESULT_HTML"
|
|
EXTRA_VOICE_SEARCH_RESULT_HTML_BASE_URLS = "android.speech.extra.VOICE_SEARCH_RESULT_HTML_BASE_URLS"
|
|
URI_SCHEME_INLINE = "inline"
|
|
|
|
def __init__(self):
|
|
super().__init__() |