Android Sound Latency Fix

If you’re developing mobile games for Android, you’ve probably noticed ridiculous sound delay on some devices.
No more. With this plugin, your sounds will play almost immediately. Check out this demo video:

Features:

  • Play in-game sounds without any delay on Android devices
  • Simultaneous playback of several sounds
  • All kinds of Android built-in audio file formats are supported
  • Plugin uses Android Sound Pool for managing and using sound files
  • Doesn’t conflict with Unity sound system

It works by issuing direct calls to the Android OS, bypassing everything that Unity has in its audio system. It means that sounds won’t be affected by distance, Doppler, project volume settings etc, which is perfectly acceptable for most of the Android games. In our game, music is played by Unity and short sounds are managed by this plugin, with no issues.

Usage is simple:

  • Send filename of sound and get its ID’s with AudioCenter.loadSound(path_to_file) method
  • Play it with AudioCenter.playSound(sound_id) method
  • Unload it with AudioCenter.unloadSound(sound_id) method to save memory
    For more detailed instructions, refer to the .pdf, supplied with the plugin.

Download it directly from our website: http://catsknead.me/static/plugin.zip

In the archive you’ll find .unitypackage, .pdf with detailed instructions, .java file, containing full source of the Android-side of the plugin and a test scene, in which you can compare two playback methods.
If you see no sound delay in the provided example scene - you probably have a lucky device, try another one :slight_smile:

Coming to the Asset Store soon.

4 Likes

Thanks! should be useful

Thank you so much :slight_smile:

This seems a nice solution.

I’m trying to do this with accessing AudioCenter.cs with javascript.
I imported the package and I have made a folder Assets/Resources/Sounds/ with the soundfile.
I moved the file AudioCenter.cs to the folder Assets/Plugins and changed the line “public class AudioCenter” into “public class AudioCenter: MonoBehaviour”

I have made the following javascript:

#pragma strict

private var csScript: AudioCenter; //create a variable to access the C# script
public var soundID: int;

function Start ()
{
    csScript = this.GetComponent(AudioCenter);
}

function loadPluginSound ()
{
    soundID = csScript.loadSound("Resources/Sounds/Example.wav");
}

function PlayExample ()
{
    csScript.playSound (soundID);
}

This is the file AudioCenter.cs:

using UnityEngine;
using System.Collections;

public class AudioCenter: MonoBehaviour
{
    #if UNITY_ANDROID && !UNITY_EDITOR
    public static AndroidJavaClass unityActivityClass = new AndroidJavaClass( "com.unity3d.player.UnityPlayer" );
    public static AndroidJavaObject activityObj = unityActivityClass.GetStatic<AndroidJavaObject>( "currentActivity" );
    private static AndroidJavaObject soundObj = new AndroidJavaObject( "com.catsknead.androidsoundfix.AudioCenter", 1, activityObj, activityObj );
   
    public static void playSound( int soundId ) {
        soundObj.Call( "playSound", new object[] { soundId } );
    }
   
    public static int loadSound( string soundName ) {
        return soundObj.Call<int>( "loadSound", new object[] { soundName } );
    }
   
    public static void unloadSound( int soundId ) {
        soundObj.Call( "unloadSound", new object[] { soundId } );
    }
    #else
    public static void playSound( int soundId ) {
        Debug.Log( "Play sound called: " + soundId.ToString() );
    }
   
    public static int loadSound( string soundName ) {
        Debug.Log( "Load sound called: " + soundName );
        return 0;
    }
   
    public static void unloadSound( int soundId ) {
        Debug.Log( "Unload sound called: " + soundId.ToString() );
    }
    #endif
}

I attached these two scripts to the gameobject and I created an Audio Source. I unchecked “3D Sound” in the Inspector.
In my game I call the function PlayExample () but I don’t hear anything.
There are no errors and in the console I see: Load sound called: Resources/Sounds/example.wav and Play sound called: 0.

I think I forgot something. What am I doing wrong?

I found out that I don’t have to access AudioCenter.cs with javascript. It’s working fine now.
But I have one question.
What is this part of AudioCenter.cs doing?

 public static AndroidJavaClass unityActivityClass = new AndroidJavaClass( "com.unity3d.player.UnityPlayer" );
    public static AndroidJavaObject activityObj = unityActivityClass.GetStatic<AndroidJavaObject>( "currentActivity" );
    private static AndroidJavaObject soundObj = new AndroidJavaObject( "com.catsknead.androidsoundfix.AudioCenter", 1, activityObj, activityObj );

