Describes a buffer notification event. To properly handle the event, the NewSoundByte field should be set to an array of bytes less than or equal to the NumBytesRequired property. If less than the required number of bytes are provided, the stream will fill the remainder with silence. SoundFinished defaults to false, and should be set to indicate if the bytes contained in NewSoundByte represent the end of the sound.
Inheritance: System.EventArgs
コード例 #1
0
        public void OnBufferNotification(object sender, BufferNotificationEventArgs e)
        {
            if (e.NewSoundByte == null || e.NewSoundByte.Length != e.NumBytesRequired)
            {
                e.NewSoundByte = new byte[e.NumBytesRequired];
            }

            int bytesRead = Stream.Read(e.NewSoundByte, 0, e.NumBytesRequired);

            if (bytesRead != e.NumBytesRequired)
            {
                byte[] trimmedBytes = new byte[bytesRead];
                Array.Copy(e.NewSoundByte, trimmedBytes, bytesRead);
                e.NewSoundByte = trimmedBytes;
            }
            e.SoundFinished = Stream.Length == Stream.Position;

            if (BufferNotification != null)
            {
                BufferNotification(sender, e);
            }
        }
コード例 #2
0
        /// <summary>
        /// The stream control thread raises events every half the stream.
        /// When the BufferNotificationEventArgs contains a SoundFinished property set to true, the
        /// current buffer segment is padded with silence.  At the next notification, the next
        /// buffer segment is filled with silence, and no event is raised.
        /// At the next notification, which will come when the padded segment
        /// (not the completely silent segment) is finished, the SecondaryBuffer is stopped and
        /// the thread terminated.
        /// </summary>
        private void StreamControlThread()
        {
            int nextPlaceForBytes     = 0;
            int wholeBufferSize       = SB.Caps.BufferBytes;
            int byteWindowSize        = wholeBufferSize / 2;
            NextNotificationTask task = NextNotificationTask.FillSectionWithNewSound;

            //BufferNotificationEventArgs ssea = new BufferNotificationEventArgs(SB.Caps.BufferBytes);
            BufferNotificationEventArgs firstNotificationEventArgs = new BufferNotificationEventArgs(wholeBufferSize);

            GetBytesByRaisingEvent(0, wholeBufferSize, firstNotificationEventArgs);
            task = HandleNewBytesInControlThread(nextPlaceForBytes, wholeBufferSize, firstNotificationEventArgs);


            bool terminate = false;

            while (!terminate)
            {
                NotificationEvent.Reset();
                NotificationEvent.WaitOne();

                if (SB.Disposed || (!Playing))
                {
                    break;
                }

                /// Very strange behavior from DirectSound!!
                /// SB.PlayPosition returns a value slightly less than the actual position.  Either that or the event is raised
                /// So you can use that to determine which section to fill.  Fill the half that you're currently "playing"
                /// according to the PlayPosition.
                /// If anyone knows how to do this properly, please e-mail me, [email protected].
                int playPosition = SB.PlayPosition;
                int distToBegin  = Math.Abs(playPosition - 0);
                int distToEnd    = Math.Abs(playPosition - wholeBufferSize);
                int distToMid    = Math.Abs(playPosition - byteWindowSize);

                if (distToMid < distToEnd && distToMid < distToBegin)
                {
                    nextPlaceForBytes = 0;
                }
                else
                {
                    nextPlaceForBytes = byteWindowSize;
                }
                //Console.WriteLine(DateTime.Now + ": Received request for bytes at " + nextPlaceForBytes + " and I'm now at " + SB.PlayPosition);
                switch (task)
                {
                case NextNotificationTask.FillSectionWithNewSound:
                    BufferNotificationEventArgs nextNotificationEventArgs = new BufferNotificationEventArgs(byteWindowSize);
                    GetBytesByRaisingEvent(nextPlaceForBytes, byteWindowSize, nextNotificationEventArgs);
                    task = HandleNewBytesInControlThread(nextPlaceForBytes, byteWindowSize, nextNotificationEventArgs);
                    break;

                case NextNotificationTask.FillSectionWithSilence:
                    task = NextNotificationTask.StopSecondaryBufferAndThread;
                    //Console.WriteLine("Filling section with silence at " + nextPlaceForBytes);
                    int currentPosition = 0; int writePos = 0;
                    SB.GetCurrentPosition(out currentPosition, out writePos);
                    //Console.WriteLine("Current pos " + currentPosition + " and writing " + byteWindowSize + " at " + nextPlaceForBytes);
                    SB.Write(nextPlaceForBytes, new byte[byteWindowSize], LockFlag.None);
                    break;

                default:                         // NextNotificationTask.StopSecondaryBufferAndThread
                    SB.Stop();
                    //Console.WriteLine("stream control thread dies.");
                    return;
                }
                //nextPlaceForBytes += byteWindowSize; if (nextPlaceForBytes >= SB.Caps.BufferBytes) nextPlaceForBytes = 0;
            }
            //Console.WriteLine("stream control thread dies.");
        }
