Files
Android-pyApi/android_pyapi/android/media_audio.py
T
shuiyu1123 a51854455b feat: 大规模扩充至212个模块/175K行代码 — 覆盖android/java/javax/org/dalvik全包
- android/ 167个模块 (app/content/os/view/widget/graphics/media/hardware/net/telephony/provider等)
- java/ 35个模块 (lang/io/util/net/nio/security/crypto/sql/beans/rmi/awt等)
- javax/ 4个模块 (net/crypto/security/sql)
- org/ 5个模块 (json/w3c_dom/xml_sax/xml_pull/apache_http)
- dalvik/ 1个模块 (system)
- ~3053个类/接口,方法签名完全对齐Android SDK
- 桌面跨平台运行 (Windows/macOS/Linux)
- 修复所有导入错误和Python关键字冲突
2026-06-24 14:15:56 +00:00

1538 lines
51 KiB
Python

"""
Android media 音频扩展组件 — AudioFormat, AudioTrack, AudioRecord, AudioDeviceInfo,
AudioRouting, AudioManager, AudioMix, AudioProfile, AudioProductStrategy 等
方法签名完全对齐 Android SDK
"""
from __future__ import annotations
import math
import time
from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
from .._core import Stub, AndroidOnlyError
from ..java.lang import RuntimeException
IllegalArgumentException = type("IllegalArgumentException", (RuntimeException,), {})
__all__ = [
"AudioFormat", "AudioAttributes", "AudioTrack", "AudioRecord",
"AudioDeviceInfo", "AudioDeviceCallback", "AudioRouting",
"AudioTimestamp", "AudioPresentation", "AudioPlaybackConfiguration",
"AudioRecordingConfiguration", "AudioManagerAudio", "AudioMixPort",
"AudioPort", "AudioPatch", "AudioGain", "AudioGainConfig",
"AudioMix", "AudioProfile", "AudioProductStrategy", "AudioVolumeGroup",
]
# ═══════════════════════════════════════════════════════════════
# AudioFormat
# ═══════════════════════════════════════════════════════════════
class AudioFormat(Stub):
"""AudioFormat — 音频格式"""
ENCODING_INVALID = 0
ENCODING_DEFAULT = 1
ENCODING_PCM_16BIT = 2
ENCODING_PCM_8BIT = 3
ENCODING_PCM_FLOAT = 4
ENCODING_AC3 = 5
ENCODING_E_AC3 = 6
ENCODING_DTS = 7
ENCODING_DTS_HD = 8
ENCODING_MP3 = 9
ENCODING_AAC_LC = 10
ENCODING_AAC_HE_V1 = 11
ENCODING_AAC_HE_V2 = 12
ENCODING_PCM_24BIT_PACKED = 13
ENCODING_PCM_32BIT = 14
ENCODING_PCM_16BIT_BUNDLED = 15
ENCODING_PCM_24BIT = 16
ENCODING_DOLBY_TRUEHD = 17
ENCODING_DOLBY_MAT = 18
ENCODING_IEC61937 = 19
ENCODING_OPUS = 20
ENCODING_AMRNB = 21
ENCODING_AMRWB = 22
ENCODING_FLAC = 23
ENCODING_MP2 = 24
ENCODING_AC4 = 25
ENCODING_AC3_PLUS = 26
ENCODING_E_AC3_JOC = 27
ENCODING_DOLBY_MAT_21 = 28
ENCODING_DSD = 29
ENCODING_PCM_8_24_BIT = 30
ENCODING_WMA = 31
ENCODING_WMA_PRO = 32
ENCODING_ALAC = 33
ENCODING_APE = 34
ENCODING_VORBIS = 35
CHANNEL_INVALID = 0
CHANNEL_OUT_FRONT_LEFT = 0x4
CHANNEL_OUT_FRONT_RIGHT = 0x8
CHANNEL_OUT_FRONT_CENTER = 0x10
CHANNEL_OUT_LOW_FREQUENCY = 0x20
CHANNEL_OUT_BACK_LEFT = 0x40
CHANNEL_OUT_BACK_RIGHT = 0x80
CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x100
CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x200
CHANNEL_OUT_BACK_CENTER = 0x400
CHANNEL_OUT_SIDE_LEFT = 0x800
CHANNEL_OUT_SIDE_RIGHT = 0x1000
CHANNEL_OUT_TOP_CENTER = 0x2000
CHANNEL_OUT_TOP_FRONT_LEFT = 0x4000
CHANNEL_OUT_TOP_FRONT_RIGHT = 0x8000
CHANNEL_OUT_TOP_FRONT_CENTER = 0x10000
CHANNEL_OUT_TOP_BACK_LEFT = 0x20000
CHANNEL_OUT_TOP_BACK_RIGHT = 0x40000
CHANNEL_OUT_TOP_BACK_CENTER = 0x80000
CHANNEL_OUT_MONO = 0x4
CHANNEL_OUT_STEREO = 0xC
CHANNEL_OUT_QUAD = 0xCC
CHANNEL_OUT_SURROUND = 0x41C
CHANNEL_OUT_5POINT1 = 0xFC
CHANNEL_OUT_7POINT1 = 0x4FC
CHANNEL_OUT_5POINT1_SIDE = 0x8FC
CHANNEL_OUT_7POINT1_SURROUND = 0x18FC
CHANNEL_IN_LEFT = 0x4
CHANNEL_IN_RIGHT = 0x8
CHANNEL_IN_FRONT = 0x10
CHANNEL_IN_BACK = 0x40
CHANNEL_IN_LEFT_PROCESSED = 0x20
CHANNEL_IN_RIGHT_PROCESSED = 0x80
CHANNEL_IN_FRONT_PROCESSED = 0x100
CHANNEL_IN_BACK_PROCESSED = 0x200
CHANNEL_IN_PRESSURE = 0x400
CHANNEL_IN_X_AXIS = 0x800
CHANNEL_IN_Y_AXIS = 0x1000
CHANNEL_IN_Z_AXIS = 0x2000
CHANNEL_IN_VOICE_UPLINK = 0x4000
CHANNEL_IN_VOICE_DNLINK = 0x8000
CHANNEL_IN_MONO = 0x10
CHANNEL_IN_STEREO = 0xC
CHANNEL_IN_DEFAULT = 0x1
SAMPLE_RATE_UNSPECIFIED = 0
class Builder(Stub):
"""AudioFormat.Builder — 音频格式构建器"""
def __init__(self):
super().__init__()
self._encoding = AudioFormat.ENCODING_DEFAULT
self._sample_rate = AudioFormat.SAMPLE_RATE_UNSPECIFIED
self._channel_mask = AudioFormat.CHANNEL_INVALID
self._channel_index_mask = 0
def setEncoding(self, encoding: int) -> "AudioFormat.Builder":
self._encoding = encoding
return self
def setSampleRate(self, sampleRate: int) -> "AudioFormat.Builder":
self._sample_rate = sampleRate
return self
def setChannelMask(self, channelMask: int) -> "AudioFormat.Builder":
self._channel_mask = channelMask
return self
def setChannelIndexMask(self, channelIndexMask: int) -> "AudioFormat.Builder":
self._channel_index_mask = channelIndexMask
return self
def build(self) -> "AudioFormat":
fmt = AudioFormat()
fmt._encoding = self._encoding
fmt._sample_rate = self._sample_rate
fmt._channel_mask = self._channel_mask
fmt._channel_index_mask = self._channel_index_mask
return fmt
def __init__(self):
super().__init__()
self._encoding = AudioFormat.ENCODING_DEFAULT
self._sample_rate = AudioFormat.SAMPLE_RATE_UNSPECIFIED
self._channel_mask = AudioFormat.CHANNEL_INVALID
self._channel_index_mask = 0
def getEncoding(self) -> int:
return self._encoding
def getSampleRate(self) -> int:
return self._sample_rate
def getChannelMask(self) -> int:
return self._channel_mask
def getChannelIndexMask(self) -> int:
return self._channel_index_mask
def getChannelCount(self) -> int:
mask = self._channel_mask
if mask == AudioFormat.CHANNEL_INVALID:
return 0
return bin(mask).count("1")
def toString(self) -> str:
return (f"AudioFormat(encoding={self._encoding}, "
f"sampleRate={self._sample_rate}, channels={self.getChannelCount()})")
def equals(self, other: Any) -> bool:
if not isinstance(other, AudioFormat):
return False
return (self._encoding == other._encoding and
self._sample_rate == other._sample_rate and
self._channel_mask == other._channel_mask)
def hashCode(self) -> int:
return hash((self._encoding, self._sample_rate, self._channel_mask)) & 0x7FFFFFFF
# ═══════════════════════════════════════════════════════════════
# AudioAttributes (扩展)
# ═══════════════════════════════════════════════════════════════
class AudioAttributes(Stub):
"""AudioAttributes — 音频属性 (完整版)"""
CONTENT_TYPE_UNKNOWN = 0
CONTENT_TYPE_SPEECH = 1
CONTENT_TYPE_MUSIC = 2
CONTENT_TYPE_MOVIE = 3
CONTENT_TYPE_SONIFICATION = 4
USAGE_UNKNOWN = 0
USAGE_MEDIA = 1
USAGE_VOICE_COMMUNICATION = 2
USAGE_VOICE_COMMUNICATION_SIGNALLING = 3
USAGE_ALARM = 4
USAGE_NOTIFICATION = 5
USAGE_NOTIFICATION_RINGTONE = 6
USAGE_NOTIFICATION_COMMUNICATION_REQUEST = 7
USAGE_NOTIFICATION_COMMUNICATION_INSTANT = 8
USAGE_NOTIFICATION_COMMUNICATION_DELAYED = 9
USAGE_NOTIFICATION_EVENT = 10
USAGE_ASSISTANCE_ACCESSIBILITY = 11
USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12
USAGE_ASSISTANCE_SONIFICATION = 13
USAGE_GAME = 14
USAGE_VIRTUAL_SOURCE = 15
USAGE_ASSISTANT = 16
USAGE_CALL_ASSISTANT = 17
USAGE_EMERGENCY = 18
USAGE_SAFETY = 19
USAGE_VEHICLE_STATUS = 20
USAGE_ANNOUNCEMENT = 21
FLAG_AUDIBILITY_ENFORCED = 1
FLAG_SECURE = 2
FLAG_SCO = 4
FLAG_BEACON = 8
FLAG_BYPASS_INTERRUPTION_POLICY = 16
FLAG_BYPASS_MUTE = 32
FLAG_LOW_LATENCY = 64
FLAG_DEEP_BUFFER = 128
FLAG_NO_EXPANDABLE = 256
FLAG_HW_AV_SYNC = 512
FLAG_BYPASS_INTERRUPTION_POLICY_FLAG = 1024
ALLOW_CAPTURE_BY_ALL = 0
ALLOW_CAPTURE_BY_SYSTEM = 1
ALLOW_CAPTURE_BY_NONE = 2
class Builder(Stub):
"""AudioAttributes.Builder — 音频属性构建器"""
def __init__(self):
super().__init__()
self._content_type = AudioAttributes.CONTENT_TYPE_UNKNOWN
self._usage = AudioAttributes.USAGE_UNKNOWN
self._flags = 0
self._legacy_stream_type = -1
self._allowed_capture_policy = AudioAttributes.ALLOW_CAPTURE_BY_ALL
self._spatial_behavior = 0
def setContentType(self, contentType: int) -> "AudioAttributes.Builder":
self._content_type = contentType
return self
def setUsage(self, usage: int) -> "AudioAttributes.Builder":
self._usage = usage
return self
def setFlags(self, flags: int) -> "AudioAttributes.Builder":
self._flags = flags
return self
def setLegacyStreamType(self, streamType: int) -> "AudioAttributes.Builder":
self._legacy_stream_type = streamType
return self
def setAllowedCapturePolicy(self, capturePolicy: int) -> "AudioAttributes.Builder":
self._allowed_capture_policy = capturePolicy
return self
def setSpatialBehavior(self, spatialBehavior: int) -> "AudioAttributes.Builder":
self._spatial_behavior = spatialBehavior
return self
def build(self) -> "AudioAttributes":
attrs = AudioAttributes()
attrs._content_type = self._content_type
attrs._usage = self._usage
attrs._flags = self._flags
attrs._legacy_stream_type = self._legacy_stream_type
attrs._allowed_capture_policy = self._allowed_capture_policy
attrs._spatial_behavior = self._spatial_behavior
return attrs
def __init__(self):
super().__init__()
self._content_type = AudioAttributes.CONTENT_TYPE_UNKNOWN
self._usage = AudioAttributes.USAGE_UNKNOWN
self._flags = 0
self._legacy_stream_type = -1
self._allowed_capture_policy = AudioAttributes.ALLOW_CAPTURE_BY_ALL
self._spatial_behavior = 0
def getContentType(self) -> int:
return self._content_type
def getUsage(self) -> int:
return self._usage
def getFlags(self) -> int:
return self._flags
def getAllowedCapturePolicy(self) -> int:
return self._allowed_capture_policy
def getSpatialBehavior(self) -> int:
return self._spatial_behavior
def getVolumeControlStream(self) -> int:
if self._usage in (AudioAttributes.USAGE_VOICE_COMMUNICATION,
AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING):
return 0
if self._usage == AudioAttributes.USAGE_ALARM:
return 4
if self._usage in (AudioAttributes.USAGE_NOTIFICATION,
AudioAttributes.USAGE_NOTIFICATION_RINGTONE,
AudioAttributes.USAGE_NOTIFICATION_EVENT):
return 5
if self._usage in (AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY,
AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
AudioAttributes.USAGE_ASSISTANCE_SONIFICATION):
return 3
return 3
toString = lambda self: f"AudioAttributes(usage={self._usage}, contentType={self._content_type})"
equals = lambda self, other: self is other if not isinstance(other, AudioAttributes) else (self._usage == other._usage and self._content_type == other._content_type)
hashCode = lambda self: hash((self._usage, self._content_type)) & 0x7FFFFFFF
# ═══════════════════════════════════════════════════════════════
# AudioTimestamp
# ═══════════════════════════════════════════════════════════════
class AudioTimestamp(Stub):
"""AudioTimestamp — 音频时间戳"""
TIMEBASE_MONOTONIC = 0
TIMEBASE_BOOTTIME = 1
def __init__(self):
super().__init__()
self.framePosition: int = 0
self.nanoTime: int = 0
def toString(self) -> str:
return f"AudioTimestamp(frame={self.framePosition}, nanoTime={self.nanoTime})"
def equals(self, other: Any) -> bool:
if not isinstance(other, AudioTimestamp):
return False
return self.framePosition == other.framePosition and self.nanoTime == other.nanoTime
def hashCode(self) -> int:
return hash((self.framePosition, self.nanoTime)) & 0x7FFFFFFF
# ═══════════════════════════════════════════════════════════════
# AudioPresentation
# ═══════════════════════════════════════════════════════════════
class AudioPresentation(Stub):
"""AudioPresentation — 音频呈现"""
CONTENT_TYPE_UNKNOWN = 0
CONTENT_TYPE_DIALOG = 1
CONTENT_TYPE_MUSIC = 2
CONTENT_TYPE_VOICEOVER = 3
CONTENT_TYPE_NARRATION = 4
CONTENT_TYPE_VISUALLY_IMPAIRED = 5
CONTENT_TYPE_HEARING_IMPAIRED = 6
CONTENT_TYPE_COMMENTARY = 7
CONTENT_TYPE_SPOKEN_SUBTITLE = 8
CONTENT_TYPE_EMERGENCY = 9
CONTENT_TYPE_MAIN = 10
CONTENT_TYPE_SUPPLEMENTARY = 11
MASTERED_FOR_STEREO = 0
MASTERED_FOR_SURROUND = 1
MASTERED_FOR_3D = 2
MASTERED_FOR_HEADPHONE = 3
def __init__(self, presentationId: int = 0, programId: int = 0,
locale: str = "", contentType: int = CONTENT_TYPE_UNKNOWN,
masteredFor: int = MASTERED_FOR_STEREO,
labels: Dict[str, str] = None):
super().__init__()
self._presentation_id = presentationId
self._program_id = programId
self._locale = locale
self._content_type = contentType
self._mastered_for = masteredFor
self._labels = labels or {}
def getPresentationId(self) -> int:
return self._presentation_id
def getProgramId(self) -> int:
return self._program_id
def getLocale(self) -> str:
return self._locale
def getContentType(self) -> int:
return self._content_type
def getMasteredFor(self) -> int:
return self._mastered_for
def getLabels(self) -> Dict[str, str]:
return dict(self._labels)
def toString(self) -> str:
return f"AudioPresentation(id={self._presentation_id}, locale={self._locale})"
def equals(self, other: Any) -> bool:
if not isinstance(other, AudioPresentation):
return False
return self._presentation_id == other._presentation_id
def hashCode(self) -> int:
return self._presentation_id & 0x7FFFFFFF
# ═══════════════════════════════════════════════════════════════
# AudioTrack
# ═══════════════════════════════════════════════════════════════
class AudioTrack(Stub):
"""AudioTrack — 音频回放轨道"""
MODE_STATIC = 0
MODE_STREAM = 1
STATE_UNINITIALIZED = 0
STATE_INITIALIZED = 1
STATE_NO_STATIC_DATA = 2
WRITE_BLOCKING = 0
SUCCESS = 0
ERROR = -1
ERROR_BAD_VALUE = -2
ERROR_INVALID_OPERATION = -3
ERROR_DEAD_OBJECT = -6
ERROR_WOULD_BLOCK = -7
PERFORMANCE_MODE_NONE = 0
PERFORMANCE_MODE_LOW_LATENCY = 1
PERFORMANCE_MODE_POWER_SAVING = 2
class Builder(Stub):
"""AudioTrack.Builder — 回放轨道构建器"""
def __init__(self):
super().__init__()
self._audio_format = None
self._audio_attributes = None
self._buffer_size = 0
self._session_id = 0
self._transfer_mode = AudioTrack.MODE_STREAM
self._performance_mode = AudioTrack.PERFORMANCE_MODE_NONE
self._context = None
def setAudioFormat(self, format_: AudioFormat) -> "AudioTrack.Builder":
self._audio_format = format_
return self
def setAudioAttributes(self, attributes: AudioAttributes) -> "AudioTrack.Builder":
self._audio_attributes = attributes
return self
def setBufferSizeInBytes(self, bufferSize: int) -> "AudioTrack.Builder":
self._buffer_size = bufferSize
return self
def setSessionId(self, sessionId: int) -> "AudioTrack.Builder":
self._session_id = sessionId
return self
def setTransferMode(self, mode: int) -> "AudioTrack.Builder":
self._transfer_mode = mode
return self
def setPerformanceMode(self, mode: int) -> "AudioTrack.Builder":
self._performance_mode = mode
return self
def build(self) -> "AudioTrack":
return AudioTrack(
format_=self._audio_format,
attributes=self._audio_attributes,
bufferSize=self._buffer_size,
sessionId=self._session_id,
mode=self._transfer_mode,
performanceMode=self._performance_mode,
)
def __init__(self, format_: Any = None, attributes: Any = None,
bufferSize: int = 0, sessionId: int = 0,
mode: int = MODE_STREAM, performanceMode: int = PERFORMANCE_MODE_NONE,
sampleRate: int = 44100, channelConfig: int = AudioFormat.CHANNEL_OUT_STEREO,
audioFormat: int = AudioFormat.ENCODING_PCM_16BIT):
super().__init__()
self._state = AudioTrack.STATE_INITIALIZED
self._sample_rate = sampleRate
self._channel_config = channelConfig
self._audio_format = audioFormat
self._buffer_size = bufferSize if bufferSize > 0 else 4096
self._mode = mode
self._session_id = sessionId
self._performance_mode = performanceMode
self._playback_rate = 1.0
self._volume = 1.0
self._position = 0
self._is_playing = False
self._audio_attributes = attributes
self._format = format_
self._timestamp = AudioTimestamp()
def play(self):
self._is_playing = True
def stop(self):
self._is_playing = False
def pause(self):
self._is_playing = False
def flush(self):
self._position = 0
def release(self):
self._state = AudioTrack.STATE_UNINITIALIZED
self._is_playing = False
def write(self, audioData: Any, offsetInBytes: int = 0, sizeInBytes: int = 0) -> int:
if self._state != AudioTrack.STATE_INITIALIZED:
return AudioTrack.ERROR_INVALID_OPERATION
if isinstance(audioData, (bytes, bytearray)):
written = sizeInBytes if sizeInBytes > 0 else len(audioData)
self._position += written
return written
if hasattr(audioData, 'nbytes'):
written = sizeInBytes or audioData.nbytes
self._position += written
return written
return AudioTrack.ERROR_BAD_VALUE
def getMinBufferSize(sampleRateInHz: int, channelConfig: int, audioFormat: int) -> int:
return 4096
def getNativeOutputSampleRate(streamType: int) -> int:
return 44100
def getSampleRate(self) -> int:
return self._sample_rate
def getPlaybackRate(self) -> float:
return self._playback_rate
def setPlaybackRate(self, rate: float):
self._playback_rate = rate
def getVolume(self) -> float:
return self._volume
def setVolume(self, volume: float):
self._volume = max(0.0, min(1.0, volume))
def getAudioFormat(self) -> int:
return self._audio_format
def getChannelConfiguration(self) -> int:
return self._channel_config
def getChannelCount(self) -> int:
return bin(self._channel_config).count("1")
def getState(self) -> int:
return self._state
def getPlayState(self) -> int:
return 3 if self._is_playing else 2
def getBufferSizeInFrames(self) -> int:
return self._buffer_size // 4
def getTimestamp(self, outTimestamp: AudioTimestamp) -> int:
base_time = time.time_ns()
outTimestamp.nanoTime = base_time
outTimestamp.framePosition = self._position
return AudioTrack.SUCCESS
def getSessionId(self) -> int:
return self._session_id
def getPerformanceMode(self) -> int:
return self._performance_mode
def setPreferredDevice(self, deviceInfo: Any) -> bool:
return True
def getPreferredDevice(self) -> Optional[Any]:
return None
def toString(self) -> str:
return (f"AudioTrack(sampleRate={self._sample_rate}, "
f"playing={self._is_playing}, state={self._state})")
def equals(self, other: Any) -> bool:
return self is other
def hashCode(self) -> int:
return id(self) & 0x7FFFFFFF
# ═══════════════════════════════════════════════════════════════
# AudioRecord
# ═══════════════════════════════════════════════════════════════
class AudioRecord(Stub):
"""AudioRecord — 音频录制"""
STATE_UNINITIALIZED = 0
STATE_INITIALIZED = 1
SUCCESS = 0
ERROR = -1
ERROR_BAD_VALUE = -2
ERROR_INVALID_OPERATION = -3
ERROR_DEAD_OBJECT = -6
READ_BLOCKING = 0
READ_NON_BLOCKING = 1
class Builder(Stub):
"""AudioRecord.Builder — 录制构建器"""
def __init__(self):
super().__init__()
self._audio_format = None
self._audio_attributes = None
self._buffer_size = 0
self._session_id = 0
self._context = None
def setAudioFormat(self, format_: AudioFormat) -> "AudioRecord.Builder":
self._audio_format = format_
return self
def setAudioAttributes(self, attributes: AudioAttributes) -> "AudioRecord.Builder":
self._audio_attributes = attributes
return self
def setBufferSizeInBytes(self, bufferSize: int) -> "AudioRecord.Builder":
self._buffer_size = bufferSize
return self
def setSessionId(self, sessionId: int) -> "AudioRecord.Builder":
self._session_id = sessionId
return self
def build(self) -> "AudioRecord":
return AudioRecord(
format_=self._audio_format,
attributes=self._audio_attributes,
bufferSize=self._buffer_size,
sessionId=self._session_id,
)
def __init__(self, format_: Any = None, attributes: Any = None,
bufferSize: int = 0, sessionId: int = 0,
sampleRate: int = 44100, channelConfig: int = AudioFormat.CHANNEL_IN_MONO,
audioFormat: int = AudioFormat.ENCODING_PCM_16BIT):
super().__init__()
self._state = AudioRecord.STATE_INITIALIZED
self._sample_rate = sampleRate
self._channel_config = channelConfig
self._audio_format = audioFormat
self._buffer_size = bufferSize if bufferSize > 0 else 4096
self._session_id = sessionId
self._is_recording = False
self._position = 0
self._format = format_
self._audio_attributes = attributes
def startRecording(self):
self._is_recording = True
def stop(self):
self._is_recording = False
def release(self):
self._state = AudioRecord.STATE_UNINITIALIZED
self._is_recording = False
def read(self, audioData: Any, offsetInBytes: int = 0, sizeInBytes: int = 0) -> int:
if not self._is_recording:
return AudioRecord.ERROR_INVALID_OPERATION
return sizeInBytes if sizeInBytes > 0 else 0
def getMinBufferSize(sampleRateInHz: int, channelConfig: int, audioFormat: int) -> int:
return 4096
def getSampleRate(self) -> int:
return self._sample_rate
def getAudioFormat(self) -> int:
return self._audio_format
def getChannelConfiguration(self) -> int:
return self._channel_config
def getChannelCount(self) -> int:
return bin(self._channel_config).count("1")
def getState(self) -> int:
return self._state
def getRecordingState(self) -> int:
return 3 if self._is_recording else 2
def getBufferSizeInFrames(self) -> int:
return self._buffer_size // 4
def getSessionId(self) -> int:
return self._session_id
def setPreferredDevice(self, deviceInfo: Any) -> bool:
return True
def getPreferredDevice(self) -> Optional[Any]:
return None
def toString(self) -> str:
return f"AudioRecord(sampleRate={self._sample_rate}, recording={self._is_recording})"
def equals(self, other: Any) -> bool:
return self is other
def hashCode(self) -> int:
return id(self) & 0x7FFFFFFF
# ═══════════════════════════════════════════════════════════════
# AudioDeviceInfo
# ═══════════════════════════════════════════════════════════════
class AudioDeviceInfo(Stub):
"""AudioDeviceInfo — 音频设备信息"""
TYPE_UNKNOWN = 0
TYPE_BUILTIN_EARPIECE = 1
TYPE_BUILTIN_SPEAKER = 2
TYPE_WIRED_HEADSET = 3
TYPE_WIRED_HEADPHONES = 4
TYPE_LINE_ANALOG = 5
TYPE_LINE_DIGITAL = 6
TYPE_BLUETOOTH_SCO = 7
TYPE_BLUETOOTH_A2DP = 8
TYPE_HDMI = 9
TYPE_HDMI_ARC = 10
TYPE_USB_DEVICE = 11
TYPE_USB_ACCESSORY = 12
TYPE_DOCK = 13
TYPE_FM = 14
TYPE_BUILTIN_MIC = 15
TYPE_FM_TUNER = 16
TYPE_TV_TUNER = 17
TYPE_TELEPHONY = 18
TYPE_AUX_LINE = 19
TYPE_IP = 20
TYPE_BUS = 21
TYPE_USB_HEADSET = 22
TYPE_HEARING_AID = 23
TYPE_BUILTIN_SPEAKER_SAFE = 24
TYPE_REMOTE_SUBMIX = 25
TYPE_BLE_HEADSET = 26
TYPE_BLE_SPEAKER = 27
TYPE_BLE_BROADCAST = 28
def __init__(self, id: int = 0, type_: int = TYPE_UNKNOWN,
productName: str = "", address: str = "",
isSource: bool = False, isSink: bool = False,
sampleRates: List[int] = None,
channelMasks: List[int] = None,
encodings: List[int] = None):
super().__init__()
self._id = id
self._type = type_
self._product_name = productName
self._address = address
self._is_source = isSource
self._is_sink = isSink
self._sample_rates = sampleRates or [44100, 48000]
self._channel_masks = channelMasks or [AudioFormat.CHANNEL_OUT_STEREO]
self._encodings = encodings or [AudioFormat.ENCODING_PCM_16BIT]
def getId(self) -> int:
return self._id
def getType(self) -> int:
return self._type
def getProductName(self) -> Any:
return self._product_name
def getAddress(self) -> str:
return self._address
def isSource(self) -> bool:
return self._is_source
def isSink(self) -> bool:
return self._is_sink
def getSampleRates(self) -> List[int]:
return list(self._sample_rates)
def getChannelMasks(self) -> List[int]:
return list(self._channel_masks)
def getEncodings(self) -> List[int]:
return list(self._encodings)
def getChannelCounts(self) -> List[int]:
return [bin(m).count("1") for m in self._channel_masks]
def toString(self) -> str:
type_names = {
1: "BUILTIN_EARPIECE", 2: "BUILTIN_SPEAKER", 3: "WIRED_HEADSET",
4: "WIRED_HEADPHONES", 8: "BTSCO", 9: "HDMI", 11: "USB_DEVICE",
}
return (f"AudioDeviceInfo(id={self._id}, "
f"type={type_names.get(self._type, str(self._type))})")
def equals(self, other: Any) -> bool:
if not isinstance(other, AudioDeviceInfo):
return False
return self._id == other._id
def hashCode(self) -> int:
return self._id & 0x7FFFFFFF
# ═══════════════════════════════════════════════════════════════
# AudioDeviceCallback
# ═══════════════════════════════════════════════════════════════
class AudioDeviceCallback(Stub):
"""AudioDeviceCallback — 音频设备回调"""
def onAudioDevicesAdded(self, addedDevices: List[AudioDeviceInfo]):
pass
def onAudioDevicesRemoved(self, removedDevices: List[AudioDeviceInfo]):
pass
def toString(self) -> str:
return f"AudioDeviceCallback@{hex(id(self))}"
def equals(self, other: Any) -> bool:
return self is other
def hashCode(self) -> int:
return id(self) & 0x7FFFFFFF
# ═══════════════════════════════════════════════════════════════
# AudioRouting
# ═══════════════════════════════════════════════════════════════
class AudioRouting(Stub):
"""AudioRouting — 音频路由接口"""
def setPreferredDevice(self, deviceInfo: AudioDeviceInfo) -> bool:
raise NotImplementedError
def getPreferredDevice(self) -> Optional[AudioDeviceInfo]:
return None
def getDevices(self, flags: int) -> List[AudioDeviceInfo]:
return []
def addOnRoutingPrefChangedListener(self, listener: Any, handler: Any = None):
pass
def removeOnRoutingPrefChangedListener(self, listener: Any):
pass
def toString(self) -> str:
return f"AudioRouting@{hex(id(self))}"
def equals(self, other: Any) -> bool:
return self is other
def hashCode(self) -> int:
return id(self) & 0x7FFFFFFF
# ═══════════════════════════════════════════════════════════════
# AudioPlaybackConfiguration
# ═══════════════════════════════════════════════════════════════
class AudioPlaybackConfiguration(Stub):
"""AudioPlaybackConfiguration — 音频回放配置"""
PLAYER_STATE_UNKNOWN = -1
PLAYER_STATE_IDLE = 0
PLAYER_STATE_STARTED = 1
PLAYER_STATE_PAUSED = 2
PLAYER_STATE_STOPPED = 3
def __init__(self, id_: int = 0, usage: int = AudioAttributes.USAGE_MEDIA,
contentType: int = AudioAttributes.CONTENT_TYPE_MUSIC,
playerState: int = PLAYER_STATE_UNKNOWN):
super().__init__()
self._id = id_
self._usage = usage
self._content_type = contentType
self._player_state = playerState
def getId(self) -> int:
return self._id
def getUsage(self) -> int:
return self._usage
def getContentType(self) -> int:
return self._content_type
def getPlayerState(self) -> int:
return self._player_state
def toString(self) -> str:
return f"AudioPlaybackConfiguration(id={self._id}, state={self._player_state})"
def equals(self, other: Any) -> bool:
if not isinstance(other, AudioPlaybackConfiguration):
return False
return self._id == other._id
def hashCode(self) -> int:
return self._id & 0x7FFFFFFF
# ═══════════════════════════════════════════════════════════════
# AudioRecordingConfiguration
# ═══════════════════════════════════════════════════════════════
class AudioRecordingConfiguration(Stub):
"""AudioRecordingConfiguration — 音频录制配置"""
def __init__(self, id_: int = 0, clientUid: int = 0,
sessionId: int = 0, source: int = 0,
audioFormat: Optional[AudioFormat] = None):
super().__init__()
self._id = id_
self._client_uid = clientUid
self._session_id = sessionId
self._source = source
self._audio_format = audioFormat or AudioFormat()
def getId(self) -> int:
return self._id
def getClientUid(self) -> int:
return self._client_uid
def getSessionId(self) -> int:
return self._session_id
def getSource(self) -> int:
return self._source
def getAudioFormat(self) -> AudioFormat:
return self._audio_format
def toString(self) -> str:
return f"AudioRecordingConfiguration(id={self._id}, source={self._source})"
def equals(self, other: Any) -> bool:
if not isinstance(other, AudioRecordingConfiguration):
return False
return self._id == other._id
def hashCode(self) -> int:
return self._id & 0x7FFFFFFF
# ═══════════════════════════════════════════════════════════════
# AudioManagerAudio (扩展音频管理器)
# ═══════════════════════════════════════════════════════════════
class AudioManagerAudio(Stub):
"""AudioManager — 音频管理器 (扩展版)"""
STREAM_VOICE_CALL = 0
STREAM_SYSTEM = 1
STREAM_RING = 2
STREAM_MUSIC = 3
STREAM_ALARM = 4
STREAM_NOTIFICATION = 5
STREAM_BLUETOOTH_SCO = 6
STREAM_SYSTEM_ENFORCED = 7
STREAM_DTMF = 8
STREAM_TTS = 9
STREAM_ACCESSIBILITY = 10
FLAG_SHOW_UI = 1
FLAG_ALLOW_RINGER_MODES = 2
FLAG_PLAY_SOUND = 4
FLAG_REMOVE_SOUND_AND_VIBRATE = 8
FLAG_VIBRATE = 16
FLAG_BYPASS_INTERRUPTION_POLICY = 32
FLAG_BYPASS_MUTE = 64
FLAG_HDMI_SYSTEM_AUDIO_VOLUME = 128
FLAG_FIXED_VOLUME = 256
MODE_INVALID = -2
MODE_CURRENT = -1
MODE_NORMAL = 0
MODE_RINGTONE = 1
MODE_IN_CALL = 2
MODE_IN_COMMUNICATION = 3
DEVICE_OUT_EARPIECE = 0x1
DEVICE_OUT_SPEAKER = 0x2
DEVICE_OUT_WIRED_HEADSET = 0x4
DEVICE_OUT_WIRED_HEADPHONE = 0x8
DEVICE_OUT_BLUETOOTH_SCO = 0x10
DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20
DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40
DEVICE_OUT_BLUETOOTH_A2DP = 0x80
DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100
DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200
DEVICE_OUT_AUX_DIGITAL = 0x400
DEVICE_OUT_HDMI = 0x800
DEVICE_OUT_ANLG_DOCK_HEADSET = 0x1000
DEVICE_OUT_DGTL_DOCK_HEADSET = 0x2000
DEVICE_OUT_USB_ACCESSORY = 0x4000
DEVICE_OUT_USB_DEVICE = 0x8000
DEVICE_OUT_USB_HEADSET = 0x10000
DEVICE_OUT_LINE = 0x20000
DEVICE_OUT_HDMI_ARC = 0x40000
DEVICE_OUT_HDMI_EARC = 0x80000
DEVICE_OUT_BLE_HEADSET = 0x100000
DEVICE_OUT_BLE_SPEAKER = 0x200000
DEVICE_OUT_REMOTE_SUBMIX = 0x800000
DEVICE_IN_BUILTIN_MIC = 0x80000004
DEVICE_IN_BLUETOOTH_SCO_HEADSET = 0x80000010
DEVICE_IN_WIRED_HEADSET = 0x80000020
DEVICE_IN_HDMI = 0x80000040
DEVICE_IN_LINE = 0x80000080
DEVICE_IN_USB_ACCESSORY = 0x80000100
DEVICE_IN_USB_DEVICE = 0x80000200
DEVICE_IN_BLUETOOTH_A2DP = 0x80000400
DEVICE_IN_USB_HEADSET = 0x80000800
DEVICE_IN_BLE_HEADSET = 0x80001000
DEVICE_IN_REMOTE_SUBMIX = 0x80002000
FORMAT_DEFAULT = 0
FORMAT_PCM_16_BIT = 1
FORMAT_PCM_8_BIT = 2
FORMAT_PCM_FLOAT = 4
FORMAT_AC3 = 5
FORMAT_E_AC3 = 6
FORMAT_DTS = 7
FORMAT_DTS_HD = 8
def __init__(self):
super().__init__()
self._volumes: Dict[int, int] = {
AudioManagerAudio.STREAM_MUSIC: 10,
AudioManagerAudio.STREAM_RING: 7,
AudioManagerAudio.STREAM_ALARM: 10,
AudioManagerAudio.STREAM_NOTIFICATION: 7,
AudioManagerAudio.STREAM_SYSTEM: 7,
AudioManagerAudio.STREAM_VOICE_CALL: 5,
}
self._muted: Dict[int, bool] = {}
self._mode = AudioManagerAudio.MODE_NORMAL
self._microphone_muted = False
self._speakerphone_on = False
self._master_volume = 1.0
self._master_mute = False
self._device_callbacks: List[AudioDeviceCallback] = []
self._devices: List[AudioDeviceInfo] = []
self._routed_devices: Dict[int, int] = {}
def getStreamVolume(self, streamType: int) -> int:
return self._volumes.get(streamType, 0)
def setStreamVolume(self, streamType: int, index: int, flags: int = 0):
self._volumes[streamType] = max(0, min(index, self.getStreamMaxVolume(streamType)))
def getStreamMaxVolume(self, streamType: int) -> int:
return 15
def getStreamMinVolume(self, streamType: int) -> int:
return 0
def isStreamMute(self, streamType: int) -> bool:
return self._muted.get(streamType, False)
def setStreamMute(self, streamType: int, state: bool):
self._muted[streamType] = state
def adjustVolume(self, direction: int, flags: int = 0):
pass
def adjustStreamVolume(self, streamType: int, direction: int, flags: int = 0):
current = self.getStreamVolume(streamType)
if direction == 1:
self.setStreamVolume(streamType, current + 1, flags)
elif direction == -1:
self.setStreamVolume(streamType, current - 1, flags)
def getMode(self) -> int:
return self._mode
def setMode(self, mode: int):
self._mode = mode
def isMicrophoneMute(self) -> bool:
return self._microphone_muted
def setMicrophoneMute(self, on: bool):
self._microphone_muted = on
def isSpeakerphoneOn(self) -> bool:
return self._speakerphone_on
def setSpeakerphoneOn(self, on: bool):
self._speakerphone_on = on
def getMasterVolume(self) -> float:
return self._master_volume
def setMasterVolume(self, volume: float):
self._master_volume = max(0.0, min(1.0, volume))
def isMasterMute(self) -> bool:
return self._master_mute
def setMasterMute(self, mute: bool):
self._master_mute = mute
def getDevices(self, flags: int) -> List[AudioDeviceInfo]:
return list(self._devices)
def setPreferredDeviceForStrategy(self, strategy: int, device: AudioDeviceInfo) -> bool:
self._routed_devices[strategy] = device.getId() if device else -1
return True
def registerAudioDeviceCallback(self, callback: AudioDeviceCallback, handler: Any = None):
self._device_callbacks.append(callback)
def unregisterAudioDeviceCallback(self, callback: AudioDeviceCallback):
self._device_callbacks = [cb for cb in self._device_callbacks if cb is not callback]
def getAudioPlaybackConfigurations(self) -> List[AudioPlaybackConfiguration]:
return []
def getAudioRecordingConfigurations(self) -> List[AudioRecordingConfiguration]:
return []
def generateAudioSessionId() -> int:
return int(time.time() * 1000) & 0x7FFFFFFF
def toString(self) -> str:
return f"AudioManager(mode={self._mode}, masterVol={self._master_volume})"
def equals(self, other: Any) -> bool:
return self is other
def hashCode(self) -> int:
return id(self) & 0x7FFFFFFF
# ═══════════════════════════════════════════════════════════════
# AudioMixPort / AudioPort / AudioPatch / AudioGain / AudioGainConfig
# ═══════════════════════════════════════════════════════════════
class AudioPort(Stub):
"""AudioPort — 音频端口"""
ROLE_NONE = 0
ROLE_SOURCE = 1
ROLE_SINK = 2
TYPE_NONE = 0
TYPE_DEVICE = 1
TYPE_SUBMIX = 2
TYPE_SESSION = 3
def __init__(self, id_: int = 0, name: str = "",
role: int = ROLE_NONE, type_: int = TYPE_NONE,
gains: List["AudioGain"] = None):
super().__init__()
self._id = id_
self._name = name
self._role = role
self._type = type_
self._gains = gains or []
def getId(self) -> int:
return self._id
def getName(self) -> str:
return self._name
def getRole(self) -> int:
return self._role
def type(self) -> int:
return self._type
def gains(self) -> List["AudioGain"]:
return list(self._gains)
def toString(self) -> str:
return f"AudioPort(id={self._id}, name={self._name})"
def equals(self, other: Any) -> bool:
if not isinstance(other, AudioPort):
return False
return self._id == other._id
def hashCode(self) -> int:
return self._id & 0x7FFFFFFF
class AudioMixPort(AudioPort):
"""AudioMixPort — 音频混合端口"""
def __init__(self, id_: int = 0, name: str = "",
role: int = AudioPort.ROLE_NONE,
gains: List["AudioGain"] = None):
super().__init__(id_=id_, name=name, role=role,
type_=AudioPort.TYPE_SUBMIX, gains=gains)
def toString(self) -> str:
return f"AudioMixPort(id={self._id}, name={self._name})"
class AudioGain(Stub):
"""AudioGain — 音频增益"""
MODE_JOINT = 1
MODE_CHANNELS = 2
MODE_RAMP = 4
def __init__(self, id_: int = 0, mode: int = MODE_JOINT,
channelMask: int = 0, minValue: int = 0,
maxValue: int = 100, defaultValue: int = 50,
stepValue: int = 1, minRampMs: int = 0, maxRampMs: int = 0):
super().__init__()
self._id = id_
self._mode = mode
self._channel_mask = channelMask
self._min_value = minValue
self._max_value = maxValue
self._default_value = defaultValue
self._step_value = stepValue
self._min_ramp_ms = minRampMs
self._max_ramp_ms = maxRampMs
def mode(self) -> int:
return self._mode
def channelMask(self) -> int:
return self._channel_mask
def minValue(self) -> int:
return self._min_value
def maxValue(self) -> int:
return self._max_value
def defaultValue(self) -> int:
return self._default_value
def stepValue(self) -> int:
return self._step_value
def toString(self) -> str:
return f"AudioGain(id={self._id}, range=[{self._min_value}, {self._max_value}])"
def equals(self, other: Any) -> bool:
if not isinstance(other, AudioGain):
return False
return self._id == other._id
def hashCode(self) -> int:
return self._id & 0x7FFFFFFF
class AudioGainConfig(Stub):
"""AudioGainConfig — 音频增益配置"""
def __init__(self, gain: Optional[AudioGain] = None,
mode: int = AudioGain.MODE_JOINT,
channelMask: int = 0,
values: List[int] = None,
rampDurationMs: int = 0):
super().__init__()
self._gain = gain
self._mode = mode
self._channel_mask = channelMask
self._values = values or []
self._ramp_duration_ms = rampDurationMs
def getGain(self) -> Optional[AudioGain]:
return self._gain
def getMode(self) -> int:
return self._mode
def getChannelMask(self) -> int:
return self._channel_mask
def getValues(self) -> List[int]:
return list(self._values)
def getRampDurationMs(self) -> int:
return self._ramp_duration_ms
def toString(self) -> str:
return f"AudioGainConfig(mode={self._mode}, values={self._values})"
class AudioPatch(Stub):
"""AudioPatch — 音频补丁"""
def __init__(self, id_: int = 0, sources: List[AudioPort] = None,
sinks: List[AudioPort] = None):
super().__init__()
self._id = id_
self._sources = sources or []
self._sinks = sinks or []
def getId(self) -> int:
return self._id
def getSources(self) -> List[AudioPort]:
return list(self._sources)
def getSinks(self) -> List[AudioPort]:
return list(self._sinks)
def toString(self) -> str:
return f"AudioPatch(id={self._id}, sources={len(self._sources)}, sinks={len(self._sinks)})"
def equals(self, other: Any) -> bool:
if not isinstance(other, AudioPatch):
return False
return self._id == other._id
def hashCode(self) -> int:
return self._id & 0x7FFFFFFF
# ═══════════════════════════════════════════════════════════════
# AudioMix
# ═══════════════════════════════════════════════════════════════
class AudioMix(Stub):
"""AudioMix — 音频混合"""
ROUTE_FLAG_RENDER = 1
ROUTE_FLAG_LOOP_BACK = 2
ROUTE_FLAG_CAPTURE = 4
CALLBACK_FLAG_NOTIFY_ACTIVITY = 1
def __init__(self, routeFlags: int = ROUTE_FLAG_RENDER,
callbackFlags: int = 0,
format_: Optional[AudioFormat] = None,
deviceType: int = AudioDeviceInfo.TYPE_BUILTIN_SPEAKER):
super().__init__()
self._route_flags = routeFlags
self._callback_flags = callbackFlags
self._format = format_ or AudioFormat()
self._device_type = deviceType
def getRouteFlags(self) -> int:
return self._route_flags
def getCallbackFlags(self) -> int:
return self._callback_flags
def getFormat(self) -> AudioFormat:
return self._format
def getDeviceType(self) -> int:
return self._device_type
def toString(self) -> str:
return f"AudioMix(routeFlags={self._route_flags})"
def equals(self, other: Any) -> bool:
if not isinstance(other, AudioMix):
return False
return self._route_flags == other._route_flags
def hashCode(self) -> int:
return self._route_flags & 0x7FFFFFFF
# ═══════════════════════════════════════════════════════════════
# AudioProfile
# ═══════════════════════════════════════════════════════════════
class AudioProfile(Stub):
"""AudioProfile — 音频配置文件"""
def __init__(self, format_: int = AudioFormat.ENCODING_DEFAULT,
sampleRates: List[int] = None,
channelMasks: List[int] = None,
channelIndexMasks: List[int] = None):
super().__init__()
self._format = format_
self._sample_rates = sampleRates or [44100, 48000]
self._channel_masks = channelMasks or [AudioFormat.CHANNEL_OUT_STEREO]
self._channel_index_masks = channelIndexMasks or []
def getFormat(self) -> int:
return self._format
def getSampleRates(self) -> List[int]:
return list(self._sample_rates)
def getChannelMasks(self) -> List[int]:
return list(self._channel_masks)
def getChannelIndexMasks(self) -> List[int]:
return list(self._channel_index_masks)
def toString(self) -> str:
return f"AudioProfile(format={self._format})"
def equals(self, other: Any) -> bool:
if not isinstance(other, AudioProfile):
return False
return self._format == other._format
def hashCode(self) -> int:
return self._format & 0x7FFFFFFF
# ═══════════════════════════════════════════════════════════════
# AudioProductStrategy
# ═══════════════════════════════════════════════════════════════
class AudioProductStrategy(Stub):
"""AudioProductStrategy — 音频产品策略"""
def __init__(self, id_: int = 0, name: str = "",
toleratedFormats: List[int] = None,
volumeGroup: Optional["AudioVolumeGroup"] = None):
super().__init__()
self._id = id_
self._name = name
self._tolerated_formats = toleratedFormats or []
self._volume_group = volume_group
def getId(self) -> int:
return self._id
def getName(self) -> str:
return self._name
def getToleratedFormats(self) -> List[int]:
return list(self._tolerated_formats)
def getVolumeGroup(self) -> Optional["AudioVolumeGroup"]:
return self._volume_group
def setVolumeGroup(self, group: "AudioVolumeGroup"):
self._volume_group = group
def toString(self) -> str:
return f"AudioProductStrategy(id={self._id}, name={self._name})"
def equals(self, other: Any) -> bool:
if not isinstance(other, AudioProductStrategy):
return False
return self._id == other._id
def hashCode(self) -> int:
return self._id & 0x7FFFFFFF
# ═══════════════════════════════════════════════════════════════
# AudioVolumeGroup
# ═══════════════════════════════════════════════════════════════
class AudioVolumeGroup(Stub):
"""AudioVolumeGroup — 音频音量组"""
def __init__(self, id_: int = 0, name: str = "",
volumeIndexMin: int = 0, volumeIndexMax: int = 15):
super().__init__()
self._id = id_
self._name = name
self._volume_index_min = volumeIndexMin
self._volume_index_max = volumeIndexMax
def getId(self) -> int:
return self._id
def getName(self) -> str:
return self._name
def getMinVolumeIndex(self) -> int:
return self._volume_index_min
def getMaxVolumeIndex(self) -> int:
return self._volume_index_max
def toString(self) -> str:
return f"AudioVolumeGroup(id={self._id}, name={self._name})"
def equals(self, other: Any) -> bool:
if not isinstance(other, AudioVolumeGroup):
return False
return self._id == other._id
def hashCode(self) -> int:
return self._id & 0x7FFFFFFF