Volume too low when playing wav files using FMOD Core API

Hello. I am using FMOD Core API on Android. The volume when I play a wav file using FMOD is lower than when using another audio player. I tried setting channel volume to 1.0, but it is still too low. Is it normal? Maybe I can use a value higher than 1.0, but it may produce distortion. Is there a “safe” value above 1.0 I can use without distortion? Is there a way to play wav files with the same volume as the default Android media player?

Hi,

What version of FMOD are you using?

Does this happen for all .wav files or just one? If you try other file formats do you also experience this behavior?

Have there been any Fader changes in your Studio Project that may be affecting the volume of the event in the application?

Thank you for your answer.

This happen for all files (wav, mp3…). I am using 1.10.20. I tried updating to 2.02.12 and problem is gone: the volume is louder. So, I think I should upgrade to 2.02.12. I didn’t upgrade yet because of this problem: Lag when calling FMOD_System_Init in 2.02.07 (vs 1.10.20). But I think I have to find a workaround.

I’m still having this issue with 2.02.12 on some devices.

Hi,

Thank you for that information.

Unfortunately, versions older than 2.01 are no longer supported.

This may be linked to a known issue with sounds being interfered with by the OS limiter, in versions 2.02 and older this can be solved using the FMOD_INIT_CLIP_OUTPUT INITFLAG (FMOD API | Core API Reference) passing this in the System::init (FMOD API | Core API Reference). This flag enables hard clipping of output values greater than 1.0f or less than -1.0f.

In regards to the lag issue, the workarounds listed in the linked forum post are still valid.

Hope this helps!

Hi,

If this is the same issue experienced in this forum post: Ogg file is quieter and thinner using FMOD

I had some follow-up questions posted there but it might be worth trying the solution listed above.

Hope this helps.

Thank you for your reply. I tried FMOD_INIT_CLIP_OUTPUT with no luck. I discovered that FMOD v2 is playing with louder volume than v1 because v1 is using OPENSL, and v2 is using AAUDIO by default. So, I tried the 3 available output modes, and here is the result:

  • FMOD_OUTPUTTYPE_OPENSL: Volume is too quiet. But everything works fine.

  • FMOD_OUTPUTTYPE_AUDIOTRACK: Volume is louder than any other output mode I tried (perfect!). But “getPosition” method is not as precise as the other output modes (but I can live with it).

  • FMOD_OUTPUTTYPE_AAUDIO: Volume is louder enough. But there are other problems: the lag when I call FMOD_System_Init exists, but I can live with it. And I noticed another problem: if I press home button while a sound is played, FMOD_System_MixerSuspend is called, and when I return to the app FMOD_System_MixerResume is called, and then (after some calls to FMOD_System_Update) an annoying crackling sound appears. I tried pausing channels before calling MixerSuspend, and I even tried completely releasing FMOD. But when I initialize FMOD again, the crackling sound appears… It’s like some data is kept on buffers even when releasing FMOD…

So, do you know what this crackling sound is, and how to fix it? If not, can I always use AudioTrack? Are there any downsides or any problems if I always use AudioTrack?

Also, when using AAUDIO this error is appearing several times per second (even with FMOD samples):

