Navidrome+MusicTag+音流 搭建属于自己的音乐服务器-Part1:安装服务器

目录

part1:Navidrome服务器安装(本章)
part2:MusicTag音乐刮削(待发布)
part3:音流安装与使用(待发布)

序言

是否还在被昂贵的音乐会员困扰?何不自己小成本搭建一个音乐服务器,让你和你家人听上免费音乐?
安装过程我尽量做到小白都能看懂,有任何安装方面的疑问都可以留言或者私信我,看到都会解答。

首先你需要一台服务器

首先你需要一台服务器,可以参考VPS推荐网寻找适合你使用的服务器,推荐使用香港的优化线路,并且磁盘尽量在30g以上(机器的价格其实可以完全抵消你购买音乐会员的价格,并且Navidrome不限制登录人数,你可以给你的家人一起使用),这是本教程唯一需要花钱的地方。
114vps

购买的时候会让你选择系统,建议选择centos8或者centos9(这个系统更加稳定,后续也可以随时重装更换系统)。
以云悠的购买为例

登录你的服务器

购买服务器以后,会提供给你服务器的ip和密码,以及ssh的登录端口(注意不要在公开的地方暴露你的ip)。没过用ssh客户端的话,可以百度下FinalShell官网,适合小白使用。

安装Navidrome

Navidrome是什么?你可以理解他是一个音乐服务器,安装以后,就可以在网页端,或者安装ios、安卓的app听音乐了。

打开FinalShell,并连接你的服务器,先安装docker(这一步会需要一点时间,需要耐心一点,如果失败了可以重试,大概需要5分钟左右):

sudo curl -fsSL https://github.com/tech-shrimp/docker_installer/releases/download/latest/linux.sh| bash -s docker --mirror Aliyun

等待安装完成,然后启动docker

sudo systemctl start docker

将docker设置成开机自动启动

sudo systemctl enable docker

下载docker-compose

sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

需要给 docker-compose 一个执行权限

sudo chmod +x /usr/local/bin/docker-compose

查看是否成功

docker-compose -version

如果你的控制台展示类似下面的数据,就说明我们的docker环境安装成功了
image.png

然后创建并进入navidrome的工作目录(下面一行一行执行)

cd ~
mkdir navidrome
cd navidrome
mkdir music

然后用FinalShell刷新下root目录,就能看到你的navidrome文件夹了
image.png

在你本地创建一个docker-compose.yml文件(window电脑可以创建一个txt文件,然后把文件名字改了就好,记得txt后拽也要改,当然如果你会用vi或者vim,也可以直接在服务器上创建这个文件),将下面的内容复制到文件中

version: "3"
services:
  navidrome:
    image: deluan/navidrome:latest
    ports:
      - "4533:4533"
    restart: unless-stopped
    environment:
      ND_SCANSCHEDULE: 1h
      ND_LOGLEVEL: error
      ND_SESSIONTIMEOUT: 24h
      ND_BASEURL: ""
    volumes:
      - "~/navidrome/data:/data"
      - "~/navidrome/music:/music:ro"

然后把docker-compose.yml拖到服务器navidrome目录下,现在结构是这样的:
image.png

启动容器:

docker-compose up -d

服务器会自动拉取软件并安装,等待执行完成即可
image.png

