Android: Added first prototype of AndroidAudioRenderer
git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7723 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
This commit is contained in:
parent
68bac95cd5
commit
a7974ac659
@ -47,6 +47,11 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt
|
|||||||
*/
|
*/
|
||||||
protected ConfigType eglConfigType = ConfigType.FASTEST;
|
protected ConfigType eglConfigType = ConfigType.FASTEST;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If true all valid and not valid egl configs are logged
|
||||||
|
*/
|
||||||
|
protected boolean eglConfigVerboseLogging = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Title of the exit dialog, default is "Do you want to exit?"
|
* Title of the exit dialog, default is "Do you want to exit?"
|
||||||
*/
|
*/
|
||||||
@ -68,6 +73,7 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt
|
|||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
JmeSystem.setResources(getResources());
|
JmeSystem.setResources(getResources());
|
||||||
|
JmeSystem.setActivity(this);
|
||||||
|
|
||||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
|
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
|
||||||
@ -88,7 +94,7 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt
|
|||||||
app.setSettings(settings);
|
app.setSettings(settings);
|
||||||
app.start();
|
app.start();
|
||||||
ctx = (OGLESContext) app.getContext();
|
ctx = (OGLESContext) app.getContext();
|
||||||
view = ctx.createView(input, eglConfigType);
|
view = ctx.createView(input, eglConfigType, eglConfigVerboseLogging);
|
||||||
setContentView(view);
|
setContentView(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,8 +135,8 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy(){
|
protected void onDestroy(){
|
||||||
|
app.stop(true);
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
app.stop();
|
|
||||||
logger.info("onDestroy");
|
logger.info("onDestroy");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,6 +144,7 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt
|
|||||||
{
|
{
|
||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when an error has occured. This is typically
|
* Called when an error has occured. This is typically
|
||||||
* invoked when an uncought exception is thrown in the render thread.
|
* invoked when an uncought exception is thrown in the render thread.
|
||||||
@ -186,7 +193,7 @@ public class AndroidHarness extends Activity implements TouchListener, DialogInt
|
|||||||
{
|
{
|
||||||
if (whichButton != -2)
|
if (whichButton != -2)
|
||||||
{
|
{
|
||||||
app.stop();
|
app.stop(true);
|
||||||
this.finish();
|
this.finish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,7 @@ import java.util.logging.Logger;
|
|||||||
|
|
||||||
import com.jme3.asset.plugins.AndroidLocator;
|
import com.jme3.asset.plugins.AndroidLocator;
|
||||||
import com.jme3.asset.plugins.ClasspathLocator;
|
import com.jme3.asset.plugins.ClasspathLocator;
|
||||||
|
import com.jme3.audio.plugins.AndroidAudioLoader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <code>AndroidAssetManager</code> is an implementation of DesktopAssetManager for Android
|
* <code>AndroidAssetManager</code> is an implementation of DesktopAssetManager for Android
|
||||||
@ -73,6 +74,7 @@ public class AndroidAssetManager extends DesktopAssetManager {
|
|||||||
this.registerLocator("", AndroidLocator.class);
|
this.registerLocator("", AndroidLocator.class);
|
||||||
this.registerLocator("", ClasspathLocator.class);
|
this.registerLocator("", ClasspathLocator.class);
|
||||||
this.registerLoader(AndroidImageLoader.class, "jpg", "bmp", "gif", "png", "jpeg");
|
this.registerLoader(AndroidImageLoader.class, "jpg", "bmp", "gif", "png", "jpeg");
|
||||||
|
this.registerLoader(AndroidAudioLoader.class, "ogg", "mp3");
|
||||||
this.registerLoader(com.jme3.material.plugins.J3MLoader.class, "j3m");
|
this.registerLoader(com.jme3.material.plugins.J3MLoader.class, "j3m");
|
||||||
this.registerLoader(com.jme3.material.plugins.J3MLoader.class, "j3md");
|
this.registerLoader(com.jme3.material.plugins.J3MLoader.class, "j3md");
|
||||||
this.registerLoader(com.jme3.font.plugins.BitmapFontLoader.class, "fnt");
|
this.registerLoader(com.jme3.font.plugins.BitmapFontLoader.class, "fnt");
|
||||||
|
@ -0,0 +1,54 @@
|
|||||||
|
package com.jme3.audio.android;
|
||||||
|
|
||||||
|
import com.jme3.asset.AssetKey;
|
||||||
|
import com.jme3.audio.AudioData;
|
||||||
|
import com.jme3.audio.AudioRenderer;
|
||||||
|
|
||||||
|
public class AndroidAudioData extends AudioData
|
||||||
|
{
|
||||||
|
protected AssetKey assetKey;
|
||||||
|
protected int soundId = 0;
|
||||||
|
|
||||||
|
public AssetKey getAssetKey() {
|
||||||
|
return assetKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAssetKey(AssetKey assetKey) {
|
||||||
|
this.assetKey = assetKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSoundId() {
|
||||||
|
return soundId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSoundId(int soundId) {
|
||||||
|
this.soundId = soundId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataType getDataType() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getDuration() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resetObject() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteObject(AudioRenderer r) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,518 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2010 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package com.jme3.audio.android;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.AssetManager;
|
||||||
|
import android.media.AudioManager;
|
||||||
|
import android.media.SoundPool;
|
||||||
|
|
||||||
|
import com.jme3.audio.ListenerParam;
|
||||||
|
import com.jme3.audio.AudioParam;
|
||||||
|
import com.jme3.audio.AudioBuffer;
|
||||||
|
import com.jme3.audio.AudioData;
|
||||||
|
import com.jme3.audio.AudioRenderer;
|
||||||
|
import com.jme3.audio.AudioNode;
|
||||||
|
import com.jme3.audio.AudioNode.Status;
|
||||||
|
import com.jme3.audio.AudioStream;
|
||||||
|
import com.jme3.audio.Environment;
|
||||||
|
import com.jme3.audio.Filter;
|
||||||
|
import com.jme3.audio.Listener;
|
||||||
|
import com.jme3.audio.LowPassFilter;
|
||||||
|
import com.jme3.math.Vector3f;
|
||||||
|
import com.jme3.util.BufferUtils;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.nio.FloatBuffer;
|
||||||
|
import java.nio.IntBuffer;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is the android implementation for {@link AudioRenderer}
|
||||||
|
* @author larynx
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class AndroidAudioRenderer implements AudioRenderer, SoundPool.OnLoadCompleteListener
|
||||||
|
{
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(AndroidAudioRenderer.class.getName());
|
||||||
|
private final static int MAX_NUM_CHANNELS = 16;
|
||||||
|
|
||||||
|
private SoundPool soundPool = null;
|
||||||
|
private final AudioManager manager;
|
||||||
|
private final Context context;
|
||||||
|
private final AssetManager am;
|
||||||
|
|
||||||
|
private HashMap<Integer, AudioNode> mapLoadingAudioNodes = new HashMap<Integer, AudioNode>();
|
||||||
|
|
||||||
|
private final AtomicBoolean lastLoadCompleted = new AtomicBoolean();
|
||||||
|
|
||||||
|
|
||||||
|
private Listener listener;
|
||||||
|
private boolean audioDisabled = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public AndroidAudioRenderer(Activity context)
|
||||||
|
{
|
||||||
|
this.context = context;
|
||||||
|
manager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
|
||||||
|
context.setVolumeControlStream(AudioManager.STREAM_MUSIC);
|
||||||
|
am = context.getAssets();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize()
|
||||||
|
{
|
||||||
|
soundPool = new SoundPool(MAX_NUM_CHANNELS, AudioManager.STREAM_MUSIC, 0);
|
||||||
|
soundPool.setOnLoadCompleteListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void updateFilter(Filter f)
|
||||||
|
{
|
||||||
|
throw new UnsupportedOperationException("Filter type unsupported: " + f.getClass().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateSourceParam(AudioNode src, AudioParam param)
|
||||||
|
{
|
||||||
|
if (audioDisabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (src.getChannel() < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
assert src.getChannel() >= 0;
|
||||||
|
|
||||||
|
|
||||||
|
switch (param){
|
||||||
|
case Position:
|
||||||
|
if (!src.isPositional())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Vector3f pos = src.getWorldTranslation();
|
||||||
|
break;
|
||||||
|
case Velocity:
|
||||||
|
if (!src.isPositional())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Vector3f vel = src.getVelocity();
|
||||||
|
break;
|
||||||
|
case MaxDistance:
|
||||||
|
if (!src.isPositional())
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
case RefDistance:
|
||||||
|
if (!src.isPositional())
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
case ReverbFilter:
|
||||||
|
if (!src.isPositional() || !src.isReverbEnabled())
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
case ReverbEnabled:
|
||||||
|
if (!src.isPositional())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (src.isReverbEnabled()){
|
||||||
|
updateSourceParam(src, AudioParam.ReverbFilter);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case IsPositional:
|
||||||
|
break;
|
||||||
|
case Direction:
|
||||||
|
if (!src.isDirectional())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Vector3f dir = src.getDirection();
|
||||||
|
break;
|
||||||
|
case InnerAngle:
|
||||||
|
if (!src.isDirectional())
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
case OuterAngle:
|
||||||
|
if (!src.isDirectional())
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
case IsDirectional:
|
||||||
|
if (src.isDirectional()){
|
||||||
|
updateSourceParam(src, AudioParam.Direction);
|
||||||
|
updateSourceParam(src, AudioParam.InnerAngle);
|
||||||
|
updateSourceParam(src, AudioParam.OuterAngle);
|
||||||
|
}else{
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DryFilter:
|
||||||
|
if (src.getDryFilter() != null){
|
||||||
|
Filter f = src.getDryFilter();
|
||||||
|
if (f.isUpdateNeeded()){
|
||||||
|
updateFilter(f);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Looping:
|
||||||
|
if (src.isLooping()){
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Volume:
|
||||||
|
|
||||||
|
soundPool.setVolume(src.getChannel(), src.getVolume(), src.getVolume());
|
||||||
|
|
||||||
|
break;
|
||||||
|
case Pitch:
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateListenerParam(Listener listener, ListenerParam param)
|
||||||
|
{
|
||||||
|
if (audioDisabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (param){
|
||||||
|
case Position:
|
||||||
|
Vector3f pos = listener.getLocation();
|
||||||
|
|
||||||
|
break;
|
||||||
|
case Rotation:
|
||||||
|
Vector3f dir = listener.getDirection();
|
||||||
|
Vector3f up = listener.getUp();
|
||||||
|
|
||||||
|
break;
|
||||||
|
case Velocity:
|
||||||
|
Vector3f vel = listener.getVelocity();
|
||||||
|
|
||||||
|
break;
|
||||||
|
case Volume:
|
||||||
|
//alListenerf(AL_GAIN, listener.getVolume());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void update(float tpf)
|
||||||
|
{
|
||||||
|
// does nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateInThread(float tpf)
|
||||||
|
{
|
||||||
|
if (audioDisabled)
|
||||||
|
return;
|
||||||
|
if (!audioDisabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setListener(Listener listener)
|
||||||
|
{
|
||||||
|
if (audioDisabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (this.listener != null){
|
||||||
|
// previous listener no longer associated with current
|
||||||
|
// renderer
|
||||||
|
this.listener.setRenderer(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.listener = listener;
|
||||||
|
this.listener.setRenderer(this);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoadComplete(SoundPool soundPool, int sampleId, int status)
|
||||||
|
{
|
||||||
|
//lastLoadCompleted.set(true);
|
||||||
|
|
||||||
|
if (status == 0)
|
||||||
|
{
|
||||||
|
AudioNode src = mapLoadingAudioNodes.get(sampleId);
|
||||||
|
if (src.getAudioData() instanceof AndroidAudioData)
|
||||||
|
{
|
||||||
|
AndroidAudioData audioData = (AndroidAudioData)src.getAudioData();
|
||||||
|
|
||||||
|
int channelIndex;
|
||||||
|
channelIndex = soundPool.play(audioData.getSoundId(), 1f, 1f, 1, -1, 1f);
|
||||||
|
src.setChannel(channelIndex);
|
||||||
|
// Playing started ?
|
||||||
|
if (src.getChannel() > 0)
|
||||||
|
{
|
||||||
|
src.setStatus(Status.Playing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("AudioData is not of type AndroidAudioData for AudioNode " + src.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cleanup()
|
||||||
|
{
|
||||||
|
if (soundPool != null)
|
||||||
|
{
|
||||||
|
for (AudioNode src: mapLoadingAudioNodes.values())
|
||||||
|
{
|
||||||
|
if ((src.getStatus() == Status.Playing) && (src.getChannel() > 0))
|
||||||
|
{
|
||||||
|
soundPool.stop(src.getChannel());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (src.getAudioData() instanceof AndroidAudioData)
|
||||||
|
{
|
||||||
|
AndroidAudioData audioData = (AndroidAudioData)src.getAudioData();
|
||||||
|
if (audioData.getSoundId() > 0)
|
||||||
|
{
|
||||||
|
soundPool.unload(audioData.getSoundId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
soundPool.release();
|
||||||
|
soundPool = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void playSourceInstance(AudioNode src)
|
||||||
|
{
|
||||||
|
if (audioDisabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
AndroidAudioData audioData;
|
||||||
|
int soundId = 0;
|
||||||
|
|
||||||
|
if (src.getAudioData() instanceof AndroidAudioData)
|
||||||
|
{
|
||||||
|
audioData = (AndroidAudioData)src.getAudioData();
|
||||||
|
if (audioData.isUpdateNeeded() || (audioData.getSoundId() == 0))
|
||||||
|
{
|
||||||
|
if (audioData.getSoundId() > 0)
|
||||||
|
{
|
||||||
|
if (src.getChannel() > 0)
|
||||||
|
{
|
||||||
|
soundPool.stop(src.getChannel());
|
||||||
|
src.setChannel(-1);
|
||||||
|
}
|
||||||
|
soundPool.unload(audioData.getSoundId());
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
soundId = soundPool.load(am.openFd(audioData.getAssetKey().getName()), 1);
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
logger.log(Level.SEVERE, "Failed to load sound " + audioData.getAssetKey().getName(), e);
|
||||||
|
soundId = -1;
|
||||||
|
}
|
||||||
|
audioData.setSoundId(soundId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("AudioData is not of type AndroidAudioData for AudioNode " + src.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sound failed to load ?
|
||||||
|
if (audioData.getSoundId() <= 0)
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("Failed to load: " + audioData.getAssetKey().getName());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int channelIndex;
|
||||||
|
channelIndex = soundPool.play(audioData.getSoundId(), 1f, 1f, 1, -1, 1f);
|
||||||
|
if (channelIndex == 0)
|
||||||
|
{
|
||||||
|
// Loading is not finished
|
||||||
|
// Store the soundId and the AudioNode for async loading and later play start
|
||||||
|
mapLoadingAudioNodes.put(audioData.getSoundId(), src);
|
||||||
|
}
|
||||||
|
src.setChannel(channelIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Playing started ?
|
||||||
|
if (src.getChannel() > 0)
|
||||||
|
{
|
||||||
|
src.setStatus(Status.Playing);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void playSource(AudioNode src)
|
||||||
|
{
|
||||||
|
if (audioDisabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
//assert src.getStatus() == Status.Stopped || src.getChannel() == -1;
|
||||||
|
|
||||||
|
if (src.getStatus() == Status.Playing)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (src.getStatus() == Status.Stopped)
|
||||||
|
{
|
||||||
|
playSourceInstance(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void pauseSource(AudioNode src)
|
||||||
|
{
|
||||||
|
if (audioDisabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (src.getStatus() == Status.Playing)
|
||||||
|
{
|
||||||
|
assert src.getChannel() != -1;
|
||||||
|
|
||||||
|
if (src.getChannel() > 0)
|
||||||
|
{
|
||||||
|
soundPool.pause(src.getChannel());
|
||||||
|
}
|
||||||
|
src.setStatus(Status.Paused);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void stopSource(AudioNode src)
|
||||||
|
{
|
||||||
|
if (audioDisabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (src.getStatus() != Status.Stopped){
|
||||||
|
int chan = src.getChannel();
|
||||||
|
assert chan != -1; // if it's not stopped, must have id
|
||||||
|
|
||||||
|
if (src.getChannel() > 0)
|
||||||
|
{
|
||||||
|
soundPool.stop(src.getChannel());
|
||||||
|
src.setChannel(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
src.setStatus(Status.Stopped);
|
||||||
|
}
|
||||||
|
|
||||||
|
AndroidAudioData audioData;
|
||||||
|
if (src.getAudioData() instanceof AndroidAudioData)
|
||||||
|
{
|
||||||
|
audioData = (AndroidAudioData)src.getAudioData();
|
||||||
|
if (audioData.getSoundId() > 0)
|
||||||
|
{
|
||||||
|
soundPool.unload(audioData.getSoundId());
|
||||||
|
}
|
||||||
|
audioData.setSoundId(0);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("AudioData is not of type AndroidAudioData for AudioNode " + src.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private int convertFormat(AudioData ad)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
switch (ad.getBitsPerSample()){
|
||||||
|
case 8:
|
||||||
|
if (ad.getChannels() == 1)
|
||||||
|
return AL_FORMAT_MONO8;
|
||||||
|
else if (ad.getChannels() == 2)
|
||||||
|
return AL_FORMAT_STEREO8;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
if (ad.getChannels() == 1)
|
||||||
|
return AL_FORMAT_MONO16;
|
||||||
|
else
|
||||||
|
return AL_FORMAT_STEREO16;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
throw new UnsupportedOperationException("Unsupported channels/bits combination: "+
|
||||||
|
"bits="+ad.getBitsPerSample()+", channels="+ad.getChannels());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateAudioData(AndroidAudioData data)
|
||||||
|
{
|
||||||
|
throw new UnsupportedOperationException("updateAudioData");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteAudioData(AudioData ad)
|
||||||
|
{
|
||||||
|
if (ad instanceof AndroidAudioData)
|
||||||
|
{
|
||||||
|
if (((AndroidAudioData)ad).getSoundId() > 0)
|
||||||
|
{
|
||||||
|
soundPool.unload(((AndroidAudioData)ad).getSoundId());
|
||||||
|
}
|
||||||
|
((AndroidAudioData)ad).setSoundId(0);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("AudioData is not of type AndroidAudioData in deleteAudioData");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setEnvironment(Environment env) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package com.jme3.audio.plugins;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import com.jme3.asset.AssetInfo;
|
||||||
|
import com.jme3.asset.AssetLoader;
|
||||||
|
import com.jme3.audio.android.AndroidAudioData;
|
||||||
|
|
||||||
|
public class AndroidAudioLoader implements AssetLoader
|
||||||
|
{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object load(AssetInfo assetInfo) throws IOException
|
||||||
|
{
|
||||||
|
|
||||||
|
InputStream in = assetInfo.openStream();
|
||||||
|
if (in != null)
|
||||||
|
{
|
||||||
|
in.close();
|
||||||
|
}
|
||||||
|
AndroidAudioData result = new AndroidAudioData();
|
||||||
|
result.setAssetKey( assetInfo.getKey() );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package com.jme3.system;
|
package com.jme3.system;
|
||||||
|
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import com.jme3.util.AndroidLogHandler;
|
import com.jme3.util.AndroidLogHandler;
|
||||||
import com.jme3.asset.AndroidAssetManager;
|
import com.jme3.asset.AndroidAssetManager;
|
||||||
@ -12,6 +13,7 @@ import com.jme3.audio.AudioRenderer;
|
|||||||
import com.jme3.audio.Environment;
|
import com.jme3.audio.Environment;
|
||||||
import com.jme3.audio.Listener;
|
import com.jme3.audio.Listener;
|
||||||
import com.jme3.audio.ListenerParam;
|
import com.jme3.audio.ListenerParam;
|
||||||
|
import com.jme3.audio.android.AndroidAudioRenderer;
|
||||||
//import com.jme3.audio.DummyAudioRenderer;
|
//import com.jme3.audio.DummyAudioRenderer;
|
||||||
import com.jme3.system.JmeContext.Type;
|
import com.jme3.system.JmeContext.Type;
|
||||||
import com.jme3.system.android.OGLESContext;
|
import com.jme3.system.android.OGLESContext;
|
||||||
@ -93,9 +95,11 @@ public class JmeSystem
|
|||||||
private static boolean initialized = false;
|
private static boolean initialized = false;
|
||||||
private static boolean lowPermissions = false;
|
private static boolean lowPermissions = false;
|
||||||
private static Resources res;
|
private static Resources res;
|
||||||
|
private static Activity activity;
|
||||||
|
|
||||||
public static void initialize(AppSettings settings)
|
public static void initialize(AppSettings settings)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (initialized)
|
if (initialized)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -116,7 +120,7 @@ public class JmeSystem
|
|||||||
|
|
||||||
public static String getFullName()
|
public static String getFullName()
|
||||||
{
|
{
|
||||||
return "jMonkey Engine 3 ALPHA 0.6 Android";
|
return "jMonkey Engine 3 ALPHA 0.7 Android";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setLowPermissions(boolean lowPerm)
|
public static void setLowPermissions(boolean lowPerm)
|
||||||
@ -137,28 +141,7 @@ public class JmeSystem
|
|||||||
|
|
||||||
public static AudioRenderer newAudioRenderer(AppSettings settings)
|
public static AudioRenderer newAudioRenderer(AppSettings settings)
|
||||||
{
|
{
|
||||||
return new AudioRenderer()
|
return new AndroidAudioRenderer(activity);
|
||||||
{
|
|
||||||
public void setListener(Listener listener) {}
|
|
||||||
public void setEnvironment(Environment env) {}
|
|
||||||
public void playSourceInstance(AudioNode src) {}
|
|
||||||
public void playSource(AudioNode src) {}
|
|
||||||
public void pauseSource(AudioNode src) {}
|
|
||||||
public void stopSource(AudioNode src) {}
|
|
||||||
public void deleteAudioData(AudioData ad) {}
|
|
||||||
public void initialize() {}
|
|
||||||
public void update(float tpf) {}
|
|
||||||
public void cleanup() {}
|
|
||||||
public void updateListenerParam(Listener listener,
|
|
||||||
ListenerParam param) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
public void updateSourceParam(AudioNode src, AudioParam param) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setResources(Resources res)
|
public static void setResources(Resources res)
|
||||||
@ -171,6 +154,17 @@ public class JmeSystem
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void setActivity(Activity activity)
|
||||||
|
{
|
||||||
|
JmeSystem.activity = activity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Activity getActivity()
|
||||||
|
{
|
||||||
|
return activity;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static AssetManager newAssetManager()
|
public static AssetManager newAssetManager()
|
||||||
{
|
{
|
||||||
logger.info("newAssetManager()");
|
logger.info("newAssetManager()");
|
||||||
|
@ -25,6 +25,8 @@ public class AndroidConfigChooser implements EGLConfigChooser
|
|||||||
protected ConfigType type;
|
protected ConfigType type;
|
||||||
protected int pixelFormat;
|
protected int pixelFormat;
|
||||||
|
|
||||||
|
protected boolean verbose = false;
|
||||||
|
|
||||||
private final static int EGL_OPENGL_ES2_BIT = 4;
|
private final static int EGL_OPENGL_ES2_BIT = 4;
|
||||||
|
|
||||||
public enum ConfigType
|
public enum ConfigType
|
||||||
@ -39,9 +41,10 @@ public class AndroidConfigChooser implements EGLConfigChooser
|
|||||||
BEST
|
BEST
|
||||||
}
|
}
|
||||||
|
|
||||||
public AndroidConfigChooser(ConfigType type)
|
public AndroidConfigChooser(ConfigType type, boolean verbose)
|
||||||
{
|
{
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
this.verbose = verbose;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -70,9 +73,14 @@ public class AndroidConfigChooser implements EGLConfigChooser
|
|||||||
EGLConfig[] conf = new EGLConfig[configurations];
|
EGLConfig[] conf = new EGLConfig[configurations];
|
||||||
egl.eglGetConfigs(display, conf, configurations, num_conf);
|
egl.eglGetConfigs(display, conf, configurations, num_conf);
|
||||||
|
|
||||||
|
|
||||||
int[] value = new int[1];
|
int[] value = new int[1];
|
||||||
|
|
||||||
|
|
||||||
|
if (configurations <= 0)
|
||||||
|
{
|
||||||
|
logger.severe("###ERROR### ZERO EGL Configurations found, This Is a Problem");
|
||||||
|
}
|
||||||
|
|
||||||
// Loop over all configs to get the best
|
// Loop over all configs to get the best
|
||||||
for(int i = 0; i < configurations; i++)
|
for(int i = 0; i < configurations; i++)
|
||||||
{
|
{
|
||||||
@ -94,27 +102,57 @@ public class AndroidConfigChooser implements EGLConfigChooser
|
|||||||
bestConfig = better(bestConfig, conf[i], egl, display);
|
bestConfig = better(bestConfig, conf[i], egl, display);
|
||||||
fastestConfig = faster(fastestConfig, conf[i], egl, display);
|
fastestConfig = faster(fastestConfig, conf[i], egl, display);
|
||||||
|
|
||||||
logger.info("Supported EGL Configuration #" + i );
|
if (verbose)
|
||||||
|
{
|
||||||
|
logger.info("** Supported EGL Configuration #" + i );
|
||||||
|
logEGLConfig(conf[i], display, egl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (verbose)
|
||||||
|
{
|
||||||
|
logger.info("NOT Supported EGL Configuration #" + i + " EGL_OPENGL_ES2_BIT not set");
|
||||||
|
logEGLConfig(conf[i], display, egl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (verbose)
|
||||||
|
{
|
||||||
|
logger.info("NOT Supported EGL Configuration #" + i + " EGL_DEPTH_SIZE != 16");
|
||||||
logEGLConfig(conf[i], display, egl);
|
logEGLConfig(conf[i], display, egl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (verbose)
|
||||||
|
{
|
||||||
|
logger.info("NOT Supported EGL Configuration #" + i + " EGL_WINDOW_BIT not set");
|
||||||
|
logEGLConfig(conf[i], display, egl);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
break;
|
logger.severe("###ERROR### EGL Configuration #" + i + " is NULL");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if ((type == ConfigType.BEST) && (bestConfig != null))
|
if ((type == ConfigType.BEST) && (bestConfig != null))
|
||||||
{
|
{
|
||||||
logger.info("### JME3 ### using best EGL configuration available here: ");
|
logger.info("JME3 using best EGL configuration available here: ");
|
||||||
choosenConfig = bestConfig;
|
choosenConfig = bestConfig;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logger.info("### JME3 ### using fastest EGL configuration available here: ");
|
if (fastestConfig != null)
|
||||||
|
{
|
||||||
|
logger.info("JME3 using fastest EGL configuration available here: ");
|
||||||
|
}
|
||||||
choosenConfig = fastestConfig;
|
choosenConfig = fastestConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +165,7 @@ public class AndroidConfigChooser implements EGLConfigChooser
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logger.severe("Unable to get a valid OpenGL ES 2.0 config");
|
logger.severe("###ERROR### Unable to get a valid OpenGL ES 2.0 config, nether Fastest nor Best found! Bug. Please report this.");
|
||||||
clientOpenGLESVersion = 1;
|
clientOpenGLESVersion = 1;
|
||||||
pixelFormat = PixelFormat.UNKNOWN;
|
pixelFormat = PixelFormat.UNKNOWN;
|
||||||
return false;
|
return false;
|
||||||
|
@ -75,7 +75,7 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer
|
|||||||
protected final AtomicBoolean created = new AtomicBoolean(false);
|
protected final AtomicBoolean created = new AtomicBoolean(false);
|
||||||
protected final AtomicBoolean renderable = new AtomicBoolean(false);
|
protected final AtomicBoolean renderable = new AtomicBoolean(false);
|
||||||
protected final AtomicBoolean needClose = new AtomicBoolean(false);
|
protected final AtomicBoolean needClose = new AtomicBoolean(false);
|
||||||
protected final Object createdLock = new Object();
|
|
||||||
protected final AppSettings settings = new AppSettings(true);
|
protected final AppSettings settings = new AppSettings(true);
|
||||||
|
|
||||||
/* >= OpenGL ES 2.0 (Android 2.2+) */
|
/* >= OpenGL ES 2.0 (Android 2.2+) */
|
||||||
@ -127,7 +127,7 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer
|
|||||||
*/
|
*/
|
||||||
public GLSurfaceView createView(AndroidInput view)
|
public GLSurfaceView createView(AndroidInput view)
|
||||||
{
|
{
|
||||||
return createView(view, ConfigType.FASTEST);
|
return createView(view, ConfigType.FASTEST, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -136,7 +136,7 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer
|
|||||||
* @param debugflags 0, GLSurfaceView.DEBUG_CHECK_GL_ERROR | GLSurfaceView.DEBUG_LOG_GL_CALLS
|
* @param debugflags 0, GLSurfaceView.DEBUG_CHECK_GL_ERROR | GLSurfaceView.DEBUG_LOG_GL_CALLS
|
||||||
* @return GLSurfaceView The newly created view
|
* @return GLSurfaceView The newly created view
|
||||||
*/
|
*/
|
||||||
public GLSurfaceView createView(AndroidInput view, ConfigType configType)
|
public GLSurfaceView createView(AndroidInput view, ConfigType configType, boolean eglConfigVerboseLogging)
|
||||||
{
|
{
|
||||||
EGL10 egl = (EGL10) EGLContext.getEGL();
|
EGL10 egl = (EGL10) EGLContext.getEGL();
|
||||||
EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
|
EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
|
||||||
@ -151,7 +151,7 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer
|
|||||||
this.view = view;
|
this.view = view;
|
||||||
|
|
||||||
// Create a config chooser
|
// Create a config chooser
|
||||||
AndroidConfigChooser configChooser = new AndroidConfigChooser(configType);
|
AndroidConfigChooser configChooser = new AndroidConfigChooser(configType, eglConfigVerboseLogging);
|
||||||
// Init chooser
|
// Init chooser
|
||||||
if (!configChooser.findConfig(egl, display))
|
if (!configChooser.findConfig(egl, display))
|
||||||
{
|
{
|
||||||
@ -240,17 +240,23 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer
|
|||||||
*/
|
*/
|
||||||
protected void deinitInThread()
|
protected void deinitInThread()
|
||||||
{
|
{
|
||||||
if (renderer != null)
|
if (renderable.get())
|
||||||
renderer.cleanup();
|
{
|
||||||
|
renderable.set(false);
|
||||||
|
if (renderer != null)
|
||||||
|
renderer.cleanup();
|
||||||
|
|
||||||
listener.destroy();
|
listener.destroy();
|
||||||
|
|
||||||
// do android specific cleaning here
|
listener = null;
|
||||||
logger.info("Display destroyed.");
|
renderer = null;
|
||||||
renderable.set(false);
|
timer = null;
|
||||||
created.set(false);
|
|
||||||
renderer = null;
|
// do android specific cleaning here
|
||||||
timer = null;
|
logger.info("Display destroyed.");
|
||||||
|
|
||||||
|
created.set(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void applySettingsToRenderer(OGLESShaderRenderer renderer, AppSettings settings)
|
protected void applySettingsToRenderer(OGLESShaderRenderer renderer, AppSettings settings)
|
||||||
@ -441,12 +447,10 @@ public class OGLESContext implements JmeContext, GLSurfaceView.Renderer
|
|||||||
|
|
||||||
protected void waitFor(boolean createdVal)
|
protected void waitFor(boolean createdVal)
|
||||||
{
|
{
|
||||||
synchronized (createdLock){
|
while (created.get() != createdVal){
|
||||||
while (created.get() != createdVal){
|
try {
|
||||||
try {
|
Thread.sleep(10);
|
||||||
createdLock.wait();
|
} catch (InterruptedException ex) {
|
||||||
} catch (InterruptedException ex) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user