stream.cpp 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. /*
  2. * libdatachannel streamer example
  3. * Copyright (c) 2020 Filip Klembara (in2core)
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License
  7. * as published by the Free Software Foundation; either version 2
  8. * of the License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include "stream.hpp"
  19. #include "helpers.hpp"
  20. #ifdef _WIN32
  21. // taken from https://stackoverflow.com/questions/5801813/c-usleep-is-obsolete-workarounds-for-windows-mingw
  22. #include <windows.h>
  23. void usleep(__int64 usec)
  24. {
  25. HANDLE timer;
  26. LARGE_INTEGER ft;
  27. ft.QuadPart = -(10*usec); // Convert to 100 nanosecond interval, negative value indicates relative time
  28. timer = CreateWaitableTimer(NULL, TRUE, NULL);
  29. SetWaitableTimer(timer, &ft, 0, NULL, NULL, 0);
  30. WaitForSingleObject(timer, INFINITE);
  31. CloseHandle(timer);
  32. }
  33. #else
  34. #include <unistd.h>
  35. #endif
  36. void StreamSource::stop() {
  37. sampleTime_us = 0;
  38. sample = {};
  39. }
  40. StreamSource::~StreamSource() {
  41. stop();
  42. }
  43. Stream::Stream(std::shared_ptr<StreamSource> video, std::shared_ptr<StreamSource> audio): std::enable_shared_from_this<Stream>(), video(video), audio(audio) { }
  44. Stream::~Stream() {
  45. stop();
  46. }
  47. std::pair<std::shared_ptr<StreamSource>, Stream::StreamSourceType> Stream::unsafePrepareForSample() {
  48. std::shared_ptr<StreamSource> ss;
  49. StreamSourceType sst;
  50. uint64_t nextTime;
  51. if (audio->getSampleTime_us() < video->getSampleTime_us()) {
  52. ss = audio;
  53. sst = StreamSourceType::Audio;
  54. nextTime = audio->getSampleTime_us();
  55. } else {
  56. ss = video;
  57. sst = StreamSourceType::Video;
  58. nextTime = video->getSampleTime_us();
  59. }
  60. auto currentTime = currentTimeInMicroSeconds();
  61. auto elapsed = currentTime - startTime;
  62. if (nextTime > elapsed) {
  63. auto waitTime = nextTime - elapsed;
  64. mutex.unlock();
  65. usleep(waitTime);
  66. mutex.lock();
  67. }
  68. return {ss, sst};
  69. }
  70. void Stream::sendSample() {
  71. std::lock_guard lock(mutex);
  72. if (!isRunning) {
  73. return;
  74. }
  75. auto ssSST = unsafePrepareForSample();
  76. auto ss = ssSST.first;
  77. auto sst = ssSST.second;
  78. auto sample = ss->getSample();
  79. sampleHandler(sst, ss->getSampleTime_us(), sample);
  80. ss->loadNextSample();
  81. dispatchQueue.dispatch([this]() {
  82. this->sendSample();
  83. });
  84. }
  85. void Stream::onSample(std::function<void (StreamSourceType, uint64_t, rtc::binary)> handler) {
  86. sampleHandler = handler;
  87. }
  88. void Stream::start() {
  89. std::lock_guard lock(mutex);
  90. if (isRunning) {
  91. return;
  92. }
  93. _isRunning = true;
  94. startTime = currentTimeInMicroSeconds();
  95. audio->start();
  96. video->start();
  97. dispatchQueue.dispatch([this]() {
  98. this->sendSample();
  99. });
  100. }
  101. void Stream::stop() {
  102. std::lock_guard lock(mutex);
  103. if (!isRunning) {
  104. return;
  105. }
  106. _isRunning = false;
  107. dispatchQueue.removePending();
  108. audio->stop();
  109. video->stop();
  110. };