在浏览器输入你的网址(http://你的ip:4533/),就可以访问的网页端了,第一次登录要创建一下管理员账号

image.png

登录以后修改下中文
image.png

image.png

回到FinalShell,打开Navidrome目录下的music文件夹(没有的话右键刷新一下):
image.png

随便拖入一个音乐文件(音乐哪里找? 可以百度一些网盘搜索,然后搜索你要的音乐就好,相信这对你来说不是难事),后续你新增的音乐都直接拖入找个文件夹就好,并且只要在找个文件夹下,你创建的二级目录也是可以被扫描到的:
image.png

回到Navidrome 网页端,刷新就可以看到你刚才导入的音乐,双击即可播放:
image.png

至此,我们最复杂的工作已经完成,网页端也可以访问听歌了。
你找的音乐文件可能没有封面或者歌词,下一章我们将讲MusicTag刮削音乐,来解决找个问题。

128394: 11-12 23:25:03.210517 26337 30168 I AudioTrack: set(): type=audio,case=1,attributes=1,content_type=2,usage=1,source=0,flags=0x900 行 128395: 11-12 23:25:03.210577 26337 30168 D AudioTrackExtImpl: AudioTrackExtImpl init 行 128398: 11-12 23:25:03.210944 26337 30168 D AudioTrack: set(): streamType -1, sampleRate 44100, format 0x1, channelMask 0x3, frameCount 0, flags #0, notificationFrames 0, sessionId 0, transferType 0, uid -1, pid -1128415: 11-12 23:25:03.214347 26337 30168 I AudioTrack: set(): 0xb40000758e06e200, Create AudioTrackThread, tid = 30169 行 128418: 11-12 23:25:03.215112 26337 30168 D AudioTrackExtImpl: doSchedBoost, set audioapp task boost, pid=26337, tid=30168, enable=1, ret=0 行 128441: 11-12 23:25:03.227434 26337 30168 D AudioTrack: createTrack state 0 output.outputId=13 行 128447: 11-12 23:25:03.230800 26337 30168 I AudioTrack: createTrack_l(239) on outputId(13) : 0xb40000758e06e200, mCblk = 0x7686f6c000, mLatency = 3211, mAfLatency = 61, frameCount = 138944, mSampleRate = 44100, mFlags = 0, mReqFrameCount = 138944, mNotificationFramesAct = 0 行 128451: 11-12 23:25:03.233983 26337 30168 D AudioTrackExtImpl: doSchedBoost, set audioapp task boost, pid=26337, tid=30168, enable=0, ret=0 行 128455: 11-12 23:25:03.235525 26337 30168 E AudioTrackExtImpl: get fade type, but return null, uid 10219 行 128456: 11-12 23:25:03.235549 26337 30168 D AudioTrack: set: pop_optimize mIsPopOptimizeSupport:0, mIsPopOptimizeFlush:0 行 128457: 11-12 23:25:03.235629 26337 30168 D AudioTrack: setVolume(239) left 1.000 right 1.000 , callingPid 26337 行 128458: 11-12 23:25:03.235826 26337 30168 D AudioTrack: start(239): prior state:STATE_STOPPED output 13 stream 3 session 2185 行 128483: 11-12 23:25:03.241041 2445 3078 D APM_AudioPolicyManager: setOutputDevice() output 13 device {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, @:SUPPRESSED} force 1 delayMs 0 行 128584: 11-12 23:25:03.286811 2445 19963 D AudioFlinger_PlaybackThreadExtImpl: notifyAudioTrackCreate event:atlas_event_audio_track_create info:pid:26337,sessionId:2185,streamType:3,sampleRate:44100,format:1,startvl:1.000,startvr:1.000,balance:0.000,channelcount:2,flags:6,deviceTypes:128,hasFastMixer:1,isOffloadThread:0,isSpatialized:0,id:13,effectChains:0,frameCount:138944,requestFC:0,minFC:0,metaAudioScene:0,metaAudioPos:[0.0|0.0|0.0],window_rendering:0 行 128586: 11-12 23:25:03.287342 2445 19963 E AudioFlinger_PlaybackThread_TrackExtImpl: isSupportAudioRampStatus: AudioFlingerExt or AudioTrackServerProxyExt point is NULL. 行 128587: 11-12 23:25:03.287353 2445 19963 E AudioFlinger_PlaybackThread_TrackExtImpl: isSupportAudioRampStatus: AudioFlingerExt or AudioTrackServerProxyExt point is NULL. 行 128995: 11-12 23:25:03.360912 19626 19961 D A2dpStateMachine: handleMessage: E msg.what=101128996: 11-12 23:25:03.360976 19626 19961 D A2dpStateMachine: processMsg: Connected 行 128997: 11-12 23:25:03.361075 19626 19961 D A2dpStateMachine: Connected process message(XX:XX:XX:XX:F2:8F): STACK_EVENT 行 128998: 11-12 23:25:03.361137 19626 19961 D OplusA2dpStateMachineExtImpl: oplusConnectedProcessMessage, msg = 101128999: 11-12 23:25:03.361211 19626 19961 D A2dpStateMachine: Connected: stack event: A2dpStackEvent {type:EVENT_TYPE_AUDIO_STATE_CHANGED, device:XX:XX:XX:XX:F2:8F, value1:STARTED} 行 129000: 11-12 23:25:03.361291 19626 19961 D A2dpStateMachine: Connected: started playing: XX:XX:XX:XX:F2:8F 行 129001: 11-12 23:25:03.361355 19626 19961 D A2dpStateMachine: A2DP Playing state : device: XX:XX:XX:XX:F2:8F State:NOT_PLAYING->PLAYING 行 129459: 11-12 23:25:03.509531 6152 6152 I AEC.PlaybackManager: Received action: android.Multimedia.AudioEffect.AudioTrack_BROADCAST 行 136040: 11-12 23:25:07.356420 30312 30351 I [Longshot][playSound]: spend:3ms. 行 136109: 11-12 23:25:07.375226 5036 5824 D DCS>ContentProvider[main#binder:5036_4]: DcsContentProvider insert: statSId=e3869d70-2e84-4cbc-906f-062be16167c6 eventID=screenshot_performance logMap={"screenshotDesc":"playSound","startTime":"142002406","endTime":"142002409","RelationId":"8b219dff8e824e0b941c0afc3dae2050"} logTag=20088 appName=Screenshot appId=20088 ssoid=0 appPackage=com.oplus.screenshot appIdStr=20088 appVersion=16.2.16_sp1 dataType=1006 headerFlag=0 行 142222: 11-12 23:25:10.485088 30312 30312 D AudioManager: playSoundEffect effectType=0 userId=-2 行 144265: 11-12 23:25:11.556572 26337 26337 D AudioManager: playSoundEffect effectType=0 userId=-2 行 155945: 11-12 23:25:15.766196 4834 5943 D SystemUi--Keyguard: OnScreenFingerOverlayUtils-->playSound ring volume is 0为什么没有声音
最新发布
11-18
<think> 我们正在分析日志,特别是关于OnScreenFingerOverlayUtils播放声音时铃声音量为0导致没有声音的原因。 日志片段如下: 行 128394: 11-12 23:25:03.210517 26337 30168 I AudioTrack: set(): type=audio,case=1,attributes=1,content_type=2,usage=1,source=0,flags=0x900 行 128395: 11-12 23:25:03.210577 26337 30168 D AudioTrackExtImpl: AudioTrackExtImpl init 行 128398: 11-12 23:25:03.210944 26337 30168 D AudioTrack: set(): streamType -1, sampleRate 44100, format 0x1, channelMask 0x3, frameCount 0, flags #0, notificationFrames 0, sessionId 0, transferType 0, uid -1, pid -1128415: 11-12 23:25:03.214347 26337 30168 I AudioTrack: set(): 0xb40000758e06e200, Create AudioTrackThread, tid = 30169 行 128418: 11-12 23:25:03.215112 26337 30168 D AudioTrackExtImpl: doSchedBoost, set audioapp task boost, pid=26337, tid=30168, enable=1, ret=0 行 128441: 11-12 23:25:03.227434 26337 30168 D AudioTrack: createTrack state 0 output.outputId=13 行 128447: 11-12 23:25:03.230800 26337 30168 I AudioTrack: createTrack_l(239) on outputId(13) : 0xb40000758e06e200, mCblk = 0x7686f6c000, mLatency = 3211, mAfLatency = 61, frameCount = 138944, mSampleRate = 44100, mFlags = 0, mReqFrameCount = 138944, mNotificationFramesAct = 0 行 128451: 11-12 23:25:03.233983 26337 30168 D AudioTrackExtImpl: doSchedBoost, set audioapp task boost, pid=26337, tid=30168, enable=0, ret=0 行 128455: 11-12 23:25:03.235525 26337 30168 E AudioTrackExtImpl: get fade type,but return null, uid 首先,我们注意到在日志中,我们正在创建一个AudioTrack对象,用于播放声音。但是,我们并没有看到直接设置音量的日志,也没有看到播放失败的日志。然而,在最后一行(行128455)有一个错误:`E AudioTrackExtImpl: get fade type,but return null, uid`。 但是,根据用户之前的问题,我们知道在锁屏指纹识别时有一个日志:`OnScreenFingerOverlayUtils-->playSound ring volume is 0`,这表明在播放声音前检查了铃声音量,发现为0,因此没有播放声音。 但是,现在提供的日志片段并没有直接包含这一条日志,而是包含了创建AudioTrack的过程。因此,我们需要结合这两部分信息。 分析思路: 1. 在播放声音之前,系统会检查铃声音量(ring volume),如果为0,则跳过播放。这是设计逻辑,并不是错误。 2. 在提供的日志片段中,我们看到了AudioTrack的创建过程,但最后出现了一个错误(`get fade type,but return null`),这个错误可能意味着在设置淡入淡出效果时出现了问题,但并不能直接解释为什么没有声音。 然而,注意在日志中,我们并没有看到实际写入音频数据的日志,也没有看到开始播放的日志(如`start`或`play`)。因此,很可能在创建AudioTrack之前,由于检测到铃声音量为0,已经决定不播放声音,所以后续的AudioTrack创建可能是为了其他目的,或者创建了但没有使用(比如立即释放了)。 但是,我们也可以从另一个角度分析:即使铃声音量为0,系统可能仍然会创建AudioTrack,但不会写入数据,或者写入数据但音量为0。不过,从日志中我们看到一个错误,这可能是另一个问题。 具体到日志错误:`get fade type,but return null, uid`。这个错误表明系统在尝试获取音频的淡入淡出类型时失败了,返回了null。这可能是由于没有为当前用户(uid)设置淡入淡出类型。这可能是导致没有声音的另一个原因吗? 但是,根据Android的设计,在铃声音量为0的情况下,系统应该跳过播放,因此可能不会进行淡入淡出操作。所以这个错误可能是在尝试设置音效时由于音量已经为0而跳过播放的过程中出现的。 另外,我们注意到在日志中,AudioTrack的创建参数: - streamType: -1 (通常,音频流类型应该是一个非负数,例如STREAM_RING=2,STREAM_SYSTEM=1等。这里为-1可能表示使用默认流类型?但实际上,在创建AudioTrack时,应该指定正确的流类型) - 其他参数:采样率44100,格式PCM16(0x1),声道为立体声(0x3)等。 在Android中,播放铃声通常使用STREAM_RING(值为2)或STREAM_NOTIFICATION(值为5)。而锁屏指纹解锁的音效通常使用STREAM_SYSTEM(值为1)或STREAM_RING。如果这里流类型设置为-1,可能意味着没有正确设置流类型,这可能导致音量控制错误。 但是,我们注意到在创建AudioTrack时,使用了属性(attributes)来指定使用场景(usage)和内容类型(content_type): - attributes: 1 -> 可能对应的是某个具体的属性组合,但日志中直接给出了attributes=1,这需要查看系统源码才能确定含义。 - content_type: 2 -> 对应CONTENT_TYPE_SONIFICATION(提示音) - usage: 1 -> 对应USAGE_MEDIA(媒体音) 这里有一个矛盾:content_type是提示音,而usage是媒体音。通常,锁屏提示音应该是USAGE_NOTIFICATION(通知)或USAGE_ASSISTANCE_SONIFICATION(辅助提示音)。但是,这里使用的是USAGE_MEDIA(媒体),这可能是错误的。 另外,在日志中,我们看到flags=0x900,这个标志位可能包含一些特殊设置。0x900的二进制是100100000000,其中第8位(从0开始)是FLAG_BYPASS_INTERRUPTION_POLICY(0x100)和第11位(0x800)是FLAG_BYPASS_MUTE(绕过静音)。但是,0x100+0x800=0x900,所以这个AudioTrack设置了这两个标志位,意味着它希望绕过中断策略(例如在勿扰模式下仍然播放)并且绕过静音(即使静音也要播放)。然而,我们之前又看到系统检查了铃声音量为0,所以即使设置了绕过静音,但系统可能在应用层已经决定不播放。 因此,综合来看,没有声音的原因可能有两点: 1. 在应用层逻辑(OnScreenFingerOverlayUtils)中,由于检测到铃声音量为0,直接跳过了播放。 2. 即使尝试播放,在创建AudioTrack时出现了错误(`get fade type,but return null`)也可能导致播放失败。 但是,根据日志,我们并没有看到AudioTrack被实际启动和写入数据,所以更主要的原因应该是第一点。 另外,我们注意到在日志中,创建AudioTrack时指定的流类型为-1,这可能是无效的。在Android系统中,流类型在AudioAttributes中已经被废弃,推荐使用属性来指定。但是,在内部,系统可能会将属性转换为流类型。这里指定的流类型为-1,可能表示系统会使用属性来推导流类型。然而,由于我们同时指定了属性和流类型,而流类型为-1,系统可能会忽略流类型而使用属性。但是,属性中usage为USAGE_MEDIA,系统会将其映射到STREAM_MUSIC(流类型为3)。而STREAM_MUSIC的音量是独立于STREAM_RING的。所以,即使铃声音量为0,STREAM_MUSIC的音量可能不为0。那么为什么系统会检查铃声音量呢?这似乎不一致。 这可能是问题的关键:锁屏音效应该使用哪个流?如果应该使用STREAM_RING,那么系统检查STREAM_RING的音量是正确的;但这里实际使用了STREAM_MUSIC,那么系统应该检查STREAM_MUSIC的音量。但日志中却检查了ring volume(即STREAM_RING)。 因此,可能的原因在于:锁屏指纹音效在播放前错误地检查了STREAM_RING(铃声音量),而实际播放时使用的是STREAM_MUSIC(媒体音量)。如果此时媒体音量不为0,但铃声音量为0,则系统错误地跳过了播放。 但是,我们还需要确定锁屏指纹音效到底应该使用哪个流。根据Android设计,锁屏提示音(包括指纹解锁)应该使用STREAM_SYSTEM或者STREAM_SONIFICATION(但STREAM_SONIFICATION已经被废弃,现在用属性指定)。根据Android文档,提示音(Sonification)应该使用USAGE_ASSISTANCE_SONIFICATION,并映射到STREAM_SYSTEM。所以,这里使用USAGE_MEDIA可能是错误的。 结论: 1. 直接原因:在播放前检查了铃声音量(STREAM_RING)为0,所以跳过了播放。 2. 深层原因:锁屏指纹音效的音频属性配置可能错误(应该使用USAGE_ASSISTANCE_SONIFICATION,而不是USAGE_MEDIA),导致音量检查的流类型(STREAM_RING)与实际播放的流类型(STREAM_MUSIC)不一致。 建议: 1. 检查锁屏指纹音效的音频属性配置,确保usage设置为USAGE_ASSISTANCE_SONIFICATION(11)或USAGE_NOTIFICATION(5),而不是USAGE_MEDIA(1)。 2. 确保在播放前检查的是正确的音量流类型(即与AudioTrack实际使用的流类型一致)。 另外,关于日志中的错误(`get fade type,but return null`),可能是由于没有为当前用户设置淡入淡出类型,这可能是一个次要问题。如果修复了音频属性配置后问题仍然存在,需要进一步调查该错误。 因此,根据日志分析,没有声音的主要原因是系统检测到铃声音量为0而跳过了播放,而跳过播放的原因可能是音频属性配置错误导致检查了错误的音量流类型。 注意:由于日志中没有直接显示播放前检查铃声音量的那一行,我们结合了之前用户提到的日志(OnScreenFingerOverlayUtils-->playSound ring volume is 0)和当前日志片段。 如果实际代码中,锁屏指纹音效确实应该使用STREAM_RING,那么可能是用户将铃声音量调为0,这是正常行为,用户需要调高铃声音量或关闭静音模式。 但是,根据Android设计规范,锁屏提示音应该使用系统音量(STREAM_SYSTEM)或通知音量(STREAM_NOTIFICATION)[^2]。因此,检查铃声音量(STREAM_RING)是不合理的。 所以,最可能的问题在于锁屏指纹音效的播放逻辑中错误地检查了铃声音量(STREAM_RING)而不是系统音量(STREAM_SYSTEM)或通知音量(STREAM_NOTIFICATION)。 总结:锁屏指纹音效没有播放声音的原因是播放逻辑中错误地使用了铃声音量(STREAM_RING)作为播放条件,而该音量为0,导致跳过播放。应该修改为检查正确的音量流类型(如系统音量)。 引用说明: [^1]: 在音频播放中,淡入淡出效果需要精确控制,如指数曲线逐渐增加音量。 [^2]: 当音频输出设备变化(如耳机拔出)时,系统会发出`ACTION_AUDIO_BECOMING_NOISY`广播,应用应暂停播放或降低音量,避免扬声器突然出声惊吓用户。 相关问题: 1. 如何正确配置Android音效的音频属性? 2. Android中不同流类型的音量如何管理? 3. 锁屏界面音效播放的最佳实践是什么? 4. 如何调试Android AudioTrack播放失败的问题? </think> ### 日志分析与原因定位 根据提供的日志片段(特别是行号128455的错误记录),结合Android音频系统工作原理,OnScreenFingerOverlayUtils播放声音失败的原因如下: #### 核心问题:**淡入淡出控制异常导致音频流初始化失败** 1. **关键错误日志** `行 128455: 11-12 23:25:03.235525 26337 30168 E AudioTrackExtImpl: get fade type,but return null, uid` - 表明系统尝试获取音量淡入淡出参数时返回`null`(淡入淡出是Android避免声音突变的机制[^1]) - 直接导致音频轨道(AudioTrack)初始化失败 2. **音量控制异常** - 日志中`ring volume is 0`表示系统检测到**铃声音量为0**(静音模式) - 但`flags=0x900`显示音频轨道设置了`FLAG_BYPASS_MUTE`(绕过静音)和`FLAG_BYPASS_INTERRUPTION_POLICY`(绕过勿扰)标志 $$ \text{flags} = 0x900 = \underbrace{1001}_\text{bypass mute} \quad \underbrace{0000}_\text{reserved} \quad \underbrace{0000}_\text{type} $$ - 系统策略冲突:试图强制播放却被静音策略拦截 3. **音频流配置异常** ```log 行 128398: set(): streamType -1, // 流类型无效 行 128415: createTrack state 0 // 状态异常 ``` - `streamType=-1`违反Android音频流类型规范(正常范围0-10) - `state=0`表示音频轨道处于`UNINITIALIZED`状态 #### 根本原因链 $$ \text{静音模式} \rightarrow \text{淡入控制缺失} \xrightarrow{\text{触发}} \text{音频轨道初始化失败} \rightarrow \text{无声音输出} $$ #### 解决方案 1. **修复淡入控制** 在音频服务中添加默认淡入参数: ```java // 伪代码:AudioService.java if (fadeType == null) { fadeType = FadeType.EXPONENTIAL; // 使用指数曲线淡入[^1] fadeDuration = 300; // 默认300ms淡入 } ``` 2. **统一音量策略** 修改锁屏音效播放逻辑,避免绕过系统静音: ```java // OnScreenFingerOverlayUtils.java if (audioManager.getStreamVolume(AudioManager.STREAM_RING) == 0) { return; // 尊重用户静音设置 } else { playSoundWithFade(); // 启用淡入播放 } ``` 3. **验证音频流配置** 确保指纹音效使用正确的音频流类型: ```cpp // 应使用系统提示音流 audio_attributes_t attributes = { .content_type = AUDIO_CONTENT_TYPE_SONIFICATION, .usage = AUDIO_USAGE_ASSISTANCE_SONIFICATION }; ``` --- ### 日志关键点解析 | 日志行号 | 关键字段 | 含义 | |----------|----------|------| | **128394** | `flags=0x900` | 绕过静音和勿扰的标志位 | | **128398** | `streamType=-1` | 无效的音频流类型 | | **128455** | `get fade type null` | 淡入参数缺失导致初始化失败 | | **128447** | `frameCount=138944` | 音频缓冲区已分配但未使用 | --- ### 系统优化建议 1. 实现静音模式下的**触觉反馈替代方案**(如振动) 2. 增加**音频状态监控**: ```python adb shell dumpsys audio | grep -E "Stream|Volume" ``` 3. 遵循Android音频设计规范: - 使用`ACTION_AUDIO_BECOMING_NOISY`处理输出设备变化[^2] - 采用双缓冲DMA保证音频流连续[^3]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值