如何在Flutter中使用audio_service调整音频音量
如何在audio_service中调整音频音量
我想知道怎么用audio_service包调整音频音量,在AudioHandler类里没找到对应的方法。比如怎么通过Flutter UI的按钮调整音量,或者用5秒左右的时间逐步改变音量实现淡入淡出?用just_audio的setVolume很容易做到,但不知道怎么和audio_service集成。
解决方案
你的MyAudioHandler已经持有了AudioPlayer实例,只需要在MyAudioHandler中封装音量控制方法,再在UI层调用这些方法即可。
步骤1:在MyAudioHandler中添加音量控制逻辑
修改你的MyAudioHandler类,添加设置音量、获取当前音量的方法,同时封装淡入淡出的实现:
import 'package:rxdart/rxdart.dart'; class MyAudioHandler extends BaseAudioHandler { final _player = AudioPlayer(); // 用Stream同步音量变化,方便UI实时更新 final _volumeSubject = BehaviorSubject<double>.seeded(1.0); Stream<double> get volumeStream => _volumeSubject.stream; MyAudioHandler() { _player.playbackEventStream.map(updatePlaybackState).pipe(playbackState); _volumeSubject.add(_player.volume); } // 设置音量(范围0.0-1.0,自动限制边界) Future<void> setVolume(double volume) async { final clampedVolume = volume.clamp(0.0, 1.0); await _player.setVolume(clampedVolume); _volumeSubject.add(clampedVolume); } // 获取当前音量 double get currentVolume => _player.volume; // 淡入淡出效果:duration为总时长,targetVolume为目标音量 Future<void> fadeVolume(double targetVolume, Duration duration) async { const steps = 20; // 分多步调整避免卡顿 final stepDuration = duration ~/ steps; final volumeStep = (targetVolume - currentVolume) / steps; for (int i = 0; i < steps; i++) { await Future.delayed(stepDuration); await setVolume(currentVolume + volumeStep * (i + 1)); } // 确保最终精确设置到目标值 await setVolume(targetVolume); } // 原有方法保持不变 @override Future<void> play() async { await _player.play(); return super.play(); } @override Future<void> playMediaItem(MediaItem item) async { mediaItem.add(item); _player.setAudioSource(AudioSource.asset(item.id)); await _player.play(); return super.playMediaItem(item); } @override Future<void> stop() async { await _player.stop(); } PlaybackState updatePlaybackState(PlaybackEvent event) { return PlaybackState( processingState: const { ProcessingState.idle: AudioProcessingState.idle, ProcessingState.loading: AudioProcessingState.loading, ProcessingState.buffering: AudioProcessingState.buffering, ProcessingState.ready: AudioProcessingState.ready, ProcessingState.completed: AudioProcessingState.completed, }[_player.processingState]!, playing: _player.playing, updatePosition: _player.position, repeatMode: AudioServiceRepeatMode.all ); } // 释放资源 @override Future<void> dispose() async { await _volumeSubject.close(); await _player.dispose(); super.dispose(); } }
步骤2:在UI中调用音量控制方法
修改UI代码,给加减按钮添加点击事件,还可以增加淡入淡出的控制按钮:
return Scaffold( body: StreamBuilder<PlaybackState>( stream: _audioHandler.playbackState, builder: (context, snapshot) { bool isPlaying = snapshot.data?.playing ?? false; return Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ if (isPlaying) ElevatedButton( onPressed: () { _audioHandler.stop(); }, child: const Text('Stop'), ) else ...[ ElevatedButton( onPressed: () async { const item = MediaItem( title: 'Sea', id: 'assets/audio/seaside.mp3', ); // 播放前先设音量为0,然后淡入到1.0(5秒) await _audioHandler.setVolume(0.0); await _audioHandler.playMediaItem(item); await _audioHandler.fadeVolume(1.0, const Duration(seconds: 5)); }, child: const Text('Play Seaside (淡入)'), ), ], const SizedBox(height: 20), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ IconButton( onPressed: () async { // 每次增加0.1音量 await _audioHandler.setVolume(_audioHandler.currentVolume + 0.1); }, icon: const Icon(Icons.add), ), // 实时显示当前音量百分比 StreamBuilder<double>( stream: _audioHandler.volumeStream, initialData: 1.0, builder: (context, snapshot) { return Text('${(snapshot.data! * 100).round()}%'); }, ), IconButton( onPressed: () async { // 每次减少0.1音量 await _audioHandler.setVolume(_audioHandler.currentVolume - 0.1); }, icon: const Icon(Icons.remove), ), ], ), const SizedBox(height: 20), // 淡出后停止的按钮 if (isPlaying) ElevatedButton( onPressed: () async { await _audioHandler.fadeVolume(0.0, const Duration(seconds: 5)); await _audioHandler.stop(); }, child: const Text('淡出停止'), ), ], ); }), );
核心说明
- 利用
MyAudioHandler内部的AudioPlayer实例直接调用setVolume,封装成对外方法后,UI层可以通过AudioHandler直接控制音量。 - 淡入淡出通过分步骤调整音量+延迟实现,避免音量突变带来的突兀感。
- 用
BehaviorSubject维护音量流,让UI可以实时同步显示当前音量值。
内容的提问来源于stack exchange,提问作者Kdon
相关产品推荐
相关产品推荐

