AudioHandler.cs 7.2 KB

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