Android Audio System 之三: AudioPolicyService 和 AudioPolicyManager

AudioPolicyService详解
本文深入解析Android音频系统中的AudioPolicyService组件,涵盖其主要职责、内部结构及与AudioPolicyManager的交互过程。介绍如何管理音频设备连接状态、音量设置及音频策略切换。

引言

    AudioPolicyService是Android音频系统的两大服务之一,另一个服务是AudioFlinger,这两大服务都在系统启动时有MediaSever加载,加载的代码位于:frameworks/base/media/mediaserver/main_mediaserver.cpp。AudioFlinger主要负责管理音频数据处理以及和硬件抽象层相关的工作。本文主要介绍AudioPolicyService。

AudioPolicyService

    AudioPolicyService主要完成以下任务:

  • JAVA应用层通过JNI,经由IAudioPolicyService接口,访问AudioPolicyService提供的服务
  • 输入输出设备的连接状态
  • 系统的音频策略(strategy)的切换
  • 音量/音频参数的设置

    AudioPolicyService的构成

    下面这张图描述了AudioPolicyService的静态结构:

 

进一步说明:

1. AudioPolicyService继承了IAudioPolicyService接口,这样AudioPolicyService就可以基于Android的Binder机制,向外部提供服务;

2. AudioPolicyService同时也继承了AudioPolicyClientInterface类,他有一个AudioPolicyInterface类的成员指针mpPolicyManager,实际上就是指向了AudioPolicyManager;

3. AudioPolicyManager类继承了AudioPolicyInterface类以便向AudioPolicyService提供服务,反过来同时还有一个AudioPolicyClientInterface指针,该指针在构造函数中被初始化,指向了AudioPolicyService,实际上,AudioPolicyService是通过成员指针mpPolicyManager访问AudioPolicyManager,而AudioPolicyManager则通过AudioPolicyClientInterface(mpClientInterface)访问AudioPolicyService;

4. AudioPolicyService有一个内部线程类AudioCommandThread,顾名思义,所有的命令(音量控制,输入、输出的切换等)最终都会在该线程中排队执行;

AudioPolicyManager

    AudioPolicyService的很大一部分管理工作都是在AudioPolicyManager中完成的。包括音量管理,音频策略(strategy)管理,输入输出设备管理。

输入输出设备管理

音频系统为音频设备定义了一个枚举:AudioSystem::audio_devices,例如:DEVICE_OUT_SPEAKER,DEVICE_OUT_WIRED_HEADPHONE,DEVICE_OUT_BLUETOOTH_A2DP,DEVICE_IN_BUILTIN_MIC,DEVICE_IN_VOICE_CALL等等,每一个枚举值其实对应一个32bit整数的某一个位,所以这些值是可以进行位或操作的,例如我希望同时打开扬声器和耳机,那么可以这样:

AudioPolicyManager中有两个成员变量:mAvailableOutputDevices和mAvailableInputDevices,他们记录了当前可用的输入和输出设备,当系统检测到耳机或者蓝牙已连接好时,会调用AudioPolicyManager的成员函数:

该函数根据传入的device值和state(DEVICE_STATE_AVAILABLE/DEVICE_STATE_UNAVAILABLE)设置mAvailableOutputDevices或者mAvailableInputDevices,然后选择相应的输入或者输出设备。

其他一些相关的函数:

  • setForceUse()  设置某种场合强制使用某一设备,例如setForceUse(FOR_MEDIA, FORCE_SPEAKER)会在播放音乐时打开扬声器
  • startOutput()/stopOutput()
  • startInput()/stopInput()

音量管理

AudioPolicyManager提供了一下几个与音量相关的函数:

  • initStreamVolume(AudioSystem::stream_type stream, int indexMin, int indexMax)
  • setStreamVolumeIndex(AudioSystem::stream_type stream, int index)
  • getStreamVolumeIndex(AudioSystem::stream_type stream)

AudioService.java中定义了每一种音频流的最大音量级别:

