# Non-looping virtual channels stay virtual forever and don't ever stop or get paused

**URL:** <https://qa.fmod.com/t/non-looping-virtual-channels-stay-virtual-forever-and-dont-ever-stop-or-get-paused/21985>\
**Category:** FMOD Engine\
**Created:** [August 10, 2024, 8:39am UTC](https://qa.fmod.com/t/non-looping-virtual-channels-stay-virtual-forever-and-dont-ever-stop-or-get-paused/21985 "2024-08-10T08:39:40Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![svbernem](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/svbernem/32/7037_2.png) [@svbernem](https://qa.fmod.com/u/svbernem)\
**Post date:** [August 10, 2024, 8:39am UTC](https://qa.fmod.com/t/non-looping-virtual-channels-stay-virtual-forever-and-dont-ever-stop-or-get-paused/21985/1 "2024-08-10T08:39:40Z")

</div>

I’m having problems managing the lifetime of non-looping, virtual fmod channels right now. This is what I currently do in my engine:

- create a channel with FMOD\_System\_PlaySound
- create custom bookkeeping for that sound
- poll the channel with FMOD\_Channel\_IsPlaying every frame. If the return value is not FMOD\_OK or isPlaying is false, I consider the channel to have finished playback (because to my understanding these are the symptoms of FMOD cleaning the channel up, which only happens after it has finished playback)
- if I consider a channel to have finished playback, I free my custom bookkeeping and call FMOD\_Channel\_Stop on it.

I have a debug-mode that delays the cleanup of custom bookkeeping and the FMOD\_Channel\_Stop call, so I can look at state in an ingame UI. I can then at some point let the deletions and FMOD\_Channel\_Stop-calls catch up. If I delay too many deletions, some channels will start to go virtual, and on catch- up, they won’t ever be cleaned up. On further inspection, this is because they are still playing and still non-paused, even after they should have finished (virtual) playback.

The basic goal I want to achieve with this is to know when a channel has finished playback, regardless whether it is virtual or not. Right now, the failure to tell if a virtual sound has finished playback leads to my engine keeping the bookkeeping around after debugging, and it starts piling up. I haven’t encountered this in normal gameplay yet, but believe this might happen there aswell if too many channels play at the same time, and that would be bad news and a resource-leak.

What am I doing wrong? How can I tell if a non-looping virtual channel has finished playback?

---

<div class="post-metadata">

**Author:** ![cameron-fmod](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/cameron-fmod/32/261_2.png) [@cameron-fmod](https://qa.fmod.com/u/cameron-fmod)\
**Post date:** [August 15, 2024, 1:30am UTC](https://qa.fmod.com/t/non-looping-virtual-channels-stay-virtual-forever-and-dont-ever-stop-or-get-paused/21985/2 "2024-08-15T01:30:53Z")

</div>

Can you tell me which version of FMOD you are using?

I’m not able to reproduce that behavior here but if you can supply some examples of your code I may have more luck.

As far as I can tell from your description everything appears fine, and in my testing it all works as expected. I also used the FMOD Profiler to watch the channels being created/virtualized/destroyed. One thing that did come up is that you won’t be able to call stop on channels if they have been stolen, you will get an error `FMOD_ERR_CHANNEL_STOLEN`, but calling `->isPlaying` on it will return false.

---

<div class="post-metadata">

**Author:** ![svbernem](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/svbernem/32/7037_2.png) [@svbernem](https://qa.fmod.com/u/svbernem)\
**Post date:** [August 16, 2024, 1:08pm UTC](https://qa.fmod.com/t/non-looping-virtual-channels-stay-virtual-forever-and-dont-ever-stop-or-get-paused/21985/3 "2024-08-16T13:08:14Z")

</div>

I’m using core api version 2.02. The code excerpts below are in a language called jai (which binds to fmod via its C-API). I hope that doesn’t cause too much confusion, as the syntax doesn’t stray too far from C/C++.

platform\_init\_audio is called on application startup. The channels are created with platform\_create\_audio\_playback. Every frame, update\_audio\_input is run, which collects all invalid fmod channels and notifies the game about them. The game then calls platform\_destroy\_audio\_playback on the invalid fmod channels it was notified about, unless I activate the debug mode I mentioned. In that case, all calls to platform\_destroy\_audio\_playback will be delayed until the debug mode is disabled.

VERIFY\_OK\_FMOD asserts if the return value is not FMOD\_OK.

```auto
platform_init_audio :: (){
    PROFILE_FUNCTION();
    {
        PROFILE_SCOPE("FMOD_System_Create");
        VERIFY_OK_FMOD(FMOD_System_Create(*fmod_system, FMOD_VERSION));
    }
    {
        PROFILE_SCOPE("FMOD_System_Init");
        VERIFY_OK_FMOD(FMOD_System_Init(fmod_system, 512, FMOD_INIT_NORMAL, null));
    }

    fmod_sounds.allocator = context.persistent_allocator;
    is_audio_initialized = true;
    is_mixer_active = true;
}

```

```auto
platform_create_audio_playback :: (asset_handle: Audio_Asset_Handle, volume: f32) -> Audio_Playback_Handle{
    DASSERT(is_audio_initialized);

    sound := get_existing(*fmod_sounds, asset_handle).*;
    channel: *FMOD_CHANNEL;
    handle := next_audio_playback_handle;
    
    VERIFY_OK_FMOD(FMOD_System_PlaySound(fmod_system, sound, null, 1, *channel));
    VERIFY_OK_FMOD(FMOD_Channel_SetVolume(channel, volume));
    VERIFY_OK_FMOD(FMOD_Channel_SetVolumeRamp(channel, 1));
    VERIFY_OK_FMOD(FMOD_Channel_SetPaused(channel, 0));

    insert(*fmod_channels, handle, channel);
    next_audio_playback_handle += 1;
    return handle;
}

```

```auto
platform_destroy_audio_playback :: (handle: Audio_Playback_Handle){
    DASSERT(is_audio_initialized);
  
    channel := get_existing(*fmod_channels, handle).*;
  
    //we call this whether the channel is valid or not, which seems to work so far.
    VERIFY_OK_FMOD(FMOD_Channel_Stop(channel));
  
    remove_existing(*fmod_channels, handle);
}

```

```auto
update_audio_input :: (){
    for fmod_channels
        if !is_channel_valid(it)
            array_insert(*platform_input_state.finished_audio_playbacks, it_index);
}

```

```auto
is_channel_valid :: (channel: *FMOD_CHANNEL) -> bool{
    is_playing: s32;
    result := FMOD_Channel_IsPlaying(channel, *is_playing);
    return result == .FMOD_OK && is_playing == 1;
}

```

If you don’t see anything wrong with this code, I could try to create a minimal repro for further debugging/isolation, but that would take some time.

---

<div class="post-metadata">

**Author:** ![cameron-fmod](https://yyz2.discourse-cdn.com/flex036/user_avatar/qa.fmod.com/cameron-fmod/32/261_2.png) [@cameron-fmod](https://qa.fmod.com/u/cameron-fmod)\
**Post date:** [August 20, 2024, 6:36am UTC](https://qa.fmod.com/t/non-looping-virtual-channels-stay-virtual-forever-and-dont-ever-stop-or-get-paused/21985/4 "2024-08-20T06:36:29Z")

</div>

I cannot see anything that jumps out at me immediately, you have probably seen it already but I’ll link our main doc page about virtual voices in case that helps at all: [https://www.fmod.com/docs/2.03/api/white-papers-virtual-voices.html](https://www.fmod.com/docs/2.03/api/white-papers-virtual-voices.html).

Non-looping sounds should naturally end by themselves, but are you saying that yours aren’t? Is that for every sound or only some?  
Are you using any dsp effects that could be keeping the channels alive?

> [Channel](https://www.fmod.com/docs/2.03/api/core-api-channel.html)s are stopped automatically when their playback position reaches the length of the [Sound](https://www.fmod.com/docs/2.03/api/core-api-sound.html) being played. This is not the case however if the [Channel](https://www.fmod.com/docs/2.03/api/core-api-channel.html) is playing a DSP or the [Sound](https://www.fmod.com/docs/2.03/api/core-api-sound.html) is looping, in which case the [Channel](https://www.fmod.com/docs/2.03/api/core-api-channel.html) will continue playing until stop is called. Once stopped, the [Channel](https://www.fmod.com/docs/2.03/api/core-api-channel.html) handle will become invalid and can be discarded and any API calls made with it will return [FMOD\_ERR\_INVALID\_HANDLE](https://www.fmod.com/docs/2.03/api/core-api-common.html#fmod_err_invalid_handle).