コード例 #3
0
        private NextNotificationTask HandleNewBytesInControlThread(int nextPlaceForBytes, int byteWindowSize, BufferNotificationEventArgs ea)
        {
            LockFlag lockFlag      = LockFlag.None;
            int      bytesObtained = ea.NewSoundByte.Length;

            if (bytesObtained > byteWindowSize)
            {
                SB.Stop();
                throw new ApplicationException("An event handler provided the streaming buffer with " + bytesObtained + " bytes of sound, but it only requested " + byteWindowSize + " bytes.");
            }
            else if (bytesObtained == byteWindowSize)
            {
                SB.Write(nextPlaceForBytes, ea.NewSoundByte, lockFlag);
            }
            else
            {
                // Fill the remainder of the segment with silence.
                if (ea.NewSoundByte.Length > 0)
                {
                    SB.Write(nextPlaceForBytes, ea.NewSoundByte, lockFlag);
                }
                SB.Write(nextPlaceForBytes + ea.NewSoundByte.Length, new byte[byteWindowSize - ea.NewSoundByte.Length], lockFlag);

                if (ea.SoundFinished)
                {
                    return(NextNotificationTask.FillSectionWithSilence);
                }
            }
            return(NextNotificationTask.FillSectionWithNewSound);
        }
コード例 #4
0
        private void GetBytesByRaisingEvent(int locationInSecondaryBuffer, int numBytesToAcquire, BufferNotificationEventArgs e)
        {
            e.NumBytesRequiredRep = numBytesToAcquire;
            if (BufferNotification != null)
            {
                BufferNotification(this, e);
            }

            if (e.NewSoundByte == null)
            {
                e.NewSoundByte = new byte[0];
            }

            //Console.WriteLine("Request issued for " + numBytesToAcquire + " bytes; " + e.NewSoundByte.Length + " obtained.");
        }
コード例 #5
0
ファイル: StreamedSound.cs プロジェクト: RHY3756547/FreeSO
        public void OnBufferNotification(object sender, BufferNotificationEventArgs e)
        {
            if (e.NewSoundByte == null || e.NewSoundByte.Length != e.NumBytesRequired)
                e.NewSoundByte = new byte[e.NumBytesRequired];

            int bytesRead = Stream.Read(e.NewSoundByte, 0, e.NumBytesRequired);
            if (bytesRead != e.NumBytesRequired)
            {
                byte[] trimmedBytes = new byte[bytesRead];
                Array.Copy(e.NewSoundByte, trimmedBytes, bytesRead);
                e.NewSoundByte = trimmedBytes;
            }
            e.SoundFinished = Stream.Length == Stream.Position;

            if (BufferNotification != null) BufferNotification(sender, e);
        }
