MonoGame / MonoGame

One framework for creating powerful cross-platform games.
http://www.monogame.net
Other
11.54k stars 2.92k forks source link

SoundEffectInstance not working on Android #2308

Closed azchohfi closed 5 years ago

azchohfi commented 10 years ago

2275 seems to have broke audio on Android (not sure if also on all OpenAL platforms).

Sound just does not play.

I just made a very quick check at SoundEffectInstance.OpenAL.cs, and i think sourceId is never being set on Android, at least not on a possible code path. Everything seems to be broke here. Just look at PlatformPlay method. It checks

if (sourceId == 0)
    return;

but, on Android, sourceId is only set later at this method... So s_soundPool.Play will never play.

Also, _soundId is always -1, and the only place that is could be set is here:

internal SoundEffect(string fileName)

but this method is never called.

2275 broke Android's SoundEffect/SoundEffectInstance for good...

tomspilman commented 10 years ago

I expected something like this would popup... we moved around a lot of code in the last 2 weeks.

@RayBatts - Is this a simple fix?

@KonajuGames - How far off is your Android sound rewrite?

RayBatts commented 10 years ago

It could be a quick fix.. but I'm unable to test it.

PlatformPlay does...

if (sourceId == 0)
    return;

I'm actually pretty sure that changing the == to != is the correct fix here. The only time you wouldn't want to play a sound is if there's already one playing. I believe that's the right move here.

Honestly these source id checks should be completely removed and this functionality should be taken care of by checking the _soundState from the shared code. (So it shouldn't even make it into the Platform code...). Maybe log it as an issue?

internal SoundEffect(string fileName)

That's getting called from ContentManager.ReadRawAsset(). Android never supported SoundEffect.FromStream() or creating a SoundEffect from a byte[] to begin with.

@KonajuGames is close to checking in a rewrite for Android's SoundEffect/SoundEffectInstance code anyway, so I don't know how much needs to be fixed here before it's replaced...

KonajuGames commented 10 years ago

To make my stuff usable with samples with differing sample rates I need to write a resampler. Then it should be good to go.

Layer today I can test the quick fix Ray suggested and then get my rewrite done.

azchohfi commented 10 years ago

I know @KonajuGames is making a big change to this but I need this working to release a game ASAP, so I'm trying to fix the currect code anyway.

I've tested @RayBatts solution, but it didn't work. I'm sure that's part of the solution, but SoundEffect's _soundID value is always -1. I use ReSharper and it is telling me that SoundEffect's constructor:

internal SoundEffect(string fileName)

is never being called. I myself tried to find where it could be called, but found nothing.

I've changed Method ReadRawAsset call the constructor I mentioned on ANDROID. Like this:

#if ANDROID
                return new SoundEffect(assetName);
#else
                using (Stream s = TitleContainer.OpenStream(assetName))
                    return SoundEffect.FromStream(s);
#endif

Doing that, _soundID is set and the sound (SoundEffectInstance) plays! =D But only once =( When SoundEffectInstance.Play is called the first time sourceId is set, and then when it gets called again sourceId != 0, so it just returns and does nothing... Well... this is my final solution for the OpenAL's PlatformPlay method:

        private void PlatformPlay()
        {
#if WINDOWS || LINUX || MONOMAC || IOS

            if (hasSourceId)
                return;

            bool isSourceAvailable = controller.ReserveSource (soundBuffer);
            if (!isSourceAvailable)
                throw new InstancePlayLimitException();

            int bufferId = soundBuffer.OpenALDataBuffer;
            AL.Source(soundBuffer.SourceId, ALSourcei.Buffer, bufferId);

            // Send the position, gain, looping, pitch, and distance model to the OpenAL driver.
            if (!hasSourceId)
                return;

            // Distance Model
            AL.DistanceModel (ALDistanceModel.InverseDistanceClamped);
            // Pan
            AL.Source (sourceId, ALSource3f.Position, _pan, 0, 0.1f);
            // Volume
            AL.Source (sourceId, ALSourcef.Gain, _volume * SoundEffect.MasterVolume);
            // Looping
            AL.Source (sourceId, ALSourceb.Looping, IsLooped);
            // Pitch
            AL.Source (sourceId, ALSourcef.Pitch, XnaPitchToAlPitch(_pitch));

            controller.PlaySound (soundBuffer);
            //Console.WriteLine ("playing: " + sourceId + " : " + soundEffect.Name);

#endif // WINDOWS || LINUX || MONOMAC || IOS

#if ANDROID

            if (soundState == SoundState.Paused)
                s_soundPool.Resume(sourceId);
            else
            {
                if (sourceId != 0)
                {
                    s_soundPool.Stop(sourceId);
                    sourceId = 0;
                }

                float panRatio = (_pan + 1.0f) / 2.0f;
                float volumeTotal = SoundEffect.MasterVolume * _volume;
                float volumeLeft = volumeTotal * (1.0f - panRatio);
                float volumeRight = volumeTotal * panRatio;

                float rate = (float)Math.Pow(2, _sampleRate);
                rate = Math.Max(Math.Min(rate, 2.0f), 0.5f);

                sourceId = s_soundPool.Play(_soundId, volumeLeft, volumeRight, 1, _looped ? -1 : 0, _sampleRate);
            }
#endif
            soundState = SoundState.Playing;
        }

Should I submit the PR since this is going to be changed soon?

KonajuGames commented 10 years ago

Submit it. My dev PC needs a reinstall (HDD locking up), so my changes will be a little while yet.

azchohfi commented 10 years ago

This is fixed now.

azchohfi commented 10 years ago

Well... this is fixed IF you are loading a wav file, not if you are loading a XNB... Will fix.

lancer1977 commented 10 years ago

I installed the package from the website, and had the same issue with no sounds regardless all the things I tried. I removed the references that were added automatically, and then installed the Nuget package. Working fine now.