stream.cpp 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. /**
  2. * libdatachannel streamer example
  3. * Copyright (c) 2020 Filip Klembara (in2core)
  4. *
  5. * This Source Code Form is subject to the terms of the Mozilla Public
  6. * License, v. 2.0. If a copy of the MPL was not distributed with this
  7. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
  8. */
  9. #include "stream.hpp"
  10. #include "helpers.hpp"
  11. #ifdef _WIN32
  12. // taken from https://stackoverflow.com/questions/5801813/c-usleep-is-obsolete-workarounds-for-windows-mingw
  13. #include <windows.h>
  14. void usleep(__int64 usec)
  15. {
  16. HANDLE timer;
  17. LARGE_INTEGER ft;
  18. ft.QuadPart = -(10*usec); // Convert to 100 nanosecond interval, negative value indicates relative time
  19. timer = CreateWaitableTimer(NULL, TRUE, NULL);
  20. SetWaitableTimer(timer, &ft, 0, NULL, NULL, 0);
  21. WaitForSingleObject(timer, INFINITE);
  22. CloseHandle(timer);
  23. }
  24. #else
  25. #include <unistd.h>
  26. #endif
  27. Stream::Stream(std::shared_ptr<StreamSource> video, std::shared_ptr<StreamSource> audio):
  28. std::enable_shared_from_this<Stream>(), video(video), audio(audio) { }
  29. Stream::~Stream() {
  30. stop();
  31. }
  32. std::pair<std::shared_ptr<StreamSource>, Stream::StreamSourceType> Stream::unsafePrepareForSample() {
  33. std::shared_ptr<StreamSource> ss;
  34. StreamSourceType sst;
  35. uint64_t nextTime;
  36. if (audio->getSampleTime_us() < video->getSampleTime_us()) {
  37. ss = audio;
  38. sst = StreamSourceType::Audio;
  39. nextTime = audio->getSampleTime_us();
  40. } else {
  41. ss = video;
  42. sst = StreamSourceType::Video;
  43. nextTime = video->getSampleTime_us();
  44. }
  45. auto currentTime = currentTimeInMicroSeconds();
  46. auto elapsed = currentTime - startTime;
  47. if (nextTime > elapsed) {
  48. auto waitTime = nextTime - elapsed;
  49. mutex.unlock();
  50. usleep(waitTime);
  51. mutex.lock();
  52. }
  53. return {ss, sst};
  54. }
  55. void Stream::sendSample() {
  56. std::lock_guard lock(mutex);
  57. if (!isRunning) {
  58. return;
  59. }
  60. auto ssSST = unsafePrepareForSample();
  61. auto ss = ssSST.first;
  62. auto sst = ssSST.second;
  63. auto sample = ss->getSample();
  64. sampleHandler(sst, ss->getSampleTime_us(), sample);
  65. ss->loadNextSample();
  66. dispatchQueue.dispatch([this]() {
  67. this->sendSample();
  68. });
  69. }
  70. void Stream::onSample(std::function<void (StreamSourceType, uint64_t, rtc::binary)> handler) {
  71. sampleHandler = handler;
  72. }
  73. void Stream::start() {
  74. std::lock_guard lock(mutex);
  75. if (isRunning) {
  76. return;
  77. }
  78. _isRunning = true;
  79. startTime = currentTimeInMicroSeconds();
  80. audio->start();
  81. video->start();
  82. dispatchQueue.dispatch([this]() {
  83. this->sendSample();
  84. });
  85. }
  86. void Stream::stop() {
  87. std::lock_guard lock(mutex);
  88. if (!isRunning) {
  89. return;
  90. }
  91. _isRunning = false;
  92. dispatchQueue.removePending();
  93. audio->stop();
  94. video->stop();
  95. };