如何在audio_service flutter中传递和播放播放列表中特定队列位置的媒体项目?

2023-12-15

我正在使用颤动音频服务 and 只是音频音乐播放器包。我想在初始化音乐播放器时播放播放列表中特定队列位置的媒体项目。当我调用 AudioService.start() 方法时,它始终播放播放列表的第一项。当我启动音频服务时,如何传递并播放播放列表中特定队列位置的媒体项目?

音频服务启动

AudioService.start(
        backgroundTaskEntrypoint: _audioPlayerTaskEntrypoint,
        androidNotificationChannelName: 'Zenmind',
        androidNotificationColor: 0xFF2196f3,
        androidNotificationIcon: 'mipmap/ic_launcher',
        androidEnableQueue: true,
        params: params); // [params contains playlist ] 

_audioPlayerTaskEntrypoint代码

void _audioPlayerTaskEntrypoint() async {
  AudioServiceBackground.run(() => AudioPlayerTask());
}

AudioPlayerTask类

class AudioPlayerTask extends BackgroundAudioTask {
  var _queue = <MediaItem>[];
  AudioPlayer _player = new AudioPlayer();
  AudioProcessingState _skipState;
  Seeker _seeker;
  StreamSubscription<PlaybackEvent> _eventSubscription;

  List<MediaItem> get queue => _queue;
  int get index => _player.currentIndex;
  MediaItem get mediaItem => index == null ? null : queue[index];

  @override
  Future<void> onStart(Map<String, dynamic> params) async {
    _queue.clear();
    List mediaItems = params['data'];
    // print(params['data']);
    for (int i = 0; i < mediaItems.length; i++) {
      MediaItem mediaItem = MediaItem.fromJson(mediaItems[i]);
      _queue.add(mediaItem);
    }

    _player.currentIndexStream.listen((index) {
      print("index value is $index");
      if (index != null) {
        AudioServiceBackground.setMediaItem(queue[index]);
      }
    });
    _eventSubscription = _player.playbackEventStream.listen((event) {
      _broadcastState();
    });

    _player.processingStateStream.listen((state) {
      switch (state) {
        case ProcessingState.completed:
          onStop();
          break;
        case ProcessingState.ready:
          _skipState = null;
          break;
        default:
          break;
      }
    });

    AudioServiceBackground.setQueue(queue);
    try {
      await _player.setAudioSource(ConcatenatingAudioSource(
        children:
            queue.map((item) => AudioSource.uri(Uri.parse(item.id))).toList(),
      ));
      onSkipToQueueItem(queue[1].id);
      onPlay();
    } catch (e) {
      print("Error: $e");
      onStop();
    }
  }

  @override
  Future<void> onSkipToQueueItem(String mediaId) async {
    final newIndex = queue.indexWhere((item) => item.id == mediaId);
    if (newIndex == -1) return;
    _skipState = newIndex > index
        ? AudioProcessingState.skippingToNext
        : AudioProcessingState.skippingToPrevious;
    _player.seek(Duration.zero, index: newIndex);
    AudioServiceBackground.sendCustomEvent('skip to $newIndex');
  }

  @override
  Future<void> onPlay() => _player.play();

  @override
  Future<void> onPause() => _player.pause();

  @override
  Future<void> onSeekTo(Duration position) => _player.seek(position);

  @override
  Future<void> onFastForward() => _seekRelative(fastForwardInterval);

  @override
  Future<void> onRewind() => _seekRelative(-rewindInterval);

  @override
  Future<void> onSeekForward(bool begin) async => _seekContinuously(begin, 1);

  @override
  Future<void> onSeekBackward(bool begin) async => _seekContinuously(begin, -1);

  @override
  Future<void> onStop() async {
    await _player.dispose();
    _eventSubscription.cancel();
    await _broadcastState();
    await super.onStop();
  }

  Future<void> _seekRelative(Duration offset) async {
    var newPosition = _player.position + offset;
    if (newPosition < Duration.zero) newPosition = Duration.zero;
    if (newPosition > mediaItem.duration) newPosition = mediaItem.duration;
    // if (newPosition > _player.duration) newPosition = _player.duration;
    await _player.seek(newPosition);
  }

  void _seekContinuously(bool begin, int direction) {
    _seeker?.stop();
    if (begin) {
      _seeker = Seeker(
          _player,
          Duration(seconds: 10 * direction),
          // Duration(seconds: 1), mediaItem)
          Duration(seconds: 1),
          queue[_player.currentIndex])
        ..start();
    }
  }

