首页 > 解决方案 > 具有剪辑/编辑功能的 Flutter Audioplayers,如 Just_ Audio player

问题描述

每当我在颤振应用程序中录制音频时,由于点击手机上的开始和停止按钮,剪辑的开头和结尾都会出现噪音。Flutter 的Just-Audio插件有一个编辑/剪辑功能,可以消除这些噪音。IE:

  await player.setClip(start: Duration(seconds: 10), end: Duration(seconds: 20));

但不幸的是,该Just-Audio插件在我的应用程序中无法正常运行。我有一个滑动浏览量,每个页面都有它自己的播放器。Just-Audio 似乎不喜欢这样,并且表现得好像每个刷过的页面都是同一个播放器。

所以我正在使用Audioplayers允许多个玩家的插件。但是 Audioplayer 插件没有该插件所具有的 Clip/Edit 功能Just-Audio。那么任何人都可以看到我可以在Audioplayers插件中获得相同的剪辑/编辑功能吗?

这是Just Player插件的功能;

Future<Duration?> setClip({Duration? start, Duration? end}) async {
    if (_disposed) return null;
    _setPlatformActive(true)?.catchError((dynamic e) {});
    final duration = await _load(
        await _platform,
        start == null && end == null
            ? _audioSource!
            : ClippingAudioSource(
                child: _audioSource as UriAudioSource,
                start: start,
                end: end,
              ));
    return duration;
  }

这是插件的小部件Audioplayers

