AudioHandler.cs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. using NAudio.Wave;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Net;
  7. using System.Text;
  8. using System.Threading;
  9. using System.Threading.Tasks;
  10. namespace MusicPlayer
  11. {
  12. public class AudioHandler
  13. {
  14. public enum AudioState { PLAYING, WAITING, STOPPED, PAUSED, SEEKING }
  15. public enum BufferState { EMPTY, BUFFERING, DONE }
  16. public AudioState AState { get; set; }
  17. public BufferState BState { get; set; }
  18. public int Buffered { get { return Math.Min((int)((bufpos / (double)LengthBuffer) * 100), 100); } }
  19. private long LengthBuffer { get; set; }
  20. private long bufpos = 0;
  21. public int Position { get { return Math.Min((int)((playpos / (double)Length) * 100), 100); } }
  22. private long Length { get; set; }
  23. private long playpos = 0;
  24. public int CurrentTime { get; set; }
  25. public int TotalTime { get { return CurrentSong != null ? CurrentSong.Seconds : 0; } }
  26. private long seek = 0;
  27. private Stream ms;
  28. private Thread network;
  29. private Thread audio;
  30. public Song CurrentSong;
  31. public AudioHandler()
  32. {
  33. CreateThreads();
  34. }
  35. private void CreateThreads()
  36. {
  37. AState = AudioState.STOPPED;
  38. BState = BufferState.EMPTY;
  39. CurrentSong = null;
  40. Thread.Sleep(11);
  41. ms = new MemoryStream();
  42. network = new Thread(LoadAudio);
  43. audio = new Thread(PlayAudio);
  44. network.IsBackground = true;
  45. audio.IsBackground = true;
  46. Length = 1;
  47. LengthBuffer = 1;
  48. bufpos = 0;
  49. playpos = 0;
  50. CurrentTime = 0;
  51. }
  52. public void Play(Song s)
  53. {
  54. if (CurrentSong == s && AState == AudioState.PAUSED)
  55. AState = AudioState.PLAYING;
  56. else
  57. {
  58. Stop();
  59. CurrentSong = s;
  60. network.Start(s);
  61. audio.Start();
  62. }
  63. }
  64. public void Seek(int position)
  65. {
  66. if (position >= Buffered-1)
  67. return;
  68. seek = Length / 100 * position;
  69. AState = AudioState.SEEKING;
  70. }
  71. public void Stop()
  72. {
  73. CreateThreads();
  74. }
  75. public void Pause()
  76. {
  77. AState = AudioState.PAUSED;
  78. }
  79. private void StreamFromMP3(Stream s, long pos, bool firstrun)
  80. {
  81. long position = 0;
  82. ms.Position = position;
  83. Mp3FileReader mp3fr = new Mp3FileReader(ms);
  84. using (WaveStream blockAlignedStream = new BlockAlignReductionStream(WaveFormatConversionStream.CreatePcmStream(mp3fr)))
  85. {
  86. blockAlignedStream.Position = pos;
  87. using (WaveOut waveOut = new WaveOut(WaveCallbackInfo.FunctionCallback()))
  88. {
  89. waveOut.Init(blockAlignedStream);
  90. waveOut.Play();
  91. Length = CurrentSong.Seconds * waveOut.OutputWaveFormat.AverageBytesPerSecond;
  92. CurrentTime = (int)(ms.Position / waveOut.OutputWaveFormat.AverageBytesPerSecond);
  93. while (waveOut.PlaybackState != PlaybackState.Stopped)
  94. {
  95. System.Threading.Thread.Sleep(10);
  96. if (AState == AudioState.PLAYING && waveOut.PlaybackState == PlaybackState.Paused)
  97. {
  98. blockAlignedStream.Position = position;
  99. waveOut.Play();
  100. }
  101. if (AState == AudioState.PAUSED && waveOut.PlaybackState == PlaybackState.Playing)
  102. {
  103. position = blockAlignedStream.Position;
  104. waveOut.Pause();
  105. }
  106. if (AState == AudioState.SEEKING)
  107. {
  108. blockAlignedStream.Seek(seek - (seek % blockAlignedStream.WaveFormat.BlockAlign), SeekOrigin.Begin);
  109. AState = AudioState.PLAYING;
  110. //waveOut.Play();
  111. }
  112. if (AState == AudioState.STOPPED)
  113. {
  114. waveOut.Stop();
  115. }
  116. if (BState == BufferState.DONE && firstrun )
  117. {
  118. position = mp3fr.Position;
  119. mp3fr.Close();
  120. StreamFromMP3(ms,position, false);
  121. break;
  122. }
  123. playpos = blockAlignedStream.Position;
  124. CurrentTime = (int)(playpos / waveOut.OutputWaveFormat.AverageBytesPerSecond);
  125. }
  126. AState = AudioState.STOPPED;
  127. playpos = 0;
  128. CurrentTime = 0;
  129. }
  130. }
  131. }
  132. private void PlayAudio()
  133. {
  134. AState = AudioState.WAITING;
  135. while (ms.Length < 65536 * 10 && BState != BufferState.DONE)
  136. Thread.Sleep(1000);
  137. AState = AudioState.PLAYING;
  138. StreamFromMP3(ms,0, true);
  139. }
  140. private void LoadAudio(object o)
  141. {
  142. Song s = (Song) o;
  143. WebResponse response = null;
  144. try
  145. {
  146. response = WebRequest.Create(s.Url).GetResponse();
  147. }
  148. catch(Exception e)
  149. {
  150. BState = BufferState.EMPTY;
  151. AState = AudioState.STOPPED;
  152. return;
  153. }
  154. BState = BufferState.EMPTY;
  155. LengthBuffer = response.ContentLength;
  156. using (var stream = response.GetResponseStream())
  157. {
  158. //byte[] buffer = new byte[65536]; // 64KB chunks
  159. byte[] buffer = new byte[65536*4]; // 256KB chunks
  160. int read;
  161. BState = BufferState.BUFFERING;
  162. AState = AudioState.WAITING;
  163. while ((read = stream.Read(buffer, 0, buffer.Length)) > 0 && AState != AudioState.STOPPED)
  164. {
  165. var pos = ms.Position;
  166. ms.Position = ms.Length;
  167. ms.Write(buffer, 0, read);
  168. ms.Position = pos;
  169. this.bufpos = ms.Length;
  170. }
  171. }
  172. BState = BufferState.DONE;
  173. }
  174. }
  175. }