# 4. Platform Details | Android

## Android Specific Starter Guide

### SDK Version

FMOD is compiled using the following tools.

- NDK - version r21d targeting android-16 (32bit) and android-21 (64bit).
- SDK - platform version 27.1.

### Compatibility

FMOD supports devices of the below ABIs back to API level 16 (Android 4.1, Jelly Bean).

- armeabi-v7a - supported and optimized with VFPv2 (and NEON if detected at runtime).
- arm64-v8a - supported and optimized with NEON.
- x86 - supported and optimized with SSE3.
- x86_64 - supported and optimized with SSE3.
- mips - unsupported due to limited demand.
- mips64 - unsupported due to limited demand.
- armeabi - unsupported from FMOD 2.2 due to NDK deprecation.

### Libraries

Substitute $ABI with your desired ABI from the 'Compatibility' list above.

FMOD Core Engine library

- /api/core/lib/$ABI/libfmod.so - Release binary for production code.
- /api/core/lib/$ABI/libfmodL.so - Release binary with logging enabled for development.

FMOD Studio Engine library (used in conjunction with core library)

- /api/studio/lib/$ABI/libfmodstudio.so - Release binary for production code.
- /api/studio/lib/$ABI/libfmodstudioL.so - Release binary with logging enabled for development.

### Java

FMOD is primarily a native C/C++ library implementation but does have a Java component that is invoked from native code. To ensure the Java component is properly operating please make sure you reference the fmod.jar in your project. This means telling the IDE or build system where to find the fmod.jar file so it's included in the application.

It is also highly recommended that you initialize the FMOD Java component, this will allow loading assets from the APK and automatic configuration for lowest latency. This should be done before System_Create or Studio::System::create, and should be closed after System::release or Studio::System::release.

A basic example is listed below, for more details please check the provided examples.

    public class MainActivity extends Activity
    {
        @Override
        protected void onCreate(Bundle savedInstanceState)
        {
            org.fmod.FMOD.init(this);
        }

        @Override
        protected void onDestroy()
        {
            org.fmod.FMOD.close();
        }
    }

    static
    {
        System.loadLibrary("fmod");
    }

### Examples

FMOD examples are shipped as Android Studio projects using the Gradle build system with the Android Gradle plugin. Examples are provided for using both CMake and ndk-build to perform the external native build:

- /api/(core|studio)/examples/androidstudio/cmake - Examples using CMake to perform the external native build.
- /api/(core|studio)/examples/androidstudio/ndkbuild - Examples using ndk-build to perform the external native build.

### Linking FMOD to your code

To link FMOD into your native code refer to the Android documentation relevant to the build tools you are using. You may also find it helpful to refer to the Android.mk files or the CMakeLists.txt files from the FMOD examples.

### Audio Latency

Reducing the amount of audio latency between calling an API function and hearing its effect is generally controlled via System::setDSPBufferSize. However it should be noted that on this platform there is significantly more OS latency (which is out of the control of developers). It is currently not mandatory for device manufactures to adhere to audio latency guidelines (section 5.3 Audio Latency of the Android CDD). Devices which report FEATURE_AUDIO_LOW_LATENCY will be able to achieve lower latency playback. This is handled internally by FMOD and requires no additional configuration. Latency test results for specific devices can be found on the Superpowered Latency Table.

Pairing with a BlueTooth speaker or headset will incur significant extra latency, 120ms in some tests. This is currently unavoidable due to the OS taking extra buffering beyond developer control.

### Asset Manager

To load files from the APK using the Asset Manager (for files stored in the asset directory at build time) you need to use a special syntax. FMOD will recognize any path that is prefixed with file:///android_asset/ as an asset, so passing a path of file:///android_asset/drumloop.wav will load the file drumloop.wav which was stored in the asset directory at build time. For this functionality to work your device must be running Gingerbread or newer and have called org.fmod.FMOD.init from Java.

### Native Threads

If you call FMOD from a native thread (not Java) you will need to ensure the thread is attached to the Java runtime environment JavaVM::AttachCurrentThread. It's recommended you remain attached for the life of the thread but you may call JavaVM::DetachCurrentThread after the invocation of FMOD if you prefer.

FMOD often makes calls to Java code contained within fmod.jar and therefore requires the thread to be attached. All internal FMOD threads are attached when they are created so this only concerns user threads.

### Suspend in Background

FMOD native threads will continue running when your application transitions to the background, this will continue to use resources. To completely stop FMOD without losing your current setup you can call System::mixerSuspend as part of your backgrounding process. When you return to the foreground, use System::mixerResume to reactivate FMOD. It is extremely important to ensure no FMOD APIs are called in-between suspend and resume as they run the risk of causing a deadlock. You must also call suspend and resume pairs on the same thread.

### Permissions

Some functionality inside of FMOD will require you set relevant permissions in your AndroidManifest.xml file.