コード例 #6
0
        /// <summary>
        /// The stream control thread raises events every half the stream.  
        /// When the BufferNotificationEventArgs contains a SoundFinished property set to true, the
        /// current buffer segment is padded with silence.  At the next notification, the next
        /// buffer segment is filled with silence, and no event is raised.  
        /// At the next notification, which will come when the padded segment 
        /// (not the completely silent segment) is finished, the SecondaryBuffer is stopped and 
        /// the thread terminated.
        /// </summary>
        private void StreamControlThread()
        {
            int nextPlaceForBytes = 0;
            int wholeBufferSize = SB.Caps.BufferBytes;
            int byteWindowSize = wholeBufferSize / 2;
            NextNotificationTask task = NextNotificationTask.FillSectionWithNewSound;

            //BufferNotificationEventArgs ssea = new BufferNotificationEventArgs(SB.Caps.BufferBytes);
            BufferNotificationEventArgs firstNotificationEventArgs = new BufferNotificationEventArgs(wholeBufferSize);
            GetBytesByRaisingEvent(0, wholeBufferSize, firstNotificationEventArgs);
            task = HandleNewBytesInControlThread(nextPlaceForBytes, wholeBufferSize, firstNotificationEventArgs);

            bool terminate = false;

            while (!terminate)
            {
                NotificationEvent.Reset();
                NotificationEvent.WaitOne();

                if (SB.Disposed || (!Playing)) break;

                /// Very strange behavior from DirectSound!!
                /// SB.PlayPosition returns a value slightly less than the actual position.  Either that or the event is raised
                /// So you can use that to determine which section to fill.  Fill the half that you're currently "playing"
                /// according to the PlayPosition.
                /// If anyone knows how to do this properly, please e-mail me, [email protected].
                int playPosition = SB.PlayPosition;
                int distToBegin = Math.Abs(playPosition - 0);
                int distToEnd = Math.Abs(playPosition - wholeBufferSize);
                int distToMid = Math.Abs(playPosition - byteWindowSize);

                if (distToMid < distToEnd && distToMid < distToBegin)
                    nextPlaceForBytes = 0;
                else
                    nextPlaceForBytes = byteWindowSize;
                //Console.WriteLine(DateTime.Now + ": Received request for bytes at " + nextPlaceForBytes + " and I'm now at " + SB.PlayPosition);
                switch(task)
                {
                    case NextNotificationTask.FillSectionWithNewSound:
                        BufferNotificationEventArgs nextNotificationEventArgs = new BufferNotificationEventArgs(byteWindowSize);
                        GetBytesByRaisingEvent(nextPlaceForBytes, byteWindowSize, nextNotificationEventArgs);
                        task = HandleNewBytesInControlThread(nextPlaceForBytes, byteWindowSize, nextNotificationEventArgs);
                        break;
                    case NextNotificationTask.FillSectionWithSilence:
                        task = NextNotificationTask.StopSecondaryBufferAndThread;
                        //Console.WriteLine("Filling section with silence at " + nextPlaceForBytes);
                        int currentPosition = 0; int writePos = 0;
                        SB.GetCurrentPosition(out currentPosition, out writePos);
                        //Console.WriteLine("Current pos " + currentPosition + " and writing " + byteWindowSize + " at " + nextPlaceForBytes);
                        SB.Write(nextPlaceForBytes, new byte[byteWindowSize], LockFlag.None);
                        break;
                    default: // NextNotificationTask.StopSecondaryBufferAndThread
                        SB.Stop();
                        //Console.WriteLine("stream control thread dies.");
                        return;
                }
                //nextPlaceForBytes += byteWindowSize; if (nextPlaceForBytes >= SB.Caps.BufferBytes) nextPlaceForBytes = 0;
            }
            //Console.WriteLine("stream control thread dies.");
        }
コード例 #7
0
        private NextNotificationTask HandleNewBytesInControlThread(int nextPlaceForBytes, int byteWindowSize, BufferNotificationEventArgs ea)
        {
            LockFlag lockFlag = LockFlag.None;
            int bytesObtained = ea.NewSoundByte.Length;
            if (bytesObtained > byteWindowSize)
            {
                SB.Stop();
                throw new ApplicationException("An event handler provided the streaming buffer with " + bytesObtained + " bytes of sound, but it only requested " + byteWindowSize + " bytes.");
            }
            else if (bytesObtained == byteWindowSize)
            {
                SB.Write(nextPlaceForBytes, ea.NewSoundByte, lockFlag);
            }
            else
            {
                // Fill the remainder of the segment with silence.
                if (ea.NewSoundByte.Length > 0) SB.Write(nextPlaceForBytes, ea.NewSoundByte, lockFlag);
                SB.Write(nextPlaceForBytes+ea.NewSoundByte.Length, new byte[byteWindowSize-ea.NewSoundByte.Length], lockFlag);

                if (ea.SoundFinished) return NextNotificationTask.FillSectionWithSilence;
            }
            return NextNotificationTask.FillSectionWithNewSound;
        }
コード例 #8
0
        private void GetBytesByRaisingEvent(int locationInSecondaryBuffer, int numBytesToAcquire, BufferNotificationEventArgs e)
        {
            e.NumBytesRequiredRep = numBytesToAcquire;
            if (BufferNotification != null) BufferNotification(this, e);

            if (e.NewSoundByte == null) e.NewSoundByte = new byte[0];

            //Console.WriteLine("Request issued for " + numBytesToAcquire + " bytes; " + e.NewSoundByte.Length + " obtained.");
        }