我正在构建一个简单的应用,该应用使用audioplayers
包播放来自URL的音频。当_play()
函数触发时,iOS Simulator崩溃,提示:
iOS => call play, playerId 85966f40-ea00-41b1-bb84-15cd8b8d4ca3
Lost connection to device.
play!
isLocal: 0 0
volume: 1.000000 1
仅当我尝试设置开始时间时才会发生这种情况:
final result = await _audioPlayer.play(url,
isLocal: isLocal, position: Duration(seconds: 2));
在Android模拟器上也会发生同样的情况,但是当我在iOS设备上运行它时,它可以工作。
我的代码几乎与audioplayers
回购中的原始代码相同,如果我更改了原始回购代码中的position
值也可以正常工作。可能是什么问题?
这是我的完整代码:
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: PlayerWidget(
url: 'http://techslides.com/demos/samples/sample.mp3')),
);
}
}
enum PlayerState { stopped, playing, paused }
class PlayerWidget extends StatefulWidget {
final String url;
final bool isLocal;
final PlayerMode mode;
PlayerWidget(
{@required this.url,
this.isLocal = false,
this.mode = PlayerMode.MEDIA_PLAYER});
@override
State<StatefulWidget> createState() {
return new _PlayerWidgetState(url, isLocal, mode);
}
}
class _PlayerWidgetState extends State<PlayerWidget> {
String url;
bool isLocal;
PlayerMode mode;
AudioPlayer _audioPlayer;
AudioPlayerState _audioPlayerState;
Duration _duration;
Duration _position;
PlayerState _playerState = PlayerState.stopped;
StreamSubscription _durationSubscription;
StreamSubscription _positionSubscription;
StreamSubscription _playerCompleteSubscription;
StreamSubscription _playerErrorSubscription;
StreamSubscription _playerStateSubscription;
get _isPlaying => _playerState == PlayerState.playing;
get _isPaused => _playerState == PlayerState.paused;
get _durationText => _duration?.toString()?.split('.')?.first ?? '';
get _positionText => _position?.toString()?.split('.')?.first ?? '';
_PlayerWidgetState(this.url, this.isLocal, this.mode);
@override
void initState() {
super.initState();
_initAudioPlayer();
}
@override
void dispose() {
_audioPlayer.stop();
_durationSubscription?.cancel();
_positionSubscription?.cancel();
_playerCompleteSubscription?.cancel();
_playerErrorSubscription?.cancel();
_playerStateSubscription?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return new Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Row(
mainAxisSize: MainAxisSize.min,
children: [
new IconButton(
onPressed: _isPlaying ? null : () => _play(),
iconSize: 64.0,
icon: new Icon(Icons.play_arrow),
color: Colors.cyan),
new IconButton(
onPressed: _isPlaying ? () => _pause() : null,
iconSize: 64.0,
icon: new Icon(Icons.pause),
color: Colors.cyan),
new IconButton(
onPressed: _isPlaying || _isPaused ? () => _stop() : null,
iconSize: 64.0,
icon: new Icon(Icons.stop),
color: Colors.cyan),
],
),
new Row(
mainAxisSize: MainAxisSize.min,
children: [
new Padding(
padding: new EdgeInsets.all(12.0),
child: new Stack(
children: [
new CircularProgressIndicator(
value: 1.0,
valueColor: new AlwaysStoppedAnimation(Colors.grey[300]),
),
new CircularProgressIndicator(
value: (_position != null &&
_duration != null &&
_position.inMilliseconds > 0 &&
_position.inMilliseconds < _duration.inMilliseconds)
? _position.inMilliseconds / _duration.inMilliseconds
: 0.0,
valueColor: new AlwaysStoppedAnimation(Colors.cyan),
),
],
),
),
new Text(
_position != null
? '${_positionText ?? ''} / ${_durationText ?? ''}'
: _duration != null ? _durationText : '',
style: new TextStyle(fontSize: 24.0),
),
],
),
new Text("State: $_audioPlayerState")
],
);
}
void _initAudioPlayer() {
_audioPlayer = new AudioPlayer(mode: mode);
_durationSubscription =
_audioPlayer.onDurationChanged.listen((duration) => setState(() {
_duration = duration;
}));
_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 = new Duration(seconds: 0);
_position = new Duration(seconds: 0);
});
});
_audioPlayer.onPlayerStateChanged.listen((state) {
if (!mounted) return;
setState(() {
_audioPlayerState = state;
});
});
}
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,
isLocal: isLocal, position: Duration(seconds: 2));
if (result == 1) setState(() => _playerState = PlayerState.playing);
return result;
}
Future<int> _pause() async {
final result = await _audioPlayer.pause();
if (result == 1) setState(() => _playerState = PlayerState.paused);
return result;
}
Future<int> _stop() async {
final result = await _audioPlayer.stop();
if (result == 1) {
setState(() {
_playerState = PlayerState.stopped;
_position = new Duration();
});
}
return result;
}
void _onComplete() {
setState(() => _playerState = PlayerState.stopped);
}
}