I got bit by a similar problem and Cameron mentioned similar advice against calling ->release() in a callback and I also noticed as you did, that calling those same FMOD methods in my class/main thread, there was never a problem…only in ->update() which presumably is also run in main thread and any calls it might also make to the static callback would also be in “main” but yet here we are with this problem…a slight mystery and confusion.
I am not an expert on FMOD, so my approach may be unwarranted and/or overkill, but here’s what I did as a strategy to rectify after Cameron advised against calling release() in the callback:
*In my class that performs FMOD, add an array/vector for a small structure to store a little info to later deal with the functions I originally wanted to perform in the callback, with a flag of “what to do” and the FMOD handle to act upon (sound/channel/???).
*Given the docs stating that ->update() and callbacks are performed in the main thread, during update(), yet ->release() still caused some sort of problem, I was still worried the callbacks were somehow using another thread to deal with some stuff within FMOD, so also created a CriticalSection. Again, probably not necessary, but I was “scared” and did so anyway, because I’m possibly ignorant of how it works
*Create a static pointer to my class on instantiate (nulled during my class destruction)
*In the static call back, enter critical, update the array/vector (my static class pointer gives me access to method/member) with a new element containing the flag of “what to do,” and the handle of sound/channel, exit critical.
*In my class, the same place I call ->update(), add a call to a new method that deals with the array/vector elements left over from any FMOD callback entries that were created.
*In this new method, loop through array/vector within which I:
assign flag/handle from structure to local vars,
delete that array element,
deal with the “what to do” cases from the local vars (releases, other FMOD calls upon channel/sound handle, etc.)
continue loop until empty
Not sure all of this was necessary, but works without problem now