AudioThread.cpp 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. #include "Main.h"
  2. #include "AudioThread.h"
  3. #include "AudioLayer.h"
  4. #include <assert.h>
  5. extern unsigned long endTime;
  6. DWORD WINAPI AudThread_stub(void *ptr)
  7. {
  8. ((AudioThread *)ptr)->AudThread();
  9. return 0;
  10. }
  11. void AudioThread::Start(WMHandler *_output)
  12. {
  13. assert(_output);
  14. output = _output;
  15. eof=0;
  16. ResetEvent(stopped);
  17. QueueUserAPC(MediaThread_StartAPC, thread, reinterpret_cast<ULONG_PTR>(static_cast<MediaThread *>(this)));
  18. }
  19. AudioThread::AudioThread(AudioLayer *audio) : output(0), audioLayer(audio)
  20. {
  21. DWORD id;
  22. thread = CreateThread(NULL, 256*1024, AudThread_stub, (void *)this, NULL, &id);
  23. SetThreadPriority(thread, AGAVE_API_CONFIG->GetInt(playbackConfigGroupGUID, L"priority", THREAD_PRIORITY_HIGHEST));
  24. }
  25. void AudioThread::AudThread()
  26. {
  27. int endbreak=0;
  28. while (true)
  29. {
  30. switch (WaitForSingleObjectEx(killEvent, wait, TRUE))
  31. {
  32. case WAIT_OBJECT_0:
  33. //StopAPC();
  34. return;
  35. case WAIT_TIMEOUT:
  36. {
  37. if (buffers.empty() || endbreak)
  38. {
  39. SetEvent(bufferFreed);
  40. if (eof==1)
  41. {
  42. eof=2;
  43. output->EndOfFile();
  44. }
  45. endbreak = 0;
  46. continue;
  47. }
  48. MediaBuffer *buffer = buffers.front();
  49. DWORD length;
  50. void *data;
  51. buffer->buffer->GetBufferAndLength((BYTE **)&data, &length);
  52. //if (out->CanWrite() >= length)
  53. {
  54. QWORD timestamptemp = buffer->timestamp/10000LL;
  55. DWORD timestamp = static_cast<DWORD>(timestamptemp);
  56. if (buffer->flags & WM_SF_DISCONTINUITY)
  57. {
  58. // fill with silence!
  59. int msToFill = timestamp - out->GetWrittenTime(); // TODO: maybe use microsoft's time resolution?
  60. if (msToFill > 0 && msToFill < 2000)
  61. {
  62. int bytes = audioLayer->AudioMillisecondsToBytes(msToFill);
  63. __int8 *zeroes = (__int8 *)calloc(bytes, 1);
  64. if (zeroes)
  65. {
  66. output->AudioDataReceived(zeroes, bytes, timestamp);
  67. free(zeroes);
  68. }
  69. else
  70. {
  71. out->Flush(timestamp);
  72. }
  73. }
  74. else if (msToFill > 0)
  75. {
  76. out->Flush(timestamp);
  77. }
  78. }
  79. output->AudioDataReceived(data, length, timestamp);
  80. // TODO seen a few crash reports failing around here
  81. // might be the cause of the random wma fails
  82. // but crash dump doesn't help too much afaict
  83. try {
  84. buffer->buffer->Release();
  85. delete buffer;
  86. } catch (...) {}
  87. //buffers.pop_front();
  88. if (buffers.size())
  89. {
  90. buffers.erase(buffers.begin());
  91. }
  92. unsigned long x = endTime;
  93. if (x && timestamp > x)
  94. {
  95. eof = 1; // reached the end baby....
  96. endbreak = 1;
  97. }
  98. }
  99. if (buffers.size() < config_audio_cache_frames)
  100. SetEvent(bufferFreed);
  101. }
  102. continue;
  103. default:
  104. continue;
  105. }
  106. }
  107. }
  108. void AudioThread::AddAPC(MediaBuffer *buffer)
  109. {
  110. OrderedInsert(buffer);
  111. if (buffers.size() >= config_audio_cache_frames)
  112. ResetEvent(bufferFreed);
  113. }