2023-02-17 11:56:00.077 31358-31803 BLASTBufferQueue org.fmod.example E [VRI[MainActivity]#0](f:0,a:3) Faking releaseBufferCallback from transactionCompleteCallback

I am using FMOD v2.02.12, and a Pixel 6 Pro with the latest Android version available. And all the tests are done without using earphones (directly through the phone speakers).

About the “crackling” sound I talked about in my previous post, I modified the play_sound.cpp example so you can reproduce it. Just play a sound (swish, for example), and before it ends, press Down to stop the channel and call mixerSuspend(). Then, press D to call mixerResume() and you will hear a something like a “crack” or “pop” sound. Sometimes that annoying sound is loud, and sometimes is quiet so, please, try several times

Here is the code:

/*==============================================================================
Play Sound Example
Copyright (c), Firelight Technologies Pty, Ltd 2004-2023.

This example shows how to simply load and play multiple sounds, the simplest 
usage of FMOD. By default FMOD will decode the entire file into memory when it
loads. If the sounds are big and possibly take up a lot of RAM it would be
better to use the FMOD_CREATESTREAM flag, this will stream the file in realtime
as it plays.

For information on using FMOD example code in your own programs, visit
https://www.fmod.com/legal
==============================================================================*/
#include "fmod.hpp"
#include "common.h"

int FMOD_Main()
{
    FMOD::System     *system;
    FMOD::Sound      *sound1, *sound2, *sound3;
    FMOD::Channel    *channel = 0;
    FMOD_RESULT       result;
    void             *extradriverdata = 0;
    bool             isSuspendedState = false;
    
    Common_Init(&extradriverdata);

    /*
        Create a System object and initialize
    */
    result = FMOD::System_Create(&system);
    ERRCHECK(result);

    result = system->init(32, FMOD_INIT_NORMAL, extradriverdata);
    ERRCHECK(result);

    result = system->createSound(Common_MediaPath("drumloop.wav"), FMOD_DEFAULT, 0, &sound1);
    ERRCHECK(result);

    result = sound1->setMode(FMOD_LOOP_OFF);    /* drumloop.wav has embedded loop points which automatically makes looping turn on, */
    ERRCHECK(result);                           /* so turn it off here.  We could have also just put FMOD_LOOP_OFF in the above CreateSound call. */

    result = system->createSound(Common_MediaPath("jaguar.wav"), FMOD_DEFAULT, 0, &sound2);
    ERRCHECK(result);

    result = system->createSound(Common_MediaPath("swish.wav"), FMOD_DEFAULT, 0, &sound3);
    ERRCHECK(result);

    /*
        Main loop
    */
    do
    {
        Common_Update();

        if (Common_BtnPress(BTN_ACTION1))
        {
            result = system->playSound(sound1, 0, false, &channel);
            ERRCHECK(result);
        }

        if (Common_BtnPress(BTN_ACTION2))
        {
            result = system->playSound(sound2, 0, false, &channel);
            ERRCHECK(result);
        }

        if (Common_BtnPress(BTN_ACTION3))
        {
            result = system->playSound(sound3, 0, false, &channel);
            ERRCHECK(result);
        }

        if (Common_BtnPress(BTN_DOWN)) {
            channel->stop();
            result = system->mixerSuspend();
            ERRCHECK(result);
            isSuspendedState = true;
        }

        if (Common_BtnPress(BTN_ACTION4)) {
            result = system->mixerResume();
            ERRCHECK(result);
            isSuspendedState = false;
        }

        result = system->update();
        ERRCHECK(result);

        {
            unsigned int ms = 0;
            unsigned int lenms = 0;
            bool         playing = 0;
            bool         paused = 0;
            int          channelsplaying = 0;

            if (channel)
            {
                FMOD::Sound *currentsound = 0;

                result = channel->isPlaying(&playing);
                if ((result != FMOD_OK) && (result != FMOD_ERR_INVALID_HANDLE) && (result != FMOD_ERR_CHANNEL_STOLEN))
                {
                    ERRCHECK(result);
                }

                result = channel->getPaused(&paused);
                if ((result != FMOD_OK) && (result != FMOD_ERR_INVALID_HANDLE) && (result != FMOD_ERR_CHANNEL_STOLEN))
                {
                    ERRCHECK(result);
                }

                result = channel->getPosition(&ms, FMOD_TIMEUNIT_MS);
                if ((result != FMOD_OK) && (result != FMOD_ERR_INVALID_HANDLE) && (result != FMOD_ERR_CHANNEL_STOLEN))
                {
                    ERRCHECK(result);
                }
               
                channel->getCurrentSound(&currentsound);
                if (currentsound)
                {
                    result = currentsound->getLength(&lenms, FMOD_TIMEUNIT_MS);
                    if ((result != FMOD_OK) && (result != FMOD_ERR_INVALID_HANDLE) && (result != FMOD_ERR_CHANNEL_STOLEN))
                    {
                        ERRCHECK(result);
                    }
                }
            }

            system->getChannelsPlaying(&channelsplaying, NULL);

            Common_Draw("==================================================");
            Common_Draw("Play Sound Example.");
            Common_Draw("Copyright (c) Firelight Technologies 2004-2023.");
            Common_Draw("==================================================");
            Common_Draw("");
            Common_Draw("Press %s to play a mono sound (drumloop)", Common_BtnStr(BTN_ACTION1));
            Common_Draw("Press %s to play a mono sound (jaguar)", Common_BtnStr(BTN_ACTION2));
            Common_Draw("Press %s to play a stereo sound (swish)", Common_BtnStr(BTN_ACTION3));
            Common_Draw("Press %s to stop playing channel and call mixerSuspend()", Common_BtnStr(BTN_DOWN));
            Common_Draw("Press %s to  call mixerResume()", Common_BtnStr(BTN_ACTION4));
            Common_Draw("Press %s to quit", Common_BtnStr(BTN_QUIT));
            Common_Draw("");
            Common_Draw("Time %02d:%02d:%02d/%02d:%02d:%02d : %s", ms / 1000 / 60, ms / 1000 % 60, ms / 10 % 100, lenms / 1000 / 60, lenms / 1000 % 60, lenms / 10 % 100, paused ? "Paused " : playing ? "Playing" : "Stopped");
            Common_Draw("Channels Playing %d", channelsplaying);
            Common_Draw("Suspended state: %s", isSuspendedState ? "Suspended" : "Resumed");
        }

        Common_Sleep(50);
    } while (!Common_BtnPress(BTN_QUIT));

    /*
        Shut down
    */
    result = sound1->release();
    ERRCHECK(result);
    result = sound2->release();
    ERRCHECK(result);
    result = sound3->release();
    ERRCHECK(result);
    result = system->close();
    ERRCHECK(result);
    result = system->release();
    ERRCHECK(result);

    Common_Close();

    return 0;
}

Hi,

In our list of OutputTypes (FMOD API | Core API Reference). Using AudioTrack is the default for Android 2.2 and below while AAudio is the default for Android 8.1 and above.

So it would be better to use AAudio.

In relation to the crackling this is due to channel->stop() and system->mixerSuspend() not using any volume ramping. A way to reduce the poping when stopping the audio in the examples would be to use ChannelControl::SetPause() (FMOD API | Core API Reference) which does utilize volume ramping to reduce popping:

Add this somewhere after system->init

FMOD::ChannelGroup* masterBus = nullptr;
result = system->getMasterChannelGroup(&masterBus);
ERRCHECK(result);

Then change the suspend function to:

if (Common_BtnPress(BTN_DOWN)) {
    result = masterBus->setPaused(true);
    ERRCHECK(result);
    isSuspendedState = true;
}

and the resume function to:

if (Common_BtnPress(BTN_ACTION4)) {
    result = masterBus->setPaused(false);
    ERRCHECK(result);
    isSuspendedState = false;
}

Hopefully, you should notice a decrease in the popping.

Thank you for your detailed answer. But, unfortunately, it’s not working. I’m calling masterBus->setPaused(true) before system->mixerSuspend(), but the popping sound is still there. I tried releasing FMOD, and calling init() instead of mixerSuspend / mixerRelease, but the popping is the same. Just to clarify: the popping sound is not produced when calling mixerSuspend(), it’s produced when calling update() after mixerResume() has been called.

So, to sumarize, the problems I’m having with FMOD 2.02.12 and AAUDIO are:

  • Lag at init() (tried setting lower buffer size, but still very noticeable)
  • Popping sound after mixerResume() (or system->init()) if a sound was playing when called mixerRelease() (or system->release())
  • Each call to system-update() writes this error in LogCat: Faking releaseBufferCallback from transactionCompleteCallback

I would be very pleased if they could be fixed somehow.

Here is the popping sound example with your last suggestion added:

/*==============================================================================
Play Sound Example
Copyright (c), Firelight Technologies Pty, Ltd 2004-2023.

This example shows how to simply load and play multiple sounds, the simplest 
usage of FMOD. By default FMOD will decode the entire file into memory when it
loads. If the sounds are big and possibly take up a lot of RAM it would be
better to use the FMOD_CREATESTREAM flag, this will stream the file in realtime
as it plays.

For information on using FMOD example code in your own programs, visit
https://www.fmod.com/legal
==============================================================================*/
#include "fmod.hpp"
#include "common.h"

int FMOD_Main()
{
    FMOD::System     *system;
    FMOD::Sound      *sound1, *sound2, *sound3;
    FMOD::Channel    *channel = 0;
    FMOD_RESULT       result;
    void             *extradriverdata = 0;
    bool             isSuspendedState = false;
    FMOD::ChannelGroup* masterBus = nullptr;
    
    Common_Init(&extradriverdata);

    /*
        Create a System object and initialize
    */
    result = FMOD::System_Create(&system);
    ERRCHECK(result);

    result = system->init(32, FMOD_INIT_NORMAL, extradriverdata);
    ERRCHECK(result);

    result = system->createSound(Common_MediaPath("drumloop.wav"), FMOD_DEFAULT, 0, &sound1);
    ERRCHECK(result);

    result = sound1->setMode(FMOD_LOOP_OFF);    /* drumloop.wav has embedded loop points which automatically makes looping turn on, */
    ERRCHECK(result);                           /* so turn it off here.  We could have also just put FMOD_LOOP_OFF in the above CreateSound call. */

    result = system->createSound(Common_MediaPath("jaguar.wav"), FMOD_DEFAULT, 0, &sound2);
    ERRCHECK(result);

    result = system->createSound(Common_MediaPath("swish.wav"), FMOD_DEFAULT, 0, &sound3);
    ERRCHECK(result);

    result = system->getMasterChannelGroup(&masterBus);
    ERRCHECK(result);

    /*
        Main loop
    */
    do
    {
        Common_Update();

        if (Common_BtnPress(BTN_ACTION1))
        {
            result = masterBus->setPaused(false);
            ERRCHECK(result);

            result = system->playSound(sound1, 0, false, &channel);
            ERRCHECK(result);
        }

        if (Common_BtnPress(BTN_ACTION2))
        {
            result = masterBus->setPaused(false);
            ERRCHECK(result);

            result = system->playSound(sound2, 0, false, &channel);
            ERRCHECK(result);
        }

        if (Common_BtnPress(BTN_ACTION3))
        {
            result = masterBus->setPaused(false);
            ERRCHECK(result);

            result = system->playSound(sound3, 0, false, &channel);
            ERRCHECK(result);
        }

        if (Common_BtnPress(BTN_DOWN)) {
            result = masterBus->setPaused(true);
            ERRCHECK(result);

            result = system->mixerSuspend();
            ERRCHECK(result);

            isSuspendedState = true;
        }

        if (Common_BtnPress(BTN_ACTION4)) {

            result = system->mixerResume();
            ERRCHECK(result);

            isSuspendedState = false;
        }

        result = system->update();
        ERRCHECK(result);

        {
            unsigned int ms = 0;
            unsigned int lenms = 0;
            bool         playing = 0;
            bool         paused = 0;
            int          channelsplaying = 0;

            if (channel)
            {
                FMOD::Sound *currentsound = 0;

                result = channel->isPlaying(&playing);
                if ((result != FMOD_OK) && (result != FMOD_ERR_INVALID_HANDLE) && (result != FMOD_ERR_CHANNEL_STOLEN))
                {
                    ERRCHECK(result);
                }

                result = channel->getPaused(&paused);
                if ((result != FMOD_OK) && (result != FMOD_ERR_INVALID_HANDLE) && (result != FMOD_ERR_CHANNEL_STOLEN))
                {
                    ERRCHECK(result);
                }

                result = channel->getPosition(&ms, FMOD_TIMEUNIT_MS);
                if ((result != FMOD_OK) && (result != FMOD_ERR_INVALID_HANDLE) && (result != FMOD_ERR_CHANNEL_STOLEN))
                {
                    ERRCHECK(result);
                }
               
                channel->getCurrentSound(&currentsound);
                if (currentsound)
                {
                    result = currentsound->getLength(&lenms, FMOD_TIMEUNIT_MS);
                    if ((result != FMOD_OK) && (result != FMOD_ERR_INVALID_HANDLE) && (result != FMOD_ERR_CHANNEL_STOLEN))
                    {
                        ERRCHECK(result);
                    }
                }
            }

            system->getChannelsPlaying(&channelsplaying, NULL);

            Common_Draw("==================================================");
            Common_Draw("Play Sound Example.");
            Common_Draw("Copyright (c) Firelight Technologies 2004-2023.");
            Common_Draw("==================================================");
            Common_Draw("");
            Common_Draw("Press %s to play a mono sound (drumloop)", Common_BtnStr(BTN_ACTION1));
            Common_Draw("Press %s to play a mono sound (jaguar)", Common_BtnStr(BTN_ACTION2));
            Common_Draw("Press %s to play a stereo sound (swish)", Common_BtnStr(BTN_ACTION3));
            Common_Draw("Press %s to stop playing channel and call mixerSuspend()", Common_BtnStr(BTN_DOWN));
            Common_Draw("Press %s to  call mixerResume()", Common_BtnStr(BTN_ACTION4));
            Common_Draw("Press %s to quit", Common_BtnStr(BTN_QUIT));
            Common_Draw("");
            Common_Draw("Time %02d:%02d:%02d/%02d:%02d:%02d : %s", ms / 1000 / 60, ms / 1000 % 60, ms / 10 % 100, lenms / 1000 / 60, lenms / 1000 % 60, lenms / 10 % 100, paused ? "Paused " : playing ? "Playing" : "Stopped");
            Common_Draw("Channels Playing %d", channelsplaying);
            Common_Draw("Suspended state: %s", isSuspendedState ? "Suspended" : "Resumed");
        }

        Common_Sleep(50);
    } while (!Common_BtnPress(BTN_QUIT));

    /*
        Shut down
    */
    result = sound1->release();
    ERRCHECK(result);
    result = sound2->release();
    ERRCHECK(result);
    result = sound3->release();
    ERRCHECK(result);
    result = system->close();
    ERRCHECK(result);
    result = system->release();
    ERRCHECK(result);

    Common_Close();

    return 0;
}

I have just tried a Samsung Galaxy A21s, and AAUDIO volume is a lot lower than AUDIOTRACK. So, it seems that AudioTrack works better for me (with AudioTrack also I don’t have the issues listed in my previous message). The question is: what happens if I use AudioTrack always for all devices (and all Android versions)? Will any device present problems? There will be any issues?

Thank you.

Hi,

In the code you have uploaded, it is still using system->mixerSuspend() which might be the cause of the popping. So I have changed the code to remove any mixer manipulation:

Play Sound Example
#include "fmod.hpp"
#include "common.h"

int FMOD_Main()
{
    FMOD::System     *system;
    FMOD::Sound      *sound1, *sound2, *sound3;
    FMOD::Channel    *channel = 0;
    FMOD_RESULT       result;
    void             *extradriverdata = 0;
    bool             isSuspendedState = false;
    FMOD::ChannelGroup* masterBus = nullptr;
    
    Common_Init(&extradriverdata);

    /*
        Create a System object and initialize
    */
    result = FMOD::System_Create(&system);
    ERRCHECK(result);

    result = system->init(32, FMOD_INIT_NORMAL, extradriverdata);
    ERRCHECK(result);

    result = system->createSound(Common_MediaPath("drumloop.wav"), FMOD_DEFAULT, 0, &sound1);
    ERRCHECK(result);

    result = sound1->setMode(FMOD_LOOP_OFF);    /* drumloop.wav has embedded loop points which automatically makes looping turn on, */
    ERRCHECK(result);                           /* so turn it off here.  We could have also just put FMOD_LOOP_OFF in the above CreateSound call. */

    result = system->createSound(Common_MediaPath("jaguar.wav"), FMOD_DEFAULT, 0, &sound2);
    ERRCHECK(result);

    result = system->createSound(Common_MediaPath("swish.wav"), FMOD_DEFAULT, 0, &sound3);
    ERRCHECK(result);

    result = system->getMasterChannelGroup(&masterBus);
    ERRCHECK(result);

    /*
        Main loop
    */
    do
    {
        Common_Update();

        if (Common_BtnPress(BTN_ACTION1))
        {
            result = system->playSound(sound1, 0, false, &channel);
            ERRCHECK(result);
        }

        if (Common_BtnPress(BTN_ACTION2))
        {
            result = system->playSound(sound2, 0, false, &channel);
            ERRCHECK(result);
        }

        if (Common_BtnPress(BTN_ACTION3))
        {
            result = system->playSound(sound3, 0, false, &channel);
            ERRCHECK(result);
        }

        if (Common_BtnPress(BTN_DOWN)) {
            result = masterBus->setPaused(true);
            ERRCHECK(result);
            isSuspendedState = true;
        }

        if (Common_BtnPress(BTN_ACTION4)) {

            result = masterBus-SetPaused(false);
            ERRCHECK(result);

            isSuspendedState = false;
        }

        result = system->update();
        ERRCHECK(result);

        {
            unsigned int ms = 0;
            unsigned int lenms = 0;
            bool         playing = 0;
            bool         paused = 0;
            int          channelsplaying = 0;

            if (channel)
            {
                FMOD::Sound *currentsound = 0;

                result = channel->isPlaying(&playing);
                if ((result != FMOD_OK) && (result != FMOD_ERR_INVALID_HANDLE) && (result != FMOD_ERR_CHANNEL_STOLEN))
                {
                    ERRCHECK(result);
                }

                result = channel->getPaused(&paused);
                if ((result != FMOD_OK) && (result != FMOD_ERR_INVALID_HANDLE) && (result != FMOD_ERR_CHANNEL_STOLEN))
                {
                    ERRCHECK(result);
                }

                result = channel->getPosition(&ms, FMOD_TIMEUNIT_MS);
                if ((result != FMOD_OK) && (result != FMOD_ERR_INVALID_HANDLE) && (result != FMOD_ERR_CHANNEL_STOLEN))
                {
                    ERRCHECK(result);
                }
               
                channel->getCurrentSound(&currentsound);
                if (currentsound)
                {
                    result = currentsound->getLength(&lenms, FMOD_TIMEUNIT_MS);
                    if ((result != FMOD_OK) && (result != FMOD_ERR_INVALID_HANDLE) && (result != FMOD_ERR_CHANNEL_STOLEN))
                    {
                        ERRCHECK(result);
                    }
                }
            }

            system->getChannelsPlaying(&channelsplaying, NULL);

            Common_Draw("==================================================");
            Common_Draw("Play Sound Example.");
            Common_Draw("Copyright (c) Firelight Technologies 2004-2023.");
            Common_Draw("==================================================");
            Common_Draw("");
            Common_Draw("Press %s to play a mono sound (drumloop)", Common_BtnStr(BTN_ACTION1));
            Common_Draw("Press %s to play a mono sound (jaguar)", Common_BtnStr(BTN_ACTION2));
            Common_Draw("Press %s to play a stereo sound (swish)", Common_BtnStr(BTN_ACTION3));
            Common_Draw("Press %s to stop playing channel and call mixerSuspend()", Common_BtnStr(BTN_DOWN));
            Common_Draw("Press %s to  call mixerResume()", Common_BtnStr(BTN_ACTION4));
            Common_Draw("Press %s to quit", Common_BtnStr(BTN_QUIT));
            Common_Draw("");
            Common_Draw("Time %02d:%02d:%02d/%02d:%02d:%02d : %s", ms / 1000 / 60, ms / 1000 % 60, ms / 10 % 100, lenms / 1000 / 60, lenms / 1000 % 60, lenms / 10 % 100, paused ? "Paused " : playing ? "Playing" : "Stopped");
            Common_Draw("Channels Playing %d", channelsplaying);
            Common_Draw("Suspended state: %s", isSuspendedState ? "Suspended" : "Resumed");
        }

        Common_Sleep(50);
    } while (!Common_BtnPress(BTN_QUIT));

    /*
        Shut down
    */
    result = sound1->release();
    ERRCHECK(result);
    result = sound2->release();
    ERRCHECK(result);
    result = sound3->release();
    ERRCHECK(result);
    result = system->close();
    ERRCHECK(result);
    result = system->release();
    ERRCHECK(result);

    Common_Close();

    return 0;
}

There should not be any issues with using AudioTrack for android devices, however, there is a known issue (FMOD API | Platform Details) Where recording does not work. If this will not affect you then it should be ok!

Hope this helps!

If you’re using it for sound effects, I’ve noticed AUDIOTRACK seems to have way higher latency on some devices, meaning that sounds will start playing noticeably later than AAUDIO.

Thank you for the explanation. If the only issue with AudioTrack is recording, then it’s fine for me, I’m not using recording.

About the popping sound: I would like to call mixerSuspend() (or release()) in Android onStop() callback, as I would like to release resources when not needed. Isn’t it an FMOD issue that should be fixed? It doesn’t feel ok that a popping sound is produced when mixerSuspend() is called while playing any sound, right?

Thank you again for your help

Do yo mean using DSP filters? Which device did you notice delays with? At least I didn’t notice any delays at play using AudioTrack. The delay that I noticed (and I think it’s very annoying) is using AAUDIO, when calling system->init().

No filters. At the start of playing every sound.

Might only be on certain hardware.

1 Like

You can call result = masterBus->setPaused(true); before calling result = system->mixerSuspend(); and implementing a small delay.

Audio is represented as positive and negative numbers, where 0 represents silence. Calling mixer->suspend() while that value is not 0 or silent will cause the pop. Calling setPaused(true) implements a volume ramp that approaches 0 before stopping the audio and reducing the popping. So it isn’t an FMOD issue it is an issue with calling an abrupt stop to the audio that is being played.

I think I did not explain the problem clearly (sorry, my English is not very good). I understand that abruptly calling mixerSuspend(), while a sound is playing, may cause a pop sound. But this is not the case. The pop sound appears when I call update() after mixerResume(), when everything was in silence. It’s like some audio data has been kept in buffer, and it’s played when the mixer is resumed.

I’m attaching this image to explain the problem clearly:

I’m calling masterBus->setPaused(true) and system->mixerSuspend() while a sound is playing. And that’s ok, no problem with that. Then, I wait some time, and after that I call system->mixerResume() and system->update(), a pop sound appears. No other sound is heard (because I paused the masterBus before), only an annoying pop sound. I don’t think that this is the expected behavior.

Hi,

Thank you for the further explanation that made it a lot clearer. Unfortunately, I was still unable to reproduce the issue. Would it be possible to get a copy of the application and audio sources you are using to test on my end? You can either upload the application to your Profiler or DM it to me directly.

Hello,

The issue can be reproduced by following these steps:

  1. Download Android FMOD Engine v2.02.12 from Downloads page
  2. Open the Android Studio project: api/core/examples/androidstudio/ndkbuild/play_sound
  3. Replace the code of play_sound.cpp with the code I’m attaching below
  4. Run on a Pixel 6 Pro (it may be reproducible with other devices as well)
  5. Press C button, then press Down button before the sound finishes, wait, and now press the D button. Now, the pop sound will appear. I recorded the issue in a video: FMOD Popping sound with Pixel 6 Pro - YouTube

Here is the code (it’s the same I sent in a previous message in this post):

/*==============================================================================
Play Sound Example
Copyright (c), Firelight Technologies Pty, Ltd 2004-2023.

This example shows how to simply load and play multiple sounds, the simplest 
usage of FMOD. By default FMOD will decode the entire file into memory when it
loads. If the sounds are big and possibly take up a lot of RAM it would be
better to use the FMOD_CREATESTREAM flag, this will stream the file in realtime
as it plays.

For information on using FMOD example code in your own programs, visit
https://www.fmod.com/legal
==============================================================================*/
#include "fmod.hpp"
#include "common.h"

int FMOD_Main()
{
    FMOD::System     *system;
    FMOD::Sound      *sound1, *sound2, *sound3;
    FMOD::Channel    *channel = 0;
    FMOD_RESULT       result;
    void             *extradriverdata = 0;
    bool             isSuspendedState = false;
    FMOD::ChannelGroup* masterBus = nullptr;

    Common_Init(&extradriverdata);

    /*
        Create a System object and initialize
    */
    result = FMOD::System_Create(&system);
    ERRCHECK(result);

    result = system->init(32, FMOD_INIT_NORMAL, extradriverdata);
    ERRCHECK(result);

    result = system->createSound(Common_MediaPath("drumloop.wav"), FMOD_DEFAULT, 0, &sound1);
    ERRCHECK(result);

    result = sound1->setMode(FMOD_LOOP_OFF);    /* drumloop.wav has embedded loop points which automatically makes looping turn on, */
    ERRCHECK(result);                           /* so turn it off here.  We could have also just put FMOD_LOOP_OFF in the above CreateSound call. */

    result = system->createSound(Common_MediaPath("jaguar.wav"), FMOD_DEFAULT, 0, &sound2);
    ERRCHECK(result);

    result = system->createSound(Common_MediaPath("swish.wav"), FMOD_DEFAULT, 0, &sound3);
    ERRCHECK(result);

    result = system->getMasterChannelGroup(&masterBus);
    ERRCHECK(result);

    /*
        Main loop
    */
    do
    {
        Common_Update();

        if (Common_BtnPress(BTN_ACTION1))
        {
            result = masterBus->setPaused(false);
            ERRCHECK(result);

            result = system->playSound(sound1, 0, false, &channel);
            ERRCHECK(result);
        }

        if (Common_BtnPress(BTN_ACTION2))
        {
            result = masterBus->setPaused(false);
            ERRCHECK(result);

            result = system->playSound(sound2, 0, false, &channel);
            ERRCHECK(result);
        }

        if (Common_BtnPress(BTN_ACTION3))
        {
            result = masterBus->setPaused(false);
            ERRCHECK(result);

            result = system->playSound(sound3, 0, false, &channel);
            ERRCHECK(result);
        }

        if (Common_BtnPress(BTN_DOWN)) {
            result = masterBus->setPaused(true);
            ERRCHECK(result);

            result = system->mixerSuspend();
            ERRCHECK(result);

            isSuspendedState = true;
        }

        if (Common_BtnPress(BTN_ACTION4)) {

            result = system->mixerResume();
            ERRCHECK(result);

            isSuspendedState = false;
        }

        result = system->update();
        ERRCHECK(result);

        {
            unsigned int ms = 0;
            unsigned int lenms = 0;
            bool         playing = 0;
            bool         paused = 0;
            int          channelsplaying = 0;

            if (channel)
            {
                FMOD::Sound *currentsound = 0;

                result = channel->isPlaying(&playing);
                if ((result != FMOD_OK) && (result != FMOD_ERR_INVALID_HANDLE) && (result != FMOD_ERR_CHANNEL_STOLEN))
                {
                    ERRCHECK(result);
                }

                result = channel->getPaused(&paused);
                if ((result != FMOD_OK) && (result != FMOD_ERR_INVALID_HANDLE) && (result != FMOD_ERR_CHANNEL_STOLEN))
                {
                    ERRCHECK(result);
                }

                result = channel->getPosition(&ms, FMOD_TIMEUNIT_MS);
                if ((result != FMOD_OK) && (result != FMOD_ERR_INVALID_HANDLE) && (result != FMOD_ERR_CHANNEL_STOLEN))
                {
                    ERRCHECK(result);
                }

                channel->getCurrentSound(&currentsound);
                if (currentsound)
                {
                    result = currentsound->getLength(&lenms, FMOD_TIMEUNIT_MS);
                    if ((result != FMOD_OK) && (result != FMOD_ERR_INVALID_HANDLE) && (result != FMOD_ERR_CHANNEL_STOLEN))
                    {
                        ERRCHECK(result);
                    }
                }
            }

            system->getChannelsPlaying(&channelsplaying, NULL);

            Common_Draw("==================================================");
            Common_Draw("Play Sound Example.");
            Common_Draw("Copyright (c) Firelight Technologies 2004-2023.");
            Common_Draw("==================================================");
            Common_Draw("");
            Common_Draw("Press %s to play a mono sound (drumloop)", Common_BtnStr(BTN_ACTION1));
            Common_Draw("Press %s to play a mono sound (jaguar)", Common_BtnStr(BTN_ACTION2));
            Common_Draw("Press %s to play a stereo sound (swish)", Common_BtnStr(BTN_ACTION3));
            Common_Draw("Press %s to stop playing channel and call mixerSuspend()", Common_BtnStr(BTN_DOWN));
            Common_Draw("Press %s to  call mixerResume()", Common_BtnStr(BTN_ACTION4));
            Common_Draw("Press %s to quit", Common_BtnStr(BTN_QUIT));
            Common_Draw("");
            Common_Draw("Time %02d:%02d:%02d/%02d:%02d:%02d : %s", ms / 1000 / 60, ms / 1000 % 60, ms / 10 % 100, lenms / 1000 / 60, lenms / 1000 % 60, lenms / 10 % 100, paused ? "Paused " : playing ? "Playing" : "Stopped");
            Common_Draw("Channels Playing %d", channelsplaying);
            Common_Draw("Suspended state: %s", isSuspendedState ? "Suspended" : "Resumed");
        }

        Common_Sleep(50);
    } while (!Common_BtnPress(BTN_QUIT));

    /*
        Shut down
    */
    result = sound1->release();
    ERRCHECK(result);
    result = sound2->release();
    ERRCHECK(result);
    result = sound3->release();
    ERRCHECK(result);
    result = system->close();
    ERRCHECK(result);
    result = system->release();
    ERRCHECK(result);

    Common_Close();

    return 0;
}