Esempio n. 1
0
        /// <summary>
        /// 面倒なので IDisposable は実装せず、明示的な破棄を義務付ける。using ブロックで使うわけではないので、実装しようがすまいがあまり関係ない。
        /// </summary>
        public void Destroy()
        {
            // HACK: 複数の音声を再生している場合、停止から SourceReader 破棄までの間隔が短いと、Access Violation が発生する模様。具体的な原因は不明。
            // とりあえずスレッドを1ミリ秒待機させることで回避できるようだが、時間は環境に依存しそう。根本原因の調査が必要。
            // SharpDX を一切使わず、ネイティブ C++ で直接 Media Foundation を叩いて組んだ場合も発生するのか?
            // Windows 8.1 では発生するが、Windows 10 では発生しない?
            // SharpDX 3.0.2 では発生するが、SharpDX 3.1.1 では発生しない?
            this.Stop();

            //System.Threading.Thread.Sleep(1);

            MyGenericsHelper.SafeDispose(ref this._xaSourceVoice);

            if (this._mfSourceReader != null)
            {
                //this._mfSourceReader.Flush(MF.SourceReaderIndex.FirstAudioStream);
                //this._mfSourceReader.SetStreamSelection(MF.SourceReaderIndex.FirstAudioStream, new SharpDX.Mathematics.Interop.RawBool(false));
            }

            MyGenericsHelper.SafeDispose(ref this._mfSourceReader);

            foreach (var buffer in this._audioRingBuffers)
            {
                System.Diagnostics.Debug.Assert(buffer != null);
                buffer.Destroy();
            }
        }
Esempio n. 2
0
        public static MF.SourceReader CreateSourceReader(byte[] buffer)
        {
            // 列挙体・構造体・COM インターフェイスのマッピングは下記を参考にできそう。SharpDX はある程度までラップコードを自動生成している模様。
            // http://sharpdx.org/wiki/class-library-api/mediafoundation.html
            // GUID 定数のマッピングは下記を参考にできそう。
            // https://github.com/sharpdx/SharpDX/blob/master/Source/SharpDX.MediaFoundation/Mapping-core.xml

            // マネージ参照の代入は COM スマートポインタの代入とは別物。
            // マネージ参照を代入しただけでは、明示的な Dispose すなわち IUnknown::Release() による COM 参照カウント減少は不要。
            // 通例、他の COM オブジェクトのメソッド引数に渡すなどのタイミングで COM 参照カウントが増える。
            // フィールドで保持するルート オブジェクトなど、別の COM オブジェクトから参照されないものだけを最後に Dispose すればよいはず。
            // HACK: オブジェクト間の COM 参照関連付け前に途中で例外が発生したときはどうする?
            // Dispose を明示的に呼び出すタイミングを失い、GC 任せになるのは危険なので、どのみち例外 catch 時に明示的な破棄が必要になる。
            // だとすれば C# での記述は煩雑すぎる。using で Dispose すれば、C++ のスマートポインタのように例外発生時の COM 参照カウントを安全に制御できる?
            // C# の using による後始末は、C++ のコンストラクタ・デストラクタと違ってコードのネストが深くなりがちなのが欠点。
            // using を使わずに生成すると、戻り値として返却するまでに例外発生した場合の後始末が大変。
            // かといって、using ブロックで生成したオブジェクトをそのまま返すと、
            // 破棄後の無効なオブジェクトを返すことになってしまうので、COM 参照カウントを増やしてから返す。
            // → ルート オブジェクトには using は使えない模様。たとえ QueryInterface や AddReference していても、
            // 一度でも Dispose されたオブジェクトを使おうとすると、AccessViolationException が発生する。
            // QueryInterface はオブジェクトを複製するものではなく、また SharpDX.ComObject.Dispose() で Release した後、
            // 参照カウント残数にかかわらずネイティブポインタに NULL を代入する実装になっていることが原因。
            // したがって、ルート オブジェクトは Dispose すなわち Release を明示的に制御する必要がある。

            // MediaAttributes のコンストラクタは MFCreateAttributes() 相当らしいが、第2引数 cInitialSize の説明は
            // The initial number of elements allocated for the attribute store. The attribute store grows as needed.
            // とあるので、initialSizeInBytes という引数名は間違っているように思われる。
            // https://msdn.microsoft.com/en-us/library/windows/desktop/ms701878.aspx

            MF.SourceReader mfSourceReader = null;

            try
            {
                using (var mfAttributes = new MF.MediaAttributes(1))
                {
                    mfAttributes.Set(MF.SinkWriterAttributeKeys.LowLatency, true);

                    using (var mfMediaType = new MF.MediaType())
                    {
                        mfMediaType.Set(MF.MediaTypeAttributeKeys.MajorType, MF.MediaTypeGuids.Audio);
                        //mfMediaType.Set(MF.MediaTypeAttributeKeys.Subtype, MF.AudioFormatGuids.Float); // MP3 では OK だが、WAV だと 0xC00D5212 で失敗する模様。
                        mfMediaType.Set(MF.MediaTypeAttributeKeys.Subtype, MF.AudioFormatGuids.Pcm);
                        mfSourceReader = new MF.SourceReader(buffer, mfAttributes);
                        // オリジナルの IMFSourceReader::SetCurrentMediaType() の第2引数は NULL を指定する予約引数だが、SharpDX では隠ぺいされている。
                        mfSourceReader.SetCurrentMediaType(MF.SourceReaderIndex.FirstAudioStream, mfMediaType);

                        //return mfSourceReader.QueryInterface<MF.SourceReader>();
                        //(mfSourceReader as SharpDX.IUnknown).AddReference();
                        return(mfSourceReader);
                    }
                }
            }
            catch
            {
                MyGenericsHelper.SafeDispose(ref mfSourceReader);
                throw;
            }
        }
Esempio n. 3
0
 /// <summary>
 /// 面倒なので IDisposable は実装せず、明示的な破棄を義務付ける。using ブロックで使うわけではないので、実装しようがすまいがあまり関係ない。
 /// </summary>
 public void Destroy()
 {
     MyGenericsHelper.SafeDispose(ref this._xaudio);
     MyGenericsHelper.SafeDispose(ref this._xaMasteringVoice);
 }