由此可见,电话铃声可以有7个级别的音量,而音乐则可以有15个音量级别,java的代码通过jni,最后调用AudioPolicyManager的initStreamVolume(),把这个数组的内容传入AudioPolicyManager中,这样AudioPolicyManager也就记住了每一个音频流的音量级别。应用程序可以调用setStreamVolumeIndex设置各个音频流的音量级别,setStreamVolumeIndex会把这个整数的音量级别转化为适合人耳的对数级别,然后通过AudioPolicyService的AudioCommandThread,最终会将设置应用到AudioFlinger的相应的Track中。

音频策略管理

 我想首先要搞清楚stream_type,device,strategy三者之间的关系:

  • AudioSystem::stream_type  音频流的类型,一共有10种类型
  • AudioSystem::audio_devices  音频输入输出设备,每一个bit代表一种设备,见前面的说明
  • AudioPolicyManager::routing_strategy 音频路由策略,可以有4种策略

getStrategy(stream_type)根据stream type,返回对应的routing strategy值,getDeviceForStrategy()则是根据routing strategy,返回可用的device。Android把10种stream type归纳为4种路由策略,然后根据路由策略决定具体的输出设备。

 

成员变量mOutputs

这是AudioPolocyManager用管理输出的键值对向量(数组),通常AudioPolocyManager会打开3个输出句柄(audio_io_handle_t),关于audio_io_handle_t,请参考另一编博客:http://blog.csdn.net/DroidPhone/archive/2010/10/14/5941344.aspx,它实际上就是AudioFlinger中某个PlaybackTread的ID。这3个句柄分别是:

  • mHardwareOutput            // hardware output handler
  • mA2dpOutput                   // A2DP output handler
  • mDuplicatedOutput          // duplicated output handler: outputs to hardware and A2DP

可以通过startOutput()把某一个stream type放入到相应的输出中。

 

popCount()

这个函数主要用来计算device变量中有多少个非0位(计算32位数种1的个数),例如该函数返回2,代表同时有两个device要处理。之所以特别介绍它,是因为这个函数的实现很有意思:

不知道各位看懂了么?

 

 

AudioCommandThread

    这是AudioPolicyService中的一个线程,主要用于处理音频设置相关的命令。包括:

  • START_TONE
  • STOP_TONE
  • SET_VOLUME
  • SET_PARAMETERS
  • SET_VOICE_VOLUME

     每种命令的参数有相应的包装:

  • class ToneData
  • class VolumeData
  • class ParametersData
  • class VoiceVolumeData

    START_TONE/STOP_TONE:播放电话系统中常用的特殊音调,例如:TONE_DTMF_0,TONE_SUP_BUSY等等。

    SET_VOLUME:最终会调用AudioFlinger进行音量设置

    SET_VOICE_VOLUME:最终会调用AudioFlinger进行电话音量设置

    SET_PARAMETERS:通过一个KeyValuePairs形式的字符串进行参数设置,KeyValuePairs的格式可以这样:

 

  •  "sampling_rate=44100"
  • "channels=2"
  • "sampling_rate=44100;channels=2"     // 组合形式

    这些KeyValuePairs可以通过AudioPolicyService的成员函数setParameters()传入。

 

