Commit 2da6b175 authored by Jason Simmons's avatar Jason Simmons

Merge pull request #845 from jason-simmons/sound_pool

Update SoundEffectPlayer to use the SoundPool API
parents 640c609f db10a6ee
...@@ -7,8 +7,8 @@ dependencies: ...@@ -7,8 +7,8 @@ dependencies:
collection: '>=1.1.3 <2.0.0' collection: '>=1.1.3 <2.0.0'
intl: '>=0.12.4+2 <0.13.0' intl: '>=0.12.4+2 <0.13.0'
material_design_icons: '>=0.0.3 <0.1.0' material_design_icons: '>=0.0.3 <0.1.0'
sky_engine: 0.0.71 sky_engine: 0.0.72
sky_services: 0.0.71 sky_services: 0.0.72
vector_math: '>=1.4.3 <2.0.0' vector_math: '>=1.4.3 <2.0.0'
# To pin the transitive dependency through mojo_sdk. # To pin the transitive dependency through mojo_sdk.
......
part of flutter_sprites; part of flutter_sprites;
// TODO: The sound effects should probably use Android's SoundPool instead of /// An audio asset loaded by the SoundEffectPlayer.
// MediaPlayer as it is more efficient and flexible for playing back sound effects
typedef void SoundEffectStreamCallback(SoundEffectStream stream);
class SoundEffect { class SoundEffect {
SoundEffect(this._pipeFuture); SoundEffect(this._soundId);
// TODO: Remove load method from SoundEffect int _soundId;
Future load() async {
_data = await _pipeFuture;
}
Future<MojoDataPipeConsumer> _pipeFuture;
MojoDataPipeConsumer _data;
} }
/// A sound being played by the SoundEffectPlayer.
class SoundEffectStream { class SoundEffectStream {
SoundEffectStream( SoundEffectStream(SoundEffectPlayer player, int streamId, {
this.sound, double leftVolume,
this.loop, double rightVolume,
this.volume, double pitch
this.pitch, }) {
this.pan, _player = player;
this.onSoundComplete _streamId = streamId;
); _paused = false;
_leftVolume = leftVolume;
// TODO: Make these properties work _rightVolume = rightVolume;
SoundEffect sound; _pitch = pitch;
bool playing = false; }
bool loop = false;
double volume = 1.0; SoundEffectPlayer _player;
double pitch = 1.0; int _streamId;
double pan = 0.0;
SoundPoolProxy get _soundPool => _player._soundPool;
// TODO: Implement completion callback. On completion, sounds should
// also be removed from the list of playing sounds. void stop() {
SoundEffectStreamCallback onSoundComplete; _soundPool.ptr.stop(_streamId);
}
MediaPlayerProxy _player;
} bool get paused => _paused;
bool _paused;
SoundEffectPlayer _sharedSoundEffectPlayer; void set paused(bool value) {
_paused = value;
class SoundEffectPlayer { if (_paused) {
_soundPool.ptr.pause(_streamId);
static SoundEffectPlayer sharedInstance() { } else {
if (_sharedSoundEffectPlayer == null) { _soundPool.ptr.resume(_streamId);
_sharedSoundEffectPlayer = new SoundEffectPlayer();
} }
return _sharedSoundEffectPlayer;
} }
SoundEffectPlayer() { double get leftVolume => _leftVolume;
_mediaService = new MediaServiceProxy.unbound(); double _leftVolume;
shell.connectToService(null, _mediaService); void set leftVolume(double value) {
_leftVolume = value;
_soundPool.ptr.setVolume(_streamId, <double>[_leftVolume, _rightVolume]);
} }
MediaServiceProxy _mediaService; double get rightVolume => _rightVolume;
List<SoundEffectStream> _soundEffectStreams = <SoundEffectStream>[]; double _rightVolume;
void set rightVolume(double value) {
// TODO: This should no longer be needed when moving to SoundPool backing _rightVolume = value;
Map<SoundEffect,MediaPlayerProxy> _mediaPlayers = <SoundEffect, MediaPlayerProxy>{}; _soundPool.ptr.setVolume(_streamId, <double>[_leftVolume, _rightVolume]);
Future _prepare(SoundEffectStream playingSound) async {
await playingSound._player.ptr.prepare(playingSound.sound._data);
} }
// TODO: Move sound loading here double get pitch => _pitch;
// TODO: Support loading sounds from bundles double _pitch;
// Future<SoundEffect> load(url) async { void set pitch(double value) {
// ... _pitch = value;
// } _soundPool.ptr.setRate(_streamId, _pitch);
}
// TODO: Add sound unloader }
// unload(SoundEffect effect) {
// ...
// }
// TODO: Add paused property (should pause playback of all sounds)
bool paused;
SoundEffectStream play( class SoundEffectPlayer {
SoundEffect sound, SoundEffectPlayer(int maxStreams) {
[bool loop = false, MediaServiceProxy mediaService = new MediaServiceProxy.unbound();
double volume = 1.0, shell.connectToService(null, mediaService);
double pitch = 1.0, _soundPool = new SoundPoolProxy.unbound();
double pan = 0.0, mediaService.ptr.createSoundPool(_soundPool, maxStreams);
SoundEffectStreamCallback callback = null]) { }
// Create new PlayingSound object SoundPoolProxy _soundPool;
SoundEffectStream playingSound = new SoundEffectStream( bool _paused;
sound, int _nextStreamId = 0;
loop,
volume, Future<SoundEffect> load(MojoDataPipeConsumer data) async {
pitch, SoundPoolLoadResponseParams result = await _soundPool.ptr.load(data);
pan, if (result.success)
callback return new SoundEffect(result.soundId);
throw new Exception('Unable to load sound');
}
Future<SoundEffectStream> play(SoundEffect sound, {
double leftVolume: 1.0,
double rightVolume: 1.0,
bool loop: false,
double pitch: 1.0
}) async {
int streamId = _nextStreamId++;
SoundPoolPlayResponseParams result = await _soundPool.ptr.play(
sound._soundId, streamId, <double>[leftVolume, rightVolume], loop, pitch
); );
// TODO: Replace this with calls to SoundPool if (result.success) {
if (_mediaPlayers[sound] == null) { return new SoundEffectStream(this, streamId,
// Create player leftVolume: leftVolume,
playingSound._player = new MediaPlayerProxy.unbound(); rightVolume: rightVolume,
_mediaService.ptr.createPlayer(playingSound._player); pitch: pitch
);
// Prepare sound, then play it
_prepare(playingSound).then((_) {
playingSound._player.ptr.seekTo(0);
playingSound._player.ptr.start();
});
_soundEffectStreams.add(playingSound);
_mediaPlayers[sound] = playingSound._player;
} else {
// Reuse player
playingSound._player = _mediaPlayers[sound];
playingSound._player.ptr.seekTo(0);
playingSound._player.ptr.start();
} }
return playingSound; throw new Exception('Unable to play sound');
} }
void stop(SoundEffectStream stream) { bool get paused => _paused;
stream._player.ptr.pause();
_soundEffectStreams.remove(stream);
}
void stopAll() { void set paused(bool value) {
for (SoundEffectStream playingSound in _soundEffectStreams) { _paused = value;
playingSound._player.ptr.pause(); if (_paused) {
_soundPool.ptr.pauseAll();
} else {
_soundPool.ptr.resumeAll();
} }
_soundEffectStreams = <SoundEffectStream>[];
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment