Ошибка при настройке громкости на SoundEffectInstance - PullRequest
1 голос
/ 30 июля 2011

Я часто вижу сообщение об ошибке в моем приложении. Я знаю, где это происходит, я просто не знаю почему. Приложение воспроизводит звуковые эффекты (не фоновую музыку), я использую Xna.Audio и у меня есть таймер для регулярного вызова FrameworkDispatcher.Update (). Я использую SoundEffect.CreateInstance, поэтому у меня может быть петля звукового эффекта. Похоже, ошибка происходит при изменении громкости. Хотя я не знаю, ПОЧЕМУ. Известны ли случаи, когда это может потерпеть неудачу?

Функция ::: Смещение


xxx_RaiseException ::: 32
WatsonUnhandledManagedException ::: 300
Dbg_NotifyManagedException ::: 136
FirstPassException ::: 1044
TransitionStub ::: 0
Microsoft.Xna.Framework.Helpers.ThrowExceptionFromErrorCode ::: 76
Microsoft.Xna.Framework.Audio.SoundEffectInstance.set_Volume ::: 232
Microsoft.Xna.Framework.Audio.SoundEffectInstance..ctor ::: 232
Microsoft.Xna.Framework.Audio.SoundEffect.CreateInstance ::: 192
AgiliTrain.PhoneyTools.Media.SoundEffectPlayer..ctor ::: 96
WildSafari.ClassicModeGame.animalVisibleTimer_Tick ::: 344
... чик ....

Для тех, кто спрашивает, вот еще код. SoundEffectPlayer принимает SoundEffect, создает экземпляр и запускает XNA FrameworkDispatcher (через GameTimer). Этот код взят из PhoneyTools, поэтому, если вам нужно больше контекста, ознакомьтесь с проектом codeplex. Когда я хочу воспроизвести эффект, я просто запускаю SoundEffectPlayer и передаю то, что хочу.

public class SoundEffectPlayer
{
    GameTimer _xnaTimer = new GameTimer();
    SoundEffectInstance _effect = null;
    public float _duration;

    public SoundEffectPlayer(SoundEffect effect, bool loop)
    {
        _effect = effect.CreateInstance();
        _effect.IsLooped = loop;
        _duration = (float)effect.Duration.TotalSeconds;
    }

    public void Play(float volume)
    {
        _xnaTimer.Start();
        _effect.Play();
        _effect.Volume = volume;
    }

    public void Stop()
    {

        _effect.Stop(true);
        _xnaTimer.Stop();
    }
}

public class GameTimer
{
    DispatcherTimer _timer = new DispatcherTimer()
    {
        Interval = TimeSpan.FromMilliseconds(50),
    };

    public GameTimer()
    {
        _timer.Tick += new EventHandler(_timer_Tick);
    }

    void _timer_Tick(object sender, EventArgs e)
    {
        FrameworkDispatcher.Update();
    }

    public void Start()
    {
        if (!_timer.IsEnabled) _timer.Start();
    }

    public void Stop()
    {
        if (_timer.IsEnabled) _timer.Stop();
    }
}

Ответы [ 2 ]

1 голос
/ 06 августа 2011

Пытаюсь помочь, хотя у меня нет действительного решения ...

Свойство setter для SoundEffectInstance не так просто, как может показаться:

  set
        {
            lock (this.voiceHandleLock)
            {
                if (this.IsDisposed)
                {
                    throw new ObjectDisposedException(base.GetType().Name, FrameworkResources.ObjectDisposedException);
                }
                if ((value < 0f) || (value > 1f))
                {
                    throw new ArgumentOutOfRangeException("value");
                }
                Helpers.ThrowExceptionFromErrorCode(SoundEffectUnsafeNativeMethods.SetVolume(this.voiceHandle, value));
                this.currentVolume = value;
            }
        }

В основном та часть, за которой мы следуем, идет в очереди раньше, чем раньше.

Если вызов из SoundEffectUnsafeNativeMethods.SetVolume возвращает любой код, меньший 0, будет получено исключение, которое вы получите.

Вот что происходит внутри небезопасного метода:

public static unsafe int modopt(IsLong) SetVolume(uint soundEffectInstanceHandle, float volume)
{
    lock (SoundEffectSubsystemSyncObject)
    {
        if ((soundEffectInstanceHandle != 0) && (soundEffectInstanceHandle != uint.MaxValue))
        {
            CHandleTable* tablePtr = ?g_pTable@CHandleTable@@0PAV1@A;
            KernelSoundEffectInstance* instancePtr = CHandleTable.LookUp<class Microsoft::Xna::Framework::Audio::KernelSoundEffectInstance>((CHandleTable modopt(IsConst)* modopt(IsConst) modopt(IsConst)) ?g_pTable@CHandleTable@@0PAV1@A, soundEffectInstanceHandle, 0);
            if (instancePtr == null)
            {
                return -2147024809;
            }
            return **(((int*) instancePtr))[0x34](instancePtr, volume);
        }
        return -2147024809;
    }
}

Вы можете попытаться окружить создание _effect.CreateInstance с помощью try ... catch и rethrow более подробное и полезное исключение, которое будет содержать, например, информацию об объекте SoundEffect, который вы пытаетесь создать (в основном вы можете запишите все значения его поля для проверки. (не уверен, что то, что вы получаете от MS, - это только трассировка стека или фактическое сообщение об исключении).

Похоже, что в WP7 вызов для установки громкости переходит к некоторой таблице указателей ОС, которая делает некоторые закулисные действия и ищет дескриптор звукового эффекта в этой таблице.

Если по какой-то причине он не найден или что-то в этом роде (не знаю почему, может быть, мы можем взять его с разработчиками XNA), он выдаст это исключение, которое вы получаете.

Я знаю, что это не решение, но, возможно, это шаг в правильном направлении.

0 голосов
/ 02 августа 2011

Как правило, исключение не должно создаваться для ситуации, которую вы описываете, если вы создали слой совместимости XNA, как это должно быть (подробности здесь ).

Однако я заметил, что вы используете PhoneyTools.Media.SoundEffectPlayer - для чего?Это может быть причиной проблемы в вашей ситуации.

Кроме того, у вас, кажется, есть неоднозначные ссылки - effect и _effect - с какой вы работаете при воспроизведении контента?

...