我想查看一个如何向音频服务添加自定义队列的示例。我正在返回一个带有音乐列表的JSON。但是我无法将其添加到音频服务后台并运行它。请帮忙。这是我的球员班级的一个例子。songModel具有所有歌曲数据下面的代码是我的实现。
`import 'package:audio_service/audio_service.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:rxdart/rxdart.dart';
import 'Songs.dart';
import 'backgroundTask.dart';
class Player extends StatefulWidget {
SongModel songModel;
Player({@required this.songModel});
@override
_Player createState() => _Player();
}
class _Player extends State<Player> {
static SongModel data;
List<MediaItem> songs;
@override
Future<void> initState() {
super.initState();
data = widget.songModel;
songs = data.songs;
print(songs);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: StreamBuilder<ScreenState>(
stream: _screenStateStream,
builder: (context, snapshot) {
final screenState = snapshot.data;
final queue = screenState?.queue;
final mediaItem = screenState?.mediaItem;
final state = screenState?.playbackState;
final basicState = state?.basicState ?? BasicPlaybackState.none;
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(data.currentSong.title),
Text(data.songs.length.toString()),
Column(mainAxisAlignment: MainAxisAlignment.center, children: [
if (queue != null && queue.isNotEmpty)
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
icon: Icon(Icons.skip_previous),
iconSize: 64.0,
onPressed: mediaItem == queue.first
? null
: AudioService.skipToPrevious,
),
IconButton(
icon: Icon(Icons.skip_next),
iconSize: 64.0,
onPressed: mediaItem == queue.last
? null
: AudioService.skipToNext,
),
if (mediaItem?.title != null) Text(mediaItem.title),
],
),
]),
if (mediaItem?.title != null) Text(mediaItem.title),
if (basicState == BasicPlaybackState.playing)
RaisedButton(child: Text("Pause"), onPressed: pause)
else if (basicState == BasicPlaybackState.buffering ||
basicState == BasicPlaybackState.skippingToNext ||
basicState == BasicPlaybackState.skippingToPrevious)
Padding(
padding: const EdgeInsets.all(8.0),
child: SizedBox(
width: 64.0,
height: 64.0,
child: CircularProgressIndicator(),
),
)
else if (state != BasicPlaybackState.stopped)
RaisedButton(child: Text("Stop"), onPressed: stop),
RaisedButton(child: Text("Play"), onPressed: play),
RaisedButton(child: Text("StartService"),onPressed:()=> start(data.songs))
],
);
},
)),
);
}
}
_backgroundTaskEntrypoint(){
AudioServiceBackground.run(() => AudioPlayerTask());
}
start(data) {
AudioService.start(
backgroundTaskEntrypoint:_backgroundTaskEntrypoint,
androidNotificationChannelName: 'com.zimosound_app.us',
notificationColor: 0xFF2196f3,
androidNotificationIcon: 'mipmap/ic_launcher',
enableQueue: true,
);
AudioServiceBackground.setQueue(data);
print(AudioService.queue);
}
stop() => AudioService.stop();
play() async {
if (await AudioService.running) {
AudioService.play();
}
}
pause() => AudioService.pause();
Stream<ScreenState> get _screenStateStream =>
Rx.combineLatest3<List<MediaItem>, MediaItem, PlaybackState, ScreenState>(
AudioService.queueStream,
AudioService.currentMediaItemStream,
AudioService.playbackStateStream,
(queue, mediaItem, playbackState) =>
ScreenState(queue, mediaItem, playbackState));
class ScreenState {
final List<MediaItem> queue;
final MediaItem mediaItem;
final PlaybackState playbackState;
ScreenState(this.queue, this.mediaItem, this.playbackState);
}
`
这是我的背景音频课程
import 'dart:async';
import 'package:audio_service/audio_service.dart';
import 'package:flutter/material.dart';
import 'package:just_audio/just_audio.dart';
MediaControl playControl = MediaControl(
androidIcon: 'drawable/ic_action_play_arrow',
label: 'Play',
action: MediaAction.play,
);
MediaControl pauseControl = MediaControl(
androidIcon: 'drawable/ic_action_pause',
label: 'Pause',
action: MediaAction.pause,
);
MediaControl skipToNextControl = MediaControl(
androidIcon: 'drawable/ic_action_skip_next',
label: 'Next',
action: MediaAction.skipToNext,
);
MediaControl skipToPreviousControl = MediaControl(
androidIcon: 'drawable/ic_action_skip_previous',
label: 'Previous',
action: MediaAction.skipToPrevious,
);
MediaControl stopControl = MediaControl(
androidIcon: 'drawable/ic_action_stop',
label: 'Stop',
action: MediaAction.stop,
);
final prevControl = MediaControl(
androidIcon: 'drawable/ic_action_stop',
label: 'Stop',
action: MediaAction.stop,
);
class AudioPlayerTask extends BackgroundAudioTask {
var _queue = AudioService.queue;
int _queueIndex;
AudioPlayer _audioPlayer = new AudioPlayer();
Completer _completer = Completer();
BasicPlaybackState _skipState;
bool _playing;
// AudioPlayerTask(List<MediaItem> queue, int queueIndex){
// this._queue = queue;
// this._queueIndex = queueIndex;
// }
bool get hasNext => _queueIndex + 1 < _queue.length;
bool get hasPrevious => _queueIndex > 0;
MediaItem get mediaItem => _queue[_queueIndex];
BasicPlaybackState _eventToBasicState(AudioPlaybackEvent event) {
if (event.buffering) {
return BasicPlaybackState.buffering;
} else {
switch (event.state) {
case AudioPlaybackState.none:
return BasicPlaybackState.none;
case AudioPlaybackState.stopped:
return BasicPlaybackState.stopped;
case AudioPlaybackState.paused:
return BasicPlaybackState.paused;
case AudioPlaybackState.playing:
return BasicPlaybackState.playing;
case AudioPlaybackState.connecting:
return _skipState ?? BasicPlaybackState.connecting;
case AudioPlaybackState.completed:
return BasicPlaybackState.stopped;
default:
throw Exception("Illegal state");
}
}
}
@override
Future<void> onStart() async {
var playerStateSubscription = _audioPlayer.playbackStateStream
.where((state) => state == AudioPlaybackState.completed)
.listen((state) {
_handlePlaybackCompleted();
});
var eventSubscription = _audioPlayer.playbackEventStream.listen((event) {
final state = _eventToBasicState(event);
if (state != BasicPlaybackState.stopped) {
_setState(
state: state,
position: event.position.inMilliseconds,
);
}
});
// AudioServiceBackground.setQueue(_queue);
await onSkipToNext();
await _completer.future;
playerStateSubscription.cancel();
eventSubscription.cancel();
}
void _handlePlaybackCompleted() {
if (hasNext) {
onSkipToNext();
} else {
onStop();
}
}
void playPause() {
if (AudioServiceBackground.state.basicState == BasicPlaybackState.playing)
onPause();
else
onPlay();
}
@override
Future<void> onSkipToNext() => _skip(1);
@override
Future<void> onSkipToPrevious() => _skip(-1);
Future<void> _skip(int offset) async {
final newPos = _queueIndex + offset;
if (!(newPos >= 0 && newPos < _queue.length)) return;
if (_playing == null) {
// First time, we want to start playing
_playing = true;
} else if (_playing) {
// Stop current item
await _audioPlayer.stop();
}
// Load next item
_queueIndex = newPos;
AudioServiceBackground.setMediaItem(mediaItem);
_skipState = offset > 0
? BasicPlaybackState.skippingToNext
: BasicPlaybackState.skippingToPrevious;
await _audioPlayer.setUrl(mediaItem.id);
_skipState = null;
// Resume playback if we were playing
if (_playing) {
onPlay();
} else {
_setState(state: BasicPlaybackState.paused);
}
}
@override
void onPlay() {
if (_skipState == null) {
_playing = true;
_audioPlayer.play();
AudioServiceBackground.sendCustomEvent('just played');
}
}
@override
void onPause() {
if (_skipState == null) {
_playing = false;
_audioPlayer.pause();
AudioServiceBackground.sendCustomEvent('just paused');
}
}
@override
void onSeekTo(int position) {
_audioPlayer.seek(Duration(milliseconds: position));
}
@override
void onClick(MediaButton button) {
playPause();
}
@override
Future<void> onStop() async {
await _audioPlayer.stop();
await _audioPlayer.dispose();
_setState(state: BasicPlaybackState.stopped);
_completer.complete();
}
void _setState({@required BasicPlaybackState state, int position}) {
if (position == null) {
position = _audioPlayer.playbackEvent.position.inMilliseconds;
}
AudioServiceBackground.setState(
controls: getControls(state),
systemActions: [MediaAction.seekTo],
basicState: state,
position: position,
);
}
List<MediaControl> getControls(BasicPlaybackState state) {
if (_playing) {
return [
skipToPreviousControl,
pauseControl,
skipToNextControl,
stopControl,
];
} else {
return [
skipToPreviousControl,
playControl,
skipToNextControl,
stopControl,
];
}
}
@override
void onAudioBecomingNoisy() {
playPause();
}
@override
void onAudioFocusGained() {
playPause();
}
@override
void onAudioFocusLost() {
playPause();
}
@override
void onAudioFocusLostTransient() {
playPause();
}
@override
void onAudioFocusLostTransientCanDuck() {
playPause();
}
}
您解决了这个问题吗?我也面临着同样的问题。
我可以从其他页面以这种方式调用audioplayerTask:
void _audioPlayerTaskEntrypoint() async {
AudioServiceBackground.run(()=> AudioPlayerTask(queue,queue.length));}
使用此代码生成队列,
for (var mp3 in data['data']){
MediaItem songs = MediaItem(id:"\"${mp3.xsources_mp3}\"",
album: "\"${mp3.xtitle}\"",
title: "\"${mp3.xtitle}\"",
artist: "\"${mp3.xauthor}\"",
duration: int.parse(mp3.id)*4000,
artUri: "\"${mp3.ximage}\"");
queue.add(songs);
}
参数中的引号是我的想法,以使值与Audio_Servive的示例保持相似的格式,我也尝试了不使用引号的方式,但它不起作用。audio_service已启动,但无法识别音频。如果您已解决此问题,请告诉我。先感谢您。