offerer.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. /**
  2. * Copyright (c) 2019 Paul-Louis Ageneau, Murat Dogan
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2.1 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this library; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. */
  18. #include "rtc/rtc.hpp"
  19. #include <httplib.h>
  20. #include <nlohmann/json.hpp>
  21. #include <chrono>
  22. #include <iostream>
  23. #include <memory>
  24. #include <thread>
  25. using namespace rtc;
  26. using namespace std;
  27. using namespace std::chrono_literals;
  28. template <class T> weak_ptr<T> make_weak_ptr(shared_ptr<T> ptr) { return ptr; }
  29. const char base64_url_alphabet[] = {
  30. 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
  31. 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
  32. 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
  33. 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
  34. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
  35. };
  36. std::string base64_encode(const std::string & in) {
  37. std::string out;
  38. int val =0, valb=-6;
  39. size_t len = in.length();
  40. unsigned int i = 0;
  41. for (i = 0; i < len; i++) {
  42. unsigned char c = in[i];
  43. val = (val<<8) + c;
  44. valb += 8;
  45. while (valb >= 0) {
  46. out.push_back(base64_url_alphabet[(val>>valb)&0x3F]);
  47. valb -= 6;
  48. }
  49. }
  50. if (valb > -6) {
  51. out.push_back(base64_url_alphabet[((val<<8)>>(valb+8))&0x3F]);
  52. }
  53. return out;
  54. }
  55. int main(int argc, char **argv) {
  56. InitLogger(LogLevel::Warning);
  57. Configuration config;
  58. // config.iceServers.emplace_back("stun.l.google.com:19302");
  59. std::string payload;
  60. auto pc = std::make_shared<PeerConnection>(config);
  61. pc->onLocalDescription([wpc = make_weak_ptr(pc)](const Description &description){
  62. auto pc = wpc.lock();
  63. if (!pc)
  64. return;
  65. pc->connectionInfo += description;
  66. pc->connectionInfo += ",";
  67. });
  68. pc->onLocalCandidate([wpc = make_weak_ptr(pc)](const Candidate &candidate) {
  69. auto pc = wpc.lock();
  70. if (!pc)
  71. return;
  72. pc->connectionInfo += candidate;
  73. cout << pc->connectionInfo << endl << endl;
  74. auto encoded = base64_encode(pc->connectionInfo);
  75. cout << "http://localhost:8080/answerer.html?connection=" << encoded << endl << endl;
  76. httplib::Client cli("localhost", 8000);
  77. auto res = cli.Get("/state/json");
  78. if (!res)
  79. return;
  80. while (res->body.empty()) {
  81. std::this_thread::sleep_for(2s);
  82. res = cli.Get("/state/json");
  83. }
  84. pc->setRemoteDescription(res->body);
  85. });
  86. pc->onStateChange([wpc = make_weak_ptr(pc)](PeerConnection::State state) {
  87. cout << "[State: " << state << "]" << endl;
  88. });
  89. pc->onGatheringStateChange([](PeerConnection::GatheringState state) {
  90. cout << "[Gathering State: " << state << "]" << endl;
  91. });
  92. auto dc = pc->createDataChannel("test"); // this is the offerer, so create a data channel
  93. dc->onOpen([&]() { cout << "[DataChannel open: " << dc->label() << "]" << endl; });
  94. dc->onClosed([&]() { cout << "[DataChannel closed: " << dc->label() << "]" << endl; });
  95. dc->onMessage([](const variant<binary, string> &message) {
  96. if (holds_alternative<string>(message)) {
  97. cout << "[Received: " << get<string>(message) << "]" << endl;
  98. }
  99. });
  100. this_thread::sleep_for(1s);
  101. bool exit = false;
  102. while (!exit) {
  103. cout << endl
  104. << "**********************************************************************************"
  105. "*****"
  106. << endl
  107. << "* 0: Exit /"
  108. << " 1: Send message *" << endl
  109. << "[Command]: ";
  110. int command = -1;
  111. cin >> command;
  112. cin.ignore();
  113. switch (command) {
  114. case 0: {
  115. exit = true;
  116. break;
  117. }
  118. case 1: {
  119. // Send Message
  120. if (!dc->isOpen()) {
  121. cout << "** Channel is not Open ** ";
  122. break;
  123. }
  124. cout << "[Message]: ";
  125. string message;
  126. getline(cin, message);
  127. dc->send(message);
  128. break;
  129. }
  130. case 4: {
  131. // Connection Info
  132. if (!dc || !dc->isOpen()) {
  133. cout << "** Channel is not Open ** ";
  134. break;
  135. }
  136. CandidateInfo local, remote;
  137. std::optional<std::chrono::milliseconds> rtt = pc->rtt();
  138. if (pc->getSelectedCandidatePair(&local, &remote)) {
  139. cout << "Local: " << local.address << ":" << local.port << " " << local.type << " "
  140. << local.transportType << endl;
  141. cout << "Remote: " << remote.address << ":" << remote.port << " " << remote.type
  142. << " " << remote.transportType << endl;
  143. cout << "Bytes Sent:" << pc->bytesSent()
  144. << " / Bytes Received:" << pc->bytesReceived() << " / Round-Trip Time:";
  145. if (rtt.has_value())
  146. cout << rtt.value().count();
  147. else
  148. cout << "null";
  149. cout << " ms";
  150. } else
  151. cout << "Could not get Candidate Pair Info" << endl;
  152. break;
  153. }
  154. default: {
  155. cout << "** Invalid Command ** ";
  156. break;
  157. }
  158. }
  159. }
  160. if (dc)
  161. dc->close();
  162. if (pc)
  163. pc->close();
  164. }