ABI: 'arm64' Timestamp: 2025-11-04 16:26:21.674122723+0800 Process uptime: 951004s Cmdline: /system/bin/audioserver pid: 2315, tid: 13258, name: binder:2315_C >>> /system/bin/audioserver <<< uid: 1041 tagged_addr_ctrl: 0000000000000001 (PR_TAGGED_ADDR_ENABLE) pac_enabled_keys: 000000000000000f (PR_PAC_APIAKEY, PR_PAC_APIBKEY, PR_PAC_APDAKEY, PR_PAC_APDBKEY) signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr -------- Abort message: 'TimeCheck timeout for IAudioPolicyService::registerPolicyMixes scheduled 16:26:07.600 on thread 13258 Timeout ms 13000.00 (8000.00 + 5000.00) elapsed steady ms 13000.6270 elapsed system ms 13000.6289 HAL pids [ 2047 ] now 16:26:21.636 secondChanceCount 65 analysis [ ] timeout [ { IAudioPolicyService::registerPolicyMixes scheduled 16:26:07.600 deadline :15.600 tid 13258 } ] pending [ { IAudioPolicyService::setForceUse scheduled 16:26:07.928 deadline :15.928 tid 8207 } { IAudioPolicyService::isStreamActive scheduled 16:26:08.236 deadline :16.236 tid 7206 } { IAudioPolicyService::getDevicesForAttributes scheduled 16:26:08.345 deadline :16.345 tid 11663 } { IAudioPolicyService::isStreamActive scheduled 16:26:09.455 deadline :17.455 tid 2315 } { IAudioPolicyService::setA11yServicesUids scheduled 16:26:09.496 deadline :17.496 tid 16797 } { IAudioPolicyService::isStreamActive scheduled 16:26:11.082 deadline :19.082 tid 29854 } { IAudioPolicyService::listAudioProductStrategies scheduled 16:26:11.654 deadline :19.654 tid 641 } { IAudioPolicyService::isStreamActive scheduled 16:26:12.246 deadline :20.246 tid 9091 } { IAudioPolicyService::isStreamActive scheduled 16:26:16.038 deadline :24.038 tid 2451 } { StreamOutHalHidl::updateSourceMetadata scheduled 16:26:19.597 deadline tid 3677 } { IAudioPolicyService::109 scheduled 16:26:20.290 deadline :28.290 tid 8708 } ] retired [ { DeviceHalHidl::getParameters scheduled 16:26:20.538 deadline tid 16630 } { DeviceHalHidl::getParameters scheduled 16:26:20.539 deadline tid 16630 } { DeviceHalHidl::getParameters scheduled 16:26:20.539 deadline tid 16630 } { IAudioFlinger::getParameters scheduled 16:26:20.537 deadline :28.537 tid 16630 } ] timeout(13258) callstack [ #00 pc 00000000000aff64 /apex/com.android.runtime/lib64/bionic/libc.so (syscall+36) (BuildId: 729ca2eb4fb5ce36e0058b2742c0e097) #01 pc 000000000008b75c /apex/com.android.runtime/lib64/bionic/libc.so (__futex_wait_ex(void volatile*, bool, int, bool, timespec const*)+148) (BuildId: 729ca2eb4fb5ce36e0058b2742c0e097) #02 pc 00000000000996bc /apex/com.android.runtime/lib64/bionic/libc.so (pthread_cond_clockwait+180) (BuildId: 729ca2eb4fb5ce36e0058b2742c0e097) #03 pc 00000000000778ac /system/lib64/libaudiopolicyservice.so (std::__1::cv_status std::__1::condition_variable::wait_for<long long, std::__1::ratio<1l, 1000000000l>>(std::__1::unique_lock<std::__1::mutex>&, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l>> const&)+192) (BuildId: bb529c12fed0ad894e0fad271ff7c0ce) #04 pc 0000000000077528 /system/lib64/libaudiopolicyservice.so (std::__1::cv_status android::audio_utils::condition_variable::wait_for<android::audio_utils::mutex_impl<android::audio_utils::AudioMutexAttributes>, long long, std::__1::ratio<1l, 1000000000l>>(android::audio_utils::unique_lock<android::audio_utils::mutex_impl<android::audio_utils::AudioMutexAttributes>>&, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l>> const&, int)+80) (BuildId: bb529c12fed0ad894e0fad271ff7c0ce) #05 pc 0000000000075d38 /system/lib64/libaudiopolicyservice.so (android::AudioPolicyService::AudioCommandThread::sendCommand(android::sp<android::AudioPolicyService::AudioCommandThread::AudioCommand>&, int)+316) (BuildId: bb529c12fed0ad894e0fad271ff7c0ce) #06 pc 000000000008bfc8 /system/lib64/libaudiopolicyservice.so (android::AudioPolicyService::AudioCommandThread::createAudioPatchCommand(audio_patch const*, int*, int)+428) (BuildId: bb529c12fed0ad894e0fad271ff7c0ce) #07 pc 00000000000440c0 /system/lib64/libaudiopolicymanagerdefault.so (android::AudioPolicyManager::installPatch(char const*, long, int*, audio_patch const*, int, unsigned int, android::sp<android::AudioPatch>*, bool)+236) (BuildId: 12aca022714682ed7eba9623053ec28e) #08 pc 0000000000043e78 /system/lib64/libaudiopolicymanagerdefault.so (android::AudioPolicyManager::installPatch(char const*, int*, android::AudioIODescriptorInterface*, audio_patch const*, int, bool)+356) (BuildId: 12aca022714682ed7eba9623053ec28e) #09 pc 0000000000038cc0 /system/lib64/libaudiopolicymanagerdefault.so (android::AudioPolicyManager::setOutputDevices(char const*, android::sp<android::SwAudioOutputDescriptor> const&, android::DeviceVector const&, bool, int, int*, bool, bool, bool, bool)+9588) (BuildId: 12aca022714682ed7eba9623053ec28e) #10 pc 000000000002ef14 /system/lib64/libaudiopolicymanagerdefault.so (android::AudioPolicyManager::setDeviceConnectionStateInt(android::sp<android::DeviceDescriptor> const&, audio_policy_dev_state_t, bool)+5948) (BuildId: 12aca022714682ed7eba9623053ec28e) #11 pc 000000000002d0f0 /system/lib64/libaudiopolicymanagerdefault.so (android::AudioPolicyManager::setDeviceConnectionStateInt(audio_policy_dev_state_t, android::media::audio::common::AudioPort const&, audio_format_t, bool)+688) (BuildId: 12aca022714682ed7eba9623053ec28e) #12 pc 00000000000656bc /system/lib64/libaudiopolicymanagerdefault.so (android::AudioPolicyManager::setDeviceConnectionStateInt(audio_devices_t, audio_policy_dev_state_t, char const*, char const*, audio_format_t, bool)+548) (BuildId: 12aca022714682ed7eba9623053ec28e) #13 pc 000000000008d1a8 /system/lib64/libaudiopolicymanagerdefault.so (android::AudioPolicyManager::unregisterPolicyMixes(android::Vector<android::AudioMix>)+1008) (BuildId: 12aca022714682ed7eba9623053ec28e) #14 pc 000000000005d4dc /system/lib64/libaudiopolicyservice.so (android::AudioPolicyService::registerPolicyMixes(std::__1::vector<android::media::AudioMix, std::__1::allocator<android::media::AudioMix>> const&, bool)+2432) (BuildId: bb529c12fed0ad894e0fad271ff7c0ce) #15 pc 00000000000400fc /system/lib64/audiopolicy-aidl-cpp.so (android::media::BnAudioPolicyService::onTransact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+22652) (BuildId: 32e17e3b33a8b9259524807e5076cd3f) #16 pc 0000000000072cb0 /system/lib64/libaudiopolicyservice.so (android::AudioPolicyService::onTransact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+1240) (BuildId: bb529c12fed0ad894e0fad271ff7c0ce) #17 pc 000000000004d2bc /system/lib64/libbinder.so (android::BBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+324) (BuildId: 0abb3e8891888472809ad5cc54c106d7) #18 pc 000000000004da54 /system/lib64/libbinder.so (android::IPCThreadState::executeCommand(int)+1136) (BuildId: 0abb3e8891888472809ad5cc54c106d7) #19 pc 0000000000077108 /system/lib64/libbinder.so (android::IPCThreadState::joinThreadPool(bool)+456) (BuildId: 0abb3e8891888472809ad5cc54c106d7) #20 pc 0000000000076ca0 /system/lib64/libbinder.so (android::PoolThread::threadLoop()+100) (BuildId: 0abb3e8891888472809ad5cc54c106d7) #21 pc 0000000000017464 /system/lib64/libutils.so (android::Thread::_threadLoop(void*)+252) (BuildId: cd6fe1a2f106f83ac0868f825dfc8390) #22 pc 0000000000019bd0 /system/lib64/libutils.so (libutil_thread_trampoline(void*) (.__uniq.226528677032898775202282855395389835431)+24) (BuildId: cd6fe1a2f106f83ac0868f825dfc8390) #23 pc 000000000009a1ac /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+184) (BuildId: 729ca2eb4fb5ce36e0058b2742c0e097) #24 pc 000000000008c9c8 /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+68) (BuildId: 729ca2eb4fb5ce36e0058b2742c0e097) ]' x0 fffffffffffffffc x1 0000000000000089 x2 0000000000000000 x3 0000007bf5df7a70 x4 0000000000000000 x5 00000000ffffffff x6 00000000ffffffff x7 b400007c37710459 x8 0000000000000062 x9 0000000000000089 x10 ffffffffc4653600 x11 0000000000000001 x12 00000000000b0a41 x13 000000007fffffff x14 0000000015185c6e x15 0000109b8a401fac x16 0000007cbabef8f0 x17 0000007cbab97f40 x18 0000007bf59c8000 x19 0000000000000000 x20 0000007bf5df7a70 x21 b400007c376f13b8 x22 0000000000000089 x23 0000007bf5dfbdc0 x24 0000007bf5dfbe40 x25 0000000000000016 x26 00000000ee6b2800 x27 0000007cc51f2d40 x28 0000000000000001 x29 0000007bf5df79e0 lr 0000007cbab73760 sp 0000007bf5df79c0 pc 0000007cbab97f64 pst 0000000040001000 25 total frames backtrace: #00 pc 00000000000aff64 /apex/com.android.runtime/lib64/bionic/libc.so (syscall+36) (BuildId: 729ca2eb4fb5ce36e0058b2742c0e097) #01 pc 000000000008b75c /apex/com.android.runtime/lib64/bionic/libc.so (__futex_wait_ex(void volatile*, bool, int, bool, timespec const*)+148) (BuildId: 729ca2eb4fb5ce36e0058b2742c0e097) #02 pc 00000000000996bc /apex/com.android.runtime/lib64/bionic/libc.so (pthread_cond_clockwait+180) (BuildId: 729ca2eb4fb5ce36e0058b2742c0e097) #03 pc 00000000000778ac /system/lib64/libaudiopolicyservice.so (std::__1::cv_status std::__1::condition_variable::wait_for<long long, std::__1::ratio<1l, 1000000000l>>(std::__1::unique_lock<std::__1::mutex>&, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l>> const&)+192) (BuildId: bb529c12fed0ad894e0fad271ff7c0ce) #04 pc 0000000000077528 /system/lib64/libaudiopolicyservice.so (std::__1::cv_status android::audio_utils::condition_variable::wait_for<android::audio_utils::mutex_impl<android::audio_utils::AudioMutexAttributes>, long long, std::__1::ratio<1l, 1000000000l>>(android::audio_utils::unique_lock<android::audio_utils::mutex_impl<android::audio_utils::AudioMutexAttributes>>&, std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l>> const&, int)+80) (BuildId: bb529c12fed0ad894e0fad271ff7c0ce) #05 pc 0000000000075d38 /system/lib64/libaudiopolicyservice.so (android::AudioPolicyService::AudioCommandThread::sendCommand(android::sp<android::AudioPolicyService::AudioCommandThread::AudioCommand>&, int)+316) (BuildId: bb529c12fed0ad894e0fad271ff7c0ce) #06 pc 000000000008bfc8 /system/lib64/libaudiopolicyservice.so (android::AudioPolicyService::AudioCommandThread::createAudioPatchCommand(audio_patch const*, int*, int)+428) (BuildId: bb529c12fed0ad894e0fad271ff7c0ce) #07 pc 00000000000440c0 /system/lib64/libaudiopolicymanagerdefault.so (android::AudioPolicyManager::installPatch(char const*, long, int*, audio_patch const*, int, unsigned int, android::sp<android::AudioPatch>*, bool)+236) (BuildId: 12aca022714682ed7eba9623053ec28e) #08 pc 0000000000043e78 /system/lib64/libaudiopolicymanagerdefault.so (android::AudioPolicyManager::installPatch(char const*, int*, android::AudioIODescriptorInterface*, audio_patch const*, int, bool)+356) (BuildId: 12aca022714682ed7eba9623053ec28e) #09 pc 0000000000038cc0 /system/lib64/libaudiopolicymanagerdefault.so (android::AudioPolicyManager::setOutputDevices(char const*, android::sp<android::SwAudioOutputDescriptor> const&, android::DeviceVector const&, bool, int, int*, bool, bool, bool, bool)+9588) (BuildId: 12aca022714682ed7eba9623053ec28e) #10 pc 000000000002ef14 /system/lib64/libaudiopolicymanagerdefault.so (android::AudioPolicyManager::setDeviceConnectionStateInt(android::sp<android::DeviceDescriptor> const&, audio_policy_dev_state_t, bool)+5948) (BuildId: 12aca022714682ed7eba9623053ec28e) #11 pc 000000000002d0f0 /system/lib64/libaudiopolicymanagerdefault.so (android::AudioPolicyManager::setDeviceConnectionStateInt(audio_policy_dev_state_t, android::media::audio::common::AudioPort const&, audio_format_t, bool)+688) (BuildId: 12aca022714682ed7eba9623053ec28e) #12 pc 00000000000656bc /system/lib64/libaudiopolicymanagerdefault.so (android::AudioPolicyManager::setDeviceConnectionStateInt(audio_devices_t, audio_policy_dev_state_t, char const*, char const*, audio_format_t, bool)+548) (BuildId: 12aca022714682ed7eba9623053ec28e) #13 pc 000000000008d1a8 /system/lib64/libaudiopolicymanagerdefault.so (android::AudioPolicyManager::unregisterPolicyMixes(android::Vector<android::AudioMix>)+1008) (BuildId: 12aca022714682ed7eba9623053ec28e) #14 pc 000000000005d4dc /system/lib64/libaudiopolicyservice.so (android::AudioPolicyService::registerPolicyMixes(std::__1::vector<android::media::AudioMix, std::__1::allocator<android::media::AudioMix>> const&, bool)+2432) (BuildId: bb529c12fed0ad894e0fad271ff7c0ce) #15 pc 00000000000400fc /system/lib64/audiopolicy-aidl-cpp.so (android::media::BnAudioPolicyService::onTransact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+22652) (BuildId: 32e17e3b33a8b9259524807e5076cd3f) #16 pc 0000000000072cb0 /system/lib64/libaudiopolicyservice.so (android::AudioPolicyService::onTransact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+1240) (BuildId: bb529c12fed0ad894e0fad271ff7c0ce) #17 pc 000000000004d2bc /system/lib64/libbinder.so (android::BBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+324) (BuildId: 0abb3e8891888472809ad5cc54c106d7) #18 pc 000000000004da54 /system/lib64/libbinder.so (android::IPCThreadState::executeCommand(int)+1136) (BuildId: 0abb3e8891888472809ad5cc54c106d7) #19 pc 0000000000077108 /system/lib64/libbinder.so (android::IPCThreadState::joinThreadPool(bool)+456) (BuildId: 0abb3e8891888472809ad5cc54c106d7) #20 pc 0000000000076ca0 /system/lib64/libbinder.so (android::PoolThread::threadLoop()+100) (BuildId: 0abb3e8891888472809ad5cc54c106d7) #21 pc 0000000000017464 /system/lib64/libutils.so (android::Thread::_threadLoop(void*)+252) (BuildId: cd6fe1a2f106f83ac0868f825dfc8390) #22 pc 0000000000019bd0 /system/lib64/libutils.so (libutil_thread_trampoline(void*) (.__uniq.226528677032898775202282855395389835431)+24) (BuildId: cd6fe1a2f106f83ac0868f825dfc8390) #23 pc 000000000009a1ac /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+184) (BuildId: 729ca2eb4fb5ce36e0058b2742c0e097) #24 pc 000000000008c9c8 /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+68) (BuildId: 729ca2eb4fb5ce36e0058b2742c0e097)
最新发布
11-08
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值