  Future<void> _broadcastState() async {
    await AudioServiceBackground.setState(
      controls: [
        MediaControl.skipToPrevious,
        if (_player.playing) MediaControl.pause else MediaControl.play,
        MediaControl.stop,
        MediaControl.skipToNext,
      ],
      systemActions: [
        MediaAction.seekTo,
        MediaAction.seekForward,
        MediaAction.seekBackward,
      ],
      androidCompactActions: [0, 1, 3],
      processingState: _getProcessingState(),
      playing: _player.playing,
      position: _player.position,
      bufferedPosition: _player.bufferedPosition,
      speed: _player.speed,
    );
  }

  AudioProcessingState _getProcessingState() {
    if (_skipState != null) return _skipState;
    switch (_player.processingState) {
      case ProcessingState.idle:
        return AudioProcessingState.stopped;
      case ProcessingState.loading:
        return AudioProcessingState.connecting;
      case ProcessingState.buffering:
        return AudioProcessingState.buffering;
      case ProcessingState.ready:
        return AudioProcessingState.ready;
      case ProcessingState.completed:
        return AudioProcessingState.completed;
      default:
        throw Exception("Invalid state: ${_player.processingState}");
    }
  }
}

在audio_service 0.17中,params传递到start()仅适用于简单数据类型,不适用于列表MediaItems。事实上,API 中还有其他专门为此设计的方法。

我建议改为以下启动顺序:

// Set the playlist
await AudioService.updateQueue(playlist);
// Jump to the right item
await AudioService.skipToQueueItem(...);
// Play
AudioService.play(); // don't await!

注意:更换AudioService. by audioHandler.如果您使用0.18.0或更高版本。

The await上面的关键词很重要。这些方法是异步的,在前面的方法完成之前不应调用后面的方法。例如,您不想跳到特定队列项目,直到after队列实际上已设置。但请注意缺乏await在最后一步:你不需要等待play除非您想等待播放完成,否则请调用。

在后台音频任务 (0.17) 或音频处理程序 (0.18) 中,添加回调updateQueue:

