问题
So my game runs smoothly on PC (win 10), but lags on android phone (Mi 9T pro, SD 855, 6GB of ram). I don't mean that only sound lags, but graphics also. When I disable sounds it runs perfectly smooth (as it should).
Yes I know that this question is asked and answered many times. And I tried all offered "solutions", but nothing helps. Tried using 22KHz samples, 44.1Khz, 48Khz. Tried adding 1 second of silence at end of each sample. Didn't help.
I'm loading samples with this method:
private void loadSounds(String path)
{
FileHandle dirHandle;
dirHandle = Gdx.files.internal(path);
for (FileHandle entry: dirHandle.list()) {
Sound sound = new Sound(entry.nameWithoutExtension(), path+"/"+entry.name());
sounds.add(sound);
}
}
Where Sound class looks like this:
public class Sound {
public String name;
private com.badlogic.gdx.audio.Sound soundObject;
public Sound(String name, String filePath) {
this.name = name;
soundObject = Gdx.audio.newSound(Gdx.files.internal(filePath));
}
public void play()
{
soundObject.play();
}
public void play (float pitch)
{
soundObject.play(1,pitch,0);
}
public void stop()
{
soundObject.stop();
}
public void dispose()
{
soundObject.dispose();
}
}
Just a usual way, nothing special. So I'm pre-loading all the sounds samples when app starts and playing them during the game. Playing is causing the lag, to be clear. Any advice on how to get rid of this lag on android is appreciated.
回答1:
Not sure about the lag but you should not play a lot of sounds simultaniously since most devices can output just a view channels. What I usually do is having a sound manager and when a sound is already playing I stop that sound and play the new one in one frame. I personally don't notice the sound that stopped abruptly and I believe a lot of games do it this way.
So just have something like a SoundManager class with a array, list, set or map of all sounds and when you want to play a sound loop trough all and stop them if they are currently playing.
playSound(String soundName){
for (Sound sound : soundMap) {
sound.stop();
}
soundMap.get(soundName).play();
}
You can extend this to having multiple lists of sounds if you do need to play some simultanoiously for whatever reason. You can also keep a list of sounds that are playing or a single sound object to directly access and stop the sound. But with just a couple dozen of sounds mapped you should not have any performance issues.
回答2:
Solved this with more restrictive sound manager class.
First during loading sound sample I'm calculating how long (approximately) each sound sample lasts. Reason for this is that LibGDX Sound class doesn't provide that functionality. Since all my samples are in same format calculation is good enough:
final long WAV_HEADER_SIZE = 2415;
final long WAV_BPS = 41137;
FileHandle file = Gdx.files.internal(filePath);
duration = (long)(1000f * (file.length() - WAV_HEADER_SIZE) / WAV_BPS);
So I'm getting this way sample duration in milliseconds. Samples are 22Khz, 352Kbps.
Then, when ever I play some sound I remember the time playing started so with this duration variable at any time I can calculate is sound still playing or not.
With this I could check how many sounds I'm playing at the same time. Max number I ever reached is 8 at the time. And that happens very rarely and doesn't last long. Common number of samples is 0 to 4 or 5.
Then, I added "priority" field for each play call (values 1 - 10) and before I play the sound I'm calculating beside number of currently playing sample also which sounds has lowest priority.
final int MAX_PRIORITY = 10;
final int MAX_NUMBER_OF_SOUNDS_PLAYED_SIMULTANEITY = 2;
if (muted > 0 || soundName.isEmpty()) return;
Array<Sound> matchedSounds = new Array<Sound>(10);
int playingCount = 0;
int lowestPriority = MAX_PRIORITY + 1;
int lowestPriorityIndex = -1;
for (int i = 0; i<sounds.size; i++){
Sound sound = sounds.get(i);
if (sound.isPlaying()){
if (sound.priority < lowestPriority){
lowestPriority = sound.priority;
lowestPriorityIndex = i;
}
playingCount++;
}
if (sound.name.startsWith(soundName)) {
matchedSounds.add(sounds.get(i));
}
}
if (playingCount > MAX_NUMBER_OF_SOUNDS_PLAYED_SIMULTANEITY){
if (priority <= lowestPriority){
return;
}else{
sounds.get(lowestPriorityIndex).stop();
}
}
So I'm checking first if number of allowed sounds is bigger of number of currently played sounds. If it's not I'm playing new sound regularly.
If it is and new sounds has lower priority than all currently playing sounds I'm just ignoring new sound.
If it is and new sounds isn't lowest with priority I'm stopping lowest one and playing new one.
That way I'm keeping number of currently playing sounds to fixed amount.
And greatest surprise is that maximum number of samples that are not making a lag is 2 at the time ?!?! What kind of sounds system lags when playing 3 or more sounds?!? Something is really wrong here.
Anyway even with max of 2 samples at the time sound sounds ok.... Missing sounds are not noticeable.
来源:https://stackoverflow.com/questions/59022221/sound-makes-app-lags-on-android-any-solution