Skip to content

Commit

Permalink
Abstract audio engine implementation. Disable GVR audio for now. (#1058)
Browse files Browse the repository at this point in the history
  • Loading branch information
MortimerGoro authored and bluemarvin committed Apr 3, 2019
1 parent 4fa75c1 commit 945a78b
Show file tree
Hide file tree
Showing 3 changed files with 199 additions and 146 deletions.
Expand Up @@ -176,7 +176,7 @@ protected void onCreate(Bundle savedInstanceState) {

mPermissionDelegate = new PermissionDelegate(this, this);

mAudioEngine = new AudioEngine(this, new VRAudioTheme());
mAudioEngine = new AudioEngine(this, null);
mAudioEngine.setEnabled(SettingsStore.getInstance(this).isAudioEnabled());
mAudioEngine.preloadAsync(() -> {
Log.i(LOGTAG, "AudioEngine sounds preloaded!");
Expand Down
184 changes: 39 additions & 145 deletions app/src/common/shared/org/mozilla/vrbrowser/audio/AudioEngine.java
Expand Up @@ -5,17 +5,12 @@

package org.mozilla.vrbrowser.audio;

import android.app.Activity;
import android.content.Context;
import android.util.Log;

import com.google.vr.sdk.audio.GvrAudioEngine;
import java.util.concurrent.ConcurrentHashMap;

public class AudioEngine {
private Context mContext;
private GvrAudioEngine mEngine;
private AudioTheme mTheme;
private AudioEngineImpl mEngine;
private ConcurrentHashMap<Sound, Integer> mSourceIds;
private float mMasterVolume = 1.0f;
private static ConcurrentHashMap<Context, AudioEngine> mEngines = new ConcurrentHashMap<>();
Expand Down Expand Up @@ -52,14 +47,24 @@ public interface AudioTheme {
String getPath(Sound aSound);
}

public interface AudioEngineImpl {
void preloadAsync(final Runnable aCallback);
void pause();
void resume();
void setPose(float qx, float qy, float qz, float qw, float px, float py, float pz);
void update();
void release();
void playSound(Sound aSound, float aVolume, boolean aLoop);
void stopSound(Sound aSound);
}

public static AudioEngine fromContext(Context aContext) {
return mEngines.get(aContext);
}

public AudioEngine(Context aContext, AudioTheme aTheme) {
public AudioEngine(Context aContext, AudioEngineImpl aImpl) {
mContext = aContext;
mTheme = aTheme;
mEngine = new GvrAudioEngine(aContext, GvrAudioEngine.RenderingMode.BINAURAL_HIGH_QUALITY);
mEngine = aImpl;
mSourceIds = new ConcurrentHashMap<>();
mEngines.put(aContext, this);
mEnabled = true;
Expand All @@ -69,177 +74,66 @@ public void setEnabled(boolean enabled) {
mEnabled = enabled;
}

private void preload() {
for (Sound sound: Sound.values()) {
if (sound.getType() == SoundType.FIELD) {
// Ambisonic soundfields do *not* need to be preloaded
// They are directly streamed and rendered from the compressed audio file.
// The handle automatically destroys itself at the moment the sound playback has stopped.
continue;
}
String path = mTheme.getPath(sound);
if (path != null && path.length() > 0) {
preloadFile(path);
}
}
}

public void preloadAsync() {
preloadAsync(null);
}

// Perform preloading in a separate thread in order to avoid blocking the main thread
public void preloadAsync(final Runnable aCallback) {
if (mEnabled) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
preload();
if (aCallback != null) {
((Activity) mContext).runOnUiThread(aCallback);
}
}
});
thread.start();
if (mEngine != null) {
mEngine.preloadAsync(aCallback);
}
}

public void release() {
mSourceIds.clear();
mEngines.remove(mContext);
for (Sound sound: Sound.values()) {
String path = mTheme.getPath(sound);
if (path != null && sound.getType() != SoundType.FIELD) {
mEngine.unloadSoundFile(mTheme.getPath(sound));
}
if (mEngine != null) {
mEngine.release();
}
}

public void pauseEngine() {
mEngine.pause();
}

public void resumeEngine() {
mEngine.resume();
}

public void setPose(float qx, float qy, float qz, float qw, float px, float py, float pz) {
mEngine.setHeadRotation(qx, qy, qz, qw);
mEngine.setHeadPosition(px, py, pz);
}

public void update() {
mEngine.update();
}

public void playSound(Sound aSound) {
if (mEnabled) {
playSound(aSound, false);
}
}

private void playSound(Sound aSound, boolean aLoopEnabled) {
String path = mTheme.getPath(aSound);
if (path == null || path.length() == 0) {
return;
}
int sourceId = createSound(aSound.getType(), mTheme.getPath(aSound));
if (sourceId != GvrAudioEngine.INVALID_ID) {
mSourceIds.put(aSound, sourceId);
playSound(sourceId, aLoopEnabled);
}
}

private void playSound(int aSourceId, boolean aLoopEnabled) {
mEngine.playSound(aSourceId, aLoopEnabled);
}

public void pauseSound(Sound aSound) {
if (mEnabled) {
Integer sourceId = findSourceId(aSound);
if (sourceId != null) {
pauseSound(sourceId);
}
if (mEngine != null) {
mEngine.pause();
}
}

private void pauseSound(int aSourceId) {
mEngine.pauseSound(aSourceId);
}

private void resumeSound(Sound aSound) {
Integer sourceId = findSourceId(aSound);
if (sourceId != null) {
resumeSound(sourceId);
public void resumeEngine() {
if (mEngine != null) {
mEngine.resume();
}
}

public void resumeSound(int aSourceId) {
if (mEnabled) {
mEngine.stopSound(aSourceId);
public void setPose(float qx, float qy, float qz, float qw, float px, float py, float pz) {
if (mEngine != null) {
mEngine.setPose(qx, qy, qz, qw, px, py, pz);
}
}

private void setSoundPosition(Sound aSound, float x, float y, float z) {
if (aSound.getType() != SoundType.OBJECT) {
Log.e(LOGTAG, "Sound position can only be set for SoundType.Object!");
return;
}
Integer sourceId = findSourceId(aSound);
if (sourceId != null) {
setSoundPosition(sourceId, x, y, z);
public void update() {
if (mEngine != null) {
mEngine.update();
}
}

public void setSoundPosition(int aSoundObjectId, float x, float y, float z) {
if (mEnabled) {
mEngine.setSoundObjectPosition(aSoundObjectId, x, y, z);
}
public void playSound(Sound aSound) {
playSound(aSound, 1.0f,false);
}

private void setSoundVolume(Sound aSound, float aVolume) {
Integer sourceId = findSourceId(aSound);
if (sourceId != null) {
setSoundVolume(sourceId, aVolume);
}
public void setMasterVolume(float aVolume) {
mMasterVolume = aVolume;
}

public void setSoundVolume(int aSourceId, float aVolume) {
if (mEnabled) {
mEngine.setSoundVolume(aSourceId, aVolume * mMasterVolume);
public void playSound(Sound aSound, float aVolume, boolean aLoop) {
if (mEnabled && mEngine != null) {
mEngine.playSound(aSound, aVolume * mMasterVolume, aLoop);
}
}

private void setMasterVolume(float aMasterVolume) {
mMasterVolume = aMasterVolume;
}


private int createSound(SoundType aType, String path) {
mEngine.preloadSoundFile(path);
int sourceId = GvrAudioEngine.INVALID_ID;
switch (aType) {
case FIELD: sourceId = mEngine.createSoundfield(path); break;
case OBJECT: sourceId = mEngine.createSoundObject(path); break;
case STEREO: sourceId = mEngine.createStereoSound(path); break;
public void stopSound(Sound aSound) {
if (mEnabled && mEngine != null) {
mEngine.stopSound(aSound);
}

if (sourceId == GvrAudioEngine.INVALID_ID) {
Log.e(LOGTAG, "Error loading sound from path: " + path);
}

return sourceId;
}

private void preloadFile(String path) {
mEngine.preloadSoundFile(path);
}

private void unloadFile(String path) {
mEngine.unloadSoundFile(path);
}

private Integer findSourceId(Sound aSound) {
return mSourceIds.get(aSound);
}
}

0 comments on commit 945a78b

Please sign in to comment.