diff --git a/sky/services/media/BUILD.gn b/sky/services/media/BUILD.gn index af7ad397306..bfa0fe938b5 100644 --- a/sky/services/media/BUILD.gn +++ b/sky/services/media/BUILD.gn @@ -28,6 +28,7 @@ if (is_android) { java_files = [ "src/org/domokit/media/MediaPlayerImpl.java", "src/org/domokit/media/MediaServiceImpl.java", + "src/org/domokit/media/SoundPoolImpl.java", ] deps = [ diff --git a/sky/services/media/media.mojom b/sky/services/media/media.mojom index a0d2634c419..f341fc0ebd9 100644 --- a/sky/services/media/media.mojom +++ b/sky/services/media/media.mojom @@ -14,7 +14,23 @@ interface MediaPlayer { SeekTo(uint32 msec); }; +[ServiceName="media::SoundPool"] +interface SoundPool { + Load(handle data_source) => (bool success, int32 sound_id); + Play(int32 sound_id, float left_volume, float right_volume, bool loop, float rate) => + (bool success, int32 stream_id); + Stop(int32 stream_id); + Pause(int32 stream_id); + Resume(int32 stream_id); + SetRate(int32 stream_id, float rate); + SetVolume(int32 stream_id, float left_volume, float right_volume); + + PauseAll(); + ResumeAll(); +}; + [ServiceName="media::MediaService"] interface MediaService { CreatePlayer(MediaPlayer& player); + CreateSoundPool(SoundPool& pool, int32 max_streams); }; diff --git a/sky/services/media/src/org/domokit/media/MediaServiceImpl.java b/sky/services/media/src/org/domokit/media/MediaServiceImpl.java index f7ba50c1283..5626b5f016a 100644 --- a/sky/services/media/src/org/domokit/media/MediaServiceImpl.java +++ b/sky/services/media/src/org/domokit/media/MediaServiceImpl.java @@ -11,6 +11,7 @@ import org.chromium.mojo.system.Core; import org.chromium.mojo.system.MojoException; import org.chromium.mojom.media.MediaPlayer; import org.chromium.mojom.media.MediaService; +import org.chromium.mojom.media.SoundPool; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -45,4 +46,9 @@ public class MediaServiceImpl implements MediaService { public void createPlayer(InterfaceRequest player) { MediaPlayer.MANAGER.bind(new MediaPlayerImpl(mCore, mContext, sThreadPool), player); } + + @Override + public void createSoundPool(InterfaceRequest pool, int maxStreams) { + SoundPool.MANAGER.bind(new SoundPoolImpl(mCore, mContext, sThreadPool, maxStreams), pool); + } } diff --git a/sky/services/media/src/org/domokit/media/SoundPoolImpl.java b/sky/services/media/src/org/domokit/media/SoundPoolImpl.java new file mode 100644 index 00000000000..14ab3a2d3e4 --- /dev/null +++ b/sky/services/media/src/org/domokit/media/SoundPoolImpl.java @@ -0,0 +1,141 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.domokit.media; + +import android.content.Context; +import android.media.AudioManager; +import android.util.Log; + +import org.chromium.mojo.common.DataPipeUtils; +import org.chromium.mojo.system.Core; +import org.chromium.mojo.system.DataPipe; +import org.chromium.mojo.system.MojoException; +import org.chromium.mojom.media.SoundPool; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.concurrent.Executor; + +/** + * Mojo service providing access to SoundPool. + */ +public class SoundPoolImpl implements SoundPool, android.media.SoundPool.OnLoadCompleteListener { + private static final String TAG = "SoundPoolImpl"; + private final Core mCore; + private final Context mContext; + private final Executor mExecutor; + private final android.media.SoundPool mSoundPool; + private final ArrayList mTempFiles; + private final HashMap mPendingLoads; + + public SoundPoolImpl(Core core, Context context, Executor executor, int maxStreams) { + mCore = core; + mContext = context; + mExecutor = executor; + mTempFiles = new ArrayList(); + mPendingLoads = new HashMap(); + + android.media.SoundPool.Builder builder = new android.media.SoundPool.Builder(); + builder.setMaxStreams(maxStreams); + mSoundPool = builder.build(); + mSoundPool.setOnLoadCompleteListener(this); + } + + @Override + public void close() { + if (mSoundPool != null) { + mSoundPool.release(); + } + for (File tempFile : mTempFiles) { + tempFile.delete(); + } + } + + @Override + public void onConnectionError(MojoException e) { + } + + @Override + public void load(DataPipe.ConsumerHandle consumerHandle, final LoadResponse callback) { + File file; + try { + file = File.createTempFile("sky_sound_pool", "temp", mContext.getCacheDir()); + } catch (IOException e) { + Log.e(TAG, "Failed to create temporary file", e); + callback.call(false, 0); + return; + } + final File tempFile = file; + + mTempFiles.add(tempFile); + + DataPipeUtils.copyToFile(mCore, consumerHandle, tempFile, mExecutor, new Runnable() { + @Override + public void run() { + String path; + try { + path = tempFile.getCanonicalPath(); + } catch (IOException e) { + callback.call(false, 0); + return; + } + int soundId = mSoundPool.load(path, 1); + mPendingLoads.put(soundId, callback); + } + }); + } + + @Override + public void onLoadComplete(android.media.SoundPool soundPool, int soundId, int status) { + LoadResponse callback = mPendingLoads.remove(soundId); + if (callback != null) { + callback.call(true, soundId); + } + } + + @Override + public void play(int soundId, float leftVolume, float rightVolume, boolean loop, float rate, + PlayResponse callback) { + int streamId = mSoundPool.play(soundId, leftVolume, rightVolume, 0, loop ? -1 : 0, rate); + callback.call(streamId != 0, streamId); + } + + @Override + public void stop(int streamId) { + mSoundPool.stop(streamId); + } + + @Override + public void pause(int streamId) { + mSoundPool.pause(streamId); + } + + @Override + public void resume(int streamId) { + mSoundPool.resume(streamId); + } + + @Override + public void setRate(int streamId, float rate) { + mSoundPool.setRate(streamId, rate); + } + + @Override + public void setVolume(int streamId, float leftVolume, float rightVolume) { + mSoundPool.setVolume(streamId, leftVolume, rightVolume); + } + + @Override + public void pauseAll() { + mSoundPool.autoPause(); + } + + @Override + public void resumeAll() { + mSoundPool.autoResume(); + } +}