- Recording - to make use of the System::recordStart API use android.permission.RECORD_AUDIO.
- Networking - to use the FMOD profiler, FMOD Studio live update or stream audio from the internet use android.permission.INTERNET.

### Thread Affinity

All threads will default to FMOD_THREAD_AFFINITY_CORE_ALL, this is recommended due to the wide variety of devices available but can be customized with Thread_SetAttributes.

### Thread Priority

The relationship between FMOD platform agnostic thread priority and the platform specific values is as follows:

- FMOD_THREAD_PRIORITY_LOW ~ 5
- FMOD_THREAD_PRIORITY_MEDIUM ~ 0
- FMOD_THREAD_PRIORITY_HIGH ~ -8
- FMOD_THREAD_PRIORITY_VERY_HIGH ~ -16
- FMOD_THREAD_PRIORITY_EXTREME ~ -18
- FMOD_THREAD_PRIORITY_CRITICAL ~ -19

### Known Issues

- The Audio Track output mode currently does not support recording, please use the OpenSL output mode for this.
- The Snapdragon Profiler created by Qualcomm has a bug when displaying system trace information. The trace will indicate that the "AudioTrack" thread executes for several milliseconds when in fact it does not. The "AudioTrack" thread is created by the OpenSL output plugin and is responsible for calling into FMOD to fetch audio. FMOD services this request efficiently with lock free data structures and returns in microseconds to avoid any audio glitches. To verify the behavior of this thread use the Android System Trace viewer instead of the Snapdragon Profiler.

## Application Lifecycle Management

FMOD will happily continue to operate when your device is in the background, for media playback applications this may be desirable. For the vast majority of use cases though, you want FMOD to be quiet and use no CPU. You can achieve this goal by using System::mixerSuspend and System::mixerResume, often it is convenient to implement these in the activity onStart and onStop overrides. To avoid issues when shutting down ensure you resume the mixer before releasing, it is recommended you perform this in the onDestroy override.

Example Java code

    @Override
    protected void onStart()
    {
        super.onStart();
        setStateStart();
    }

    @Override
    protected void onStop()
    {
        setStateStop();
        super.onStop();
    }

    @Override
    protected void onDestroy()
    {
        setStateDestroy();
        super.onDestroy();
    }

    private native void setStateStart();
    private native void setStateStop();
    private native void setStateDestroy();

Example C++ code

    void Java_org_fmod_example_MainActivity_setStateStart(JNIEnv *env, jobject thiz)
    {
        gSystem->mixerResume();
    }

    void Java_org_fmod_example_MainActivity_setStateStop(JNIEnv *env, jobject thiz)
    {
        gSystem->mixerSuspend();
    }

    void Java_org_fmod_example_MainActivity_setStateDestroy(JNIEnv *env, jobject thiz)
    {
        gSystem->mixerResume();
    }

The result of using this API will be the halt of the audio hardware and a complete lock of all FMOD threads. It is important that you do not call any FMOD API functions after System::mixerSuspend other than System::mixerResume, even if you intend to shutdown FMOD as you may cause a deadlock.

## Performance Reference

This section is a companion for the CPU Performance white paper and serves as a quick reference of facts targeting this platform.

### Format Choice

Each compression format provided in FMOD has a reason for being included, the below list will detail our recommendations for this platform. Formats listed as primary are considering the best choice, secondary formats should only be considered if the primary doesn't satisfy your requirements.

- FADPCM: Primary format for all sounds.
- Vorbis: Secondary format for long streams if FADPCM compression is too low.
- PCM: Secondary format for short sounds if FADPCM cost is too high.
- XMA: Unavailable.
- AT9: Unavailable.

### Channel Count

To give developers an idea about the costs of a particular format we provide synthetic benchmark results. These results are based on simple usage of the FMOD Studio API using recommended configuration settings.

Due to the CPU governor that controls the power saving features of the device, getting accurate CPU numbers requires rooting the device and setting the CPU frequency to maximum.

#### Settings

- Real channel count: 32
- Sample rate: 24KHz
- Speaker mode: Stereo
- DSP block size: 512 samples

#### Test Device: A

- CPU: SHIELD Android TV
- OS: Android 9

#### Results: A

- DSP with Vorbis: 8.66% (+/- 1.28%)
- DSP with FADPCM: 2.64% (+/- 0.21%)
- DSP with PCM: 1.98% (+/- 0.22%)
- Update at 60 FPS: 1.48% (+/- 6.86%)

#### Test Device: B

- CPU: Redmi 5A
- OS: Android 8.1.0

#### Results: B

- DSP with Vorbis: 21.29% (+/- 5.11%)
- DSP with FADPCM: 5.45% (+/- 0.72%)
- DSP with PCM: 4.63% (+/- 0.69%)
- Update at 60 FPS: 3.72% (+/- 2.93%)