// 0.17 solution:
Future<void> onUpdateQueue(List<MediaItem> queue) async {
  AudioServiceBackground.setQueue(_queue = queue);
  await _player.setAudioSource(ConcatenatingAudioSource(
    children:
        queue.map((item) => AudioSource.uri(Uri.parse(item.id))).toList(),
));
// 0.18 solution:
Future<void> updateQueue(List<MediaItem> queue) async {
  this.queue.add(_queue = queue);
  await _player.setAudioSource(ConcatenatingAudioSource(
    children:
        queue.map((item) => AudioSource.uri(Uri.parse(item.id))).toList(),
));
}

你已经有一个onStart,但请记住,使用上面建议的启动顺序,队列将在后面的步骤中设置,并且播放器将在后面的步骤中跳到正确的队列项目,因此您可以从您的onStart,并只保留初始化事件侦听器的代码。 (在 0.18 中,该逻辑将进入您的音频处理程序构造函数)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在audio_service flutter中传递和播放播放列表中特定队列位置的媒体项目? 的相关文章

随机推荐

  • Swift 可选 - 不同的解包方式

    我就直接说吧 有什么区别 var test String test this is an optional string if test nil println test IS NOT nil else println test is ni
  • 如何定义一个可以有多种形式的javascript属性?

    例如 IE 表格控件可以按如下方式使用 recordset fields i name recordset fields count 如何使用 javascript 定义 fields 属性 当我定义 this fields new Fie
  • iOS如何实现协议的@property

    我的理解是 协议指定方法名称 而符合该协议的其他人则负责方法的实现 那么协议中声明的属性又如何呢 实现一个属性是否意味着实现它的setter和getter 属性是一个或两个具有特定签名的方法的奇特名称 Objective C 为其提供了一个
  • 如何更改 Xamarin 表单中的 Picker 字体颜色和大小?

    我是 Xamarin 新手 目前正在 Xamarin Forms PCL 中做一个项目 有没有办法改变Picker的字体颜色和大小
  • 确定哪个依赖数组变量导致 useEffect 钩子触发

    有没有一种简单的方法可以确定a中的哪个变量useEffect的依赖数组触发函数重新触发 简单地注销每个变量可能会产生误导 如果a是一个函数并且b是一个对象 它们在记录时可能看起来相同 但实际上不同并导致 useEffect 火灾 例如 Re
  • 堆溢出的危险?

    我有一个关于堆溢出的问题 据我所知 如果堆栈变量超出其缓冲区 它可能会覆盖 EIP 和 ESP 值 例如 使程序跳转到编码器不希望它跳转的位置 据我了解 由于向后小端存储 其中数组中的字符 向后 存储 从最后到第一个 这似乎表现得像这样 另
  • PHP中的CSRF(跨站请求伪造)攻击示例及预防

    我有一个网站 人们可以这样投票 http mysite com vote 25 这将对第 25 项进行投票 我只想将此功能提供给注册用户 并且仅当他们愿意时才提供 现在我知道当有人在网站上忙碌时 有人给他们一个像这样的链接 http mys
  • 如何将 arrayList.toString() 转换为实际的 arraylist

    在我的软件中 由于没有Array数据类型输入SQLite 我保存了我的ArrayList as a String 现在我需要使用我的数组并希望将其转换回 ArrayList 我该怎么做 这里有一个例子 ArrayList
  • 如何使用谷歌地图V2在android中使用MapView?

    我想在我的活动中显示地图 在谷歌地图 V1 中我们使用
  • 使用 CSS 制作 Google API 地图标记动画? [关闭]

    Closed 这个问题需要多问focused 目前不接受答案 http bluefaqs com 2016 02 how to animate a map location marker with css 显示脉动的 GPS 位置蓝点 位于
  • SQL 点表示法

    有人可以向我解释一下 SQL Server 如何使用点表示法来识别桌子的位置 我一直以为地点是Database dbo Table但我看到代码中有其他东西代替dbo 就像是 DBName something Table有人可以解释一下吗 这
  • 在 Mac 上使用 Selenium WebDriver 在 Firefox 中打开新选项卡

    我刚刚安装了 Selenium Web Driver 并尝试了一下 效果很好 我的用例可以描述如下 在具有伪 X 服务器 Xvfb 的服务器上启动 Firefox 新的 Driver Firefox 对象 打开 10 个选项卡并在每个选项卡
  • upload_max_filesize、php.ini 和 Google App Engine

    我有一个在 Google App Engine 上运行的 PHP 5 5 应用程序 它基于 CodeIgniter 框架 最近我开始需要上传超过 8 MB 的文件 我收到以下错误 PHP Warning POST Content Lengt
  • 将 LocalDate 转换为 LocalDateTime 或 java.sql.Timestamp

    我正在使用 JodaTime 1 6 2 我有一个LocalDate我需要转换为 Joda LocalDateTime or a java sqlTimestamp用于或映射 这样做的原因是我已经弄清楚如何在LocalDateTime an
  • 比较 2 个 JSON 对象 [重复]

    这个问题在这里已经有答案了 可能的重复 JavaScript 中的对象比较 是否有任何方法可以接受 2 个 JSON 对象并比较这两个对象以查看是否有任何数据发生更改 Edit 审查完评论后 需要进行一些澄清 JSON 对象定义为 一组无序
  • Flask 在请求之前获取 url 变量?

    在 Flask 中 我有带有变量的 url 规则 例如 my blueprint add url rule
  • 为 iOS 7 编译 x264

    我在为 iOS 编译 x264 时遇到错误 我有 Xcode 版本 5 0 5A1413 和 Apple LLVM 版本 5 0 clang 500 2 75 基于 LLVM 3 3svn 我正在编译 x264 snapshot 20130
  • PHPhotoLibrary 保存 gif 数据

    我在新的 PHPhotoLibrary 中找不到与 ALAssetsLibrary gt writeImageDataToSavedPhotosAlbum 类似的方法 因为 ALAssetsLibrary 在 iOS 9 中已弃用 我无法保
  • 组合 git `continue` 命令

    我可能需要以不同的方式运行 git rebase continue git cherry pick continue git revert continue 在每种情况下 我的命令行都会提醒我 我正处于中间状态 rebase cp reve
  • 如何在audio_service flutter中传递和播放播放列表中特定队列位置的媒体项目?

    我正在使用颤动音频服务 and 只是音频音乐播放器包 我想在初始化音乐播放器时播放播放列表中特定队列位置的媒体项目 当我调用 AudioService start 方法时 它始终播放播放列表的第一项 当我启动音频服务时 如何传递并播放播放列