Sorry for not replying. I’m not experienced with JS, so I can’t tell what’s wrong there, your code seems fine to me :frowning:

This part of the code prepares all the necessary Java objects for the plugin to use.
First line retrieves the actual UnityPlayer of the game, second - gets the current activity object, third one creates an instance of the AudioCenter Java class (our plugin), with this number of streams and activity passed to the constructor.
For some reason I’ve published plugin that was built from non-refactored code, that’s why there are two activityObj passed, please ignore that… included source is the refactored one, though.

Check out examples here: http://docs.unity3d.com/Manual/PluginsForAndroid.html

Oh, and you don’t need Audio Source or Audio Listener with this plugin.

Thanks for reply!
I’m totally not experienced with this Java stuff yet.
Is it right that you need something from your website to make it work (third line)? So that you need an internet connection to make it work?

If I want to play midi files instead of these sound files,how can I do?

No, not at all! That’s just a package name.

All these formats should work, including midi:
https://developer.android.com/guide/appendix/media-formats.html#core

It’s working great!
Thanks Catsknead!

One question.
When I push the game to my Android device the sounds are perfect but when I play the game in the Unity editor, I don’t hear the sounds anymore.
Why is that?

@Catsknead ty!

@herbie_1 Because you’re on the Unity editor not android!

I did some similar experiments.

I’ve found that the latency varies significantly between devices. A simple demo with a bouncing ball that played a sound in the collider looked fine on various Nexus tablets, but was seriously off on my Moto X. So there’s definitely a device-specific component, but the fact that you can get much better latency by side-stepping Unity suggests that it’s possible for Unity to do better.

(Demo project on github)

@sonicviz
All your games have something to do with sound, did you manage to use this fix already? just curious…

Strange how this is such an underdiscussed issue. The audio latency was the very first thing that i noted when i first tried my build on android.

I got it to work!

Is there a way to manage certain parameters of the sounds? like volume etc.?

Unfortunately, for now it totally relies on the system volume, so the only way to change it is to change the system volume through special permission. Users probably won’t be happy with such intervention.
We made our sounds more silent by opening them in Audacity and amplifying them by negative dB. If you have lots of files - you can use batch processing:

  • Open Audacity
  • File > Edit Chains
  • Remove everything
  • Insert “Amplify”
  • Edit parameter
  • OK
  • File > Apply chain > Apply to Files > Select them…

It certainly is possible to change the volume of individual .play() calls, but for now we’re really busy with porting our game to iOS and won’t be able to update this plugin for a week or so… sources are open, everyone is welcome to tweak them :slight_smile:

1 Like

help me alot, thanks you so much
have a problems, it conflict with Ultimate Mobile plugin, i don’t know how to fix

If anyone needs volume control, you could add those 2 overloads to the AudioCenter.java of Catsknead.and then it should work

public void playSound( int soundID, float volume ){
        if( ( !soundsSet.contains( soundId ) ) || ( soundId == 0 ) ) {
            Log.e( "SoundPluginUnity", "File has not been loaded!" );
            return;
        }

        final int sKey = soundId;

        activity.runOnUiThread( new Runnable() {
            public void run() {
                 play( sKey, volume, volume, 1, 0, 1f );
            }
        } );
      
    }
   
    public void playSound( int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate ){
       if( ( !soundsSet.contains( soundId ) ) || ( soundId == 0 ) ) {
            Log.e( "SoundPluginUnity", "File has not been loaded!" );
            return;
        }

        final int sKey = soundId;

        activity.runOnUiThread( new Runnable() {
            public void run() {
                 play( sKey, leftVolume, rightVolume, priority, loop, rate );
            }
        } );
    }

I wasn’t able to compile the .java to a jar because i have no tools installed for this, and the command line “javac” gives me errors.

I’m unable to play multiple sounds at the same time.
When my character jumps and hits a coin the jump sound is immediately overridden by the coin sound :c

Hello Saishy,
can you post your code in order to help you…
Your load, play (and unload if you use it)

EDIT : What version of unity are you using ?

Thx,
David