import 'dart:async';
import 'package:audioplayers/audioplayers.dart';
import 'package:audioplayers/notifications.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

    class PlayerWidget extends StatefulWidget {
      final String url;
      final PlayerMode mode;
    
      const PlayerWidget({
        Key? key,
        required this.url,
        this.mode = PlayerMode.MEDIA_PLAYER,
      }) : super(key: key);
    
      @override
      State<StatefulWidget> createState() {
        return _PlayerWidgetState(url, mode);
      }
    }
    
    class _PlayerWidgetState extends State<PlayerWidget> {
      String url;
      PlayerMode mode;
    
      late AudioPlayer _audioPlayer;
      PlayerState? _audioPlayerState;
      Duration? _duration;
      Duration? _position;
    
      PlayerState _playerState = PlayerState.STOPPED;
      PlayingRoute _playingRouteState = PlayingRoute.SPEAKERS;
      StreamSubscription? _durationSubscription;
      StreamSubscription? _positionSubscription;
      StreamSubscription? _playerCompleteSubscription;
      StreamSubscription? _playerErrorSubscription;
      StreamSubscription? _playerStateSubscription;
      StreamSubscription<PlayerControlCommand>? _playerControlCommandSubscription;
    
      bool get _isPlaying => _playerState == PlayerState.PLAYING;
      bool get _isPaused => _playerState == PlayerState.PAUSED;
      String get _durationText => _duration?.toString().split('.').first ?? '';
      String get _positionText => _position?.toString().split('.').first ?? '';
    
      bool get _isPlayingThroughEarpiece =>
          _playingRouteState == PlayingRoute.EARPIECE;
    
      _PlayerWidgetState(this.url, this.mode);
    
      @override
      void initState() {
        super.initState();
        _initAudioPlayer();
      }
    
      @override
      void dispose() {
        _audioPlayer.dispose();
        _durationSubscription?.cancel();
        _positionSubscription?.cancel();
        _playerCompleteSubscription?.cancel();
        _playerErrorSubscription?.cancel();
        _playerStateSubscription?.cancel();
        _playerControlCommandSubscription?.cancel();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            Row(
              mainAxisSize: MainAxisSize.min,
              children: [
                IconButton(
                  key: const Key('play_button'),
                  onPressed: _isPlaying ? null : _play,
                  iconSize: 64.0,
                  icon: const Icon(Icons.play_arrow),
                  color: Colors.cyan,
                ),
                IconButton(
                  key: const Key('pause_button'),
                  onPressed: _isPlaying ? _pause : null,
                  iconSize: 64.0,
                  icon: const Icon(Icons.pause),
                  color: Colors.cyan,
                ),
                IconButton(
                  key: const Key('stop_button'),
                  onPressed: _isPlaying || _isPaused ? _stop : null,
                  iconSize: 64.0,
                  icon: const Icon(Icons.stop),
                  color: Colors.cyan,
                ),
                IconButton(
                  onPressed: _earpieceOrSpeakersToggle,
                  iconSize: 64.0,
                  icon: _isPlayingThroughEarpiece
                      ? const Icon(Icons.volume_up)
                      : const Icon(Icons.hearing),
                  color: Colors.cyan,
                ),
              ],
            ),
            Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Padding(
                  padding: const EdgeInsets.all(12.0),
                  child: Stack(
                    children: [
                      Slider(
                        onChanged: (v) {
                          final Position = v * _duration!.inMilliseconds;
                          _audioPlayer
                              .seek(Duration(milliseconds: Position.round()));
                        },
                        value: (_position != null &&
                                _duration != null &&
                                _position!.inMilliseconds > 0 &&
                                _position!.inMilliseconds <
                                    _duration!.inMilliseconds)
                            ? _position!.inMilliseconds / _duration!.inMilliseconds
                            : 0.0,
                      ),
                    ],
                  ),
                ),
                Text(
                  _position != null
                      ? '$_positionText / $_durationText'
                      : _duration != null
                          ? _durationText
                          : '',
                  style: const TextStyle(fontSize: 24.0),
                ),
              ],
            ),
            Text('State: $_audioPlayerState'),
          ],
        );
      }
    
      void _initAudioPlayer() {
        _audioPlayer = AudioPlayer(mode: mode);
    
        _durationSubscription = _audioPlayer.onDurationChanged.listen((duration) {
          setState(() => _duration = duration);
    
          if (Theme.of(context).platform == TargetPlatform.iOS) {
            // optional: listen for notification updates in the background
            _audioPlayer.notificationService.startHeadlessService();
    
            // set at least title to see the notification bar on ios.
            _audioPlayer.notificationService.setNotification(
              title: 'App Name',
              artist: 'Artist or blank',
              albumTitle: 'Name or blank',
              imageUrl: 'Image URL or blank',
              forwardSkipInterval: const Duration(seconds: 30), // default is 30s
              backwardSkipInterval: const Duration(seconds: 30), // default is 30s
              duration: duration,
              enableNextTrackButton: true,
              enablePreviousTrackButton: true,
            );
          }
        });
    
        _positionSubscription =
            _audioPlayer.onAudioPositionChanged.listen((p) => setState(() {
                  _position = p;
                }));
    
        _playerCompleteSubscription =
            _audioPlayer.onPlayerCompletion.listen((event) {
          _onComplete();
          setState(() {
            _position = _duration;
          });
        });
    
        _playerErrorSubscription = _audioPlayer.onPlayerError.listen((msg) {
          print('audioPlayer error : $msg');
          setState(() {
            _playerState = PlayerState.STOPPED;
            _duration = const Duration();
            _position = const Duration();
          });
        });
    
        _playerControlCommandSubscription =
            _audioPlayer.notificationService.onPlayerCommand.listen((command) {
          print('command: $command');
        });
    
        _audioPlayer.onPlayerStateChanged.listen((state) {
          if (mounted) {
            setState(() {
              _audioPlayerState = state;
            });
          }
        });
    
        _audioPlayer.onNotificationPlayerStateChanged.listen((state) {
          if (mounted) {
            setState(() => _audioPlayerState = state);
          }
        });
    
        _playingRouteState = PlayingRoute.SPEAKERS;
      }
    
      Future<int> _play() async {
        final playPosition = (_position != null &&
                _duration != null &&
                _position!.inMilliseconds > 0 &&
                _position!.inMilliseconds < _duration!.inMilliseconds)
            ? _position
            : null;
        final result = await _audioPlayer.play(url, position: playPosition);
        if (result == 1) {
          setState(() => _playerState = PlayerState.PLAYING);
        }
    
        // default playback rate is 1.0
        // this should be called after _audioPlayer.play() or _audioPlayer.resume()
        // this can also be called everytime the user wants to change playback rate in the UI
        _audioPlayer.setPlaybackRate();
    
        return result;
      }
    
      Future<int> _pause() async {
        final result = await _audioPlayer.pause();
        if (result == 1) {
          setState(() => _playerState = PlayerState.PAUSED);
        }
        return result;
      }
    
      Future<int> _earpieceOrSpeakersToggle() async {
        final result = await _audioPlayer.earpieceOrSpeakersToggle();
        if (result == 1) {
          setState(() => _playingRouteState = _playingRouteState.toggle());
        }
        return result;
      }
    
      Future<int> _stop() async {
        final result = await _audioPlayer.stop();
        if (result == 1) {
          setState(() {
            _playerState = PlayerState.STOPPED;
            _position = const Duration();
          });
        }
        return result;
      }
    
      void _onComplete() {
        setState(() => _playerState = PlayerState.STOPPED);
      }
    }

标签: flutterdartaudio-playerjust-audio

解决方案


推荐阅读