void ApplicationStreamedSound_BufferNotification(object sender, BufferNotificationEventArgs e) { if (e.SoundFinished) { IsPlaying = false; } }
void ApplicationStreamedSound_BufferNotificationSendPostback(object sender, BufferNotificationEventArgs e) { if (e.SoundFinished) { IsPlaying = false; if (OnPlayEnd != null) { OnPlayEnd(); } } }
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); } }
/// <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(object o) { 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."); }
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); }
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."); }