/** * Copyright (c) 2019 Paul-Louis Ageneau, Murat Dogan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "rtc/rtc.hpp" #include #include #include #include #include #include using namespace rtc; using namespace std; using namespace std::chrono_literals; template weak_ptr make_weak_ptr(shared_ptr ptr) { return ptr; } const char base64_url_alphabet[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_' }; std::string base64_encode(const std::string & in) { std::string out; int val =0, valb=-6; size_t len = in.length(); unsigned int i = 0; for (i = 0; i < len; i++) { unsigned char c = in[i]; val = (val<<8) + c; valb += 8; while (valb >= 0) { out.push_back(base64_url_alphabet[(val>>valb)&0x3F]); valb -= 6; } } if (valb > -6) { out.push_back(base64_url_alphabet[((val<<8)>>(valb+8))&0x3F]); } return out; } int main(int argc, char **argv) { InitLogger(LogLevel::Warning); Configuration config; // config.iceServers.emplace_back("stun.l.google.com:19302"); std::string payload; auto pc = std::make_shared(config); pc->onLocalDescription([wpc = make_weak_ptr(pc)](const Description &description){ auto pc = wpc.lock(); if (!pc) return; pc->connectionInfo += description; pc->connectionInfo += ","; }); pc->onLocalCandidate([wpc = make_weak_ptr(pc)](const Candidate &candidate) { auto pc = wpc.lock(); if (!pc) return; pc->connectionInfo += candidate; cout << pc->connectionInfo << endl << endl; auto encoded = base64_encode(pc->connectionInfo); cout << "http://localhost:8080/answerer.html?connection=" << encoded << endl << endl; httplib::Client cli("localhost", 8000); auto res = cli.Get("/state/json"); if (!res) return; while (res->body.empty()) { std::this_thread::sleep_for(2s); res = cli.Get("/state/json"); } pc->setRemoteDescription(res->body); }); pc->onStateChange([wpc = make_weak_ptr(pc)](PeerConnection::State state) { cout << "[State: " << state << "]" << endl; }); pc->onGatheringStateChange([](PeerConnection::GatheringState state) { cout << "[Gathering State: " << state << "]" << endl; }); auto dc = pc->createDataChannel("test"); // this is the offerer, so create a data channel dc->onOpen([&]() { cout << "[DataChannel open: " << dc->label() << "]" << endl; }); dc->onClosed([&]() { cout << "[DataChannel closed: " << dc->label() << "]" << endl; }); dc->onMessage([](const variant &message) { if (holds_alternative(message)) { cout << "[Received: " << get(message) << "]" << endl; } }); this_thread::sleep_for(1s); bool exit = false; while (!exit) { cout << endl << "**********************************************************************************" "*****" << endl << "* 0: Exit /" << " 1: Send message *" << endl << "[Command]: "; int command = -1; cin >> command; cin.ignore(); switch (command) { case 0: { exit = true; break; } case 1: { // Send Message if (!dc->isOpen()) { cout << "** Channel is not Open ** "; break; } cout << "[Message]: "; string message; getline(cin, message); dc->send(message); break; } case 4: { // Connection Info if (!dc || !dc->isOpen()) { cout << "** Channel is not Open ** "; break; } CandidateInfo local, remote; std::optional rtt = pc->rtt(); if (pc->getSelectedCandidatePair(&local, &remote)) { cout << "Local: " << local.address << ":" << local.port << " " << local.type << " " << local.transportType << endl; cout << "Remote: " << remote.address << ":" << remote.port << " " << remote.type << " " << remote.transportType << endl; cout << "Bytes Sent:" << pc->bytesSent() << " / Bytes Received:" << pc->bytesReceived() << " / Round-Trip Time:"; if (rtt.has_value()) cout << rtt.value().count(); else cout << "null"; cout << " ms"; } else cout << "Could not get Candidate Pair Info" << endl; break; } default: { cout << "** Invalid Command ** "; break; } } } if (dc) dc->close(); if (pc) pc->close(); }