capi.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. /**
  2. * Copyright (c) 2020 Paul-Louis Ageneau
  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.h>
  19. #include <cstdbool>
  20. #include <cstdio>
  21. #include <cstdlib>
  22. #include <cstring>
  23. #include <unistd.h> // for sleep
  24. using namespace std;
  25. typedef struct {
  26. rtcState state;
  27. rtcGatheringState gatheringState;
  28. int pc;
  29. int dc;
  30. bool connected;
  31. } Peer;
  32. Peer *peer1 = NULL;
  33. Peer *peer2 = NULL;
  34. static void descriptionCallback(const char *sdp, const char *type, void *ptr) {
  35. Peer *peer = (Peer *)ptr;
  36. printf("Description %d:\n%s\n", peer == peer1 ? 1 : 2, sdp);
  37. Peer *other = peer == peer1 ? peer2 : peer1;
  38. rtcSetRemoteDescription(other->pc, sdp, type);
  39. }
  40. static void candidateCallback(const char *cand, const char *mid, void *ptr) {
  41. Peer *peer = (Peer *)ptr;
  42. printf("Candidate %d: %s\n", peer == peer1 ? 1 : 2, cand);
  43. Peer *other = peer == peer1 ? peer2 : peer1;
  44. rtcAddRemoteCandidate(other->pc, cand, mid);
  45. }
  46. static void stateChangeCallback(rtcState state, void *ptr) {
  47. Peer *peer = (Peer *)ptr;
  48. peer->state = state;
  49. printf("State %d: %d\n", peer == peer1 ? 1 : 2, (int)state);
  50. }
  51. static void gatheringStateCallback(rtcGatheringState state, void *ptr) {
  52. Peer *peer = (Peer *)ptr;
  53. peer->gatheringState = state;
  54. printf("Gathering state %d: %d\n", peer == peer1 ? 1 : 2, (int)state);
  55. }
  56. static void openCallback(void *ptr) {
  57. Peer *peer = (Peer *)ptr;
  58. peer->connected = true;
  59. printf("DataChannel %d: Open\n", peer == peer1 ? 1 : 2);
  60. const char *message = peer == peer1 ? "Hello from 1" : "Hello from 2";
  61. rtcSendMessage(peer->dc, message, -1); // negative size indicates a null-terminated string
  62. }
  63. static void closedCallback(void *ptr) {
  64. Peer *peer = (Peer *)ptr;
  65. peer->connected = false;
  66. }
  67. static void messageCallback(const char *message, int size, void *ptr) {
  68. Peer *peer = (Peer *)ptr;
  69. if (size < 0) { // negative size indicates a null-terminated string
  70. printf("Message %d: %s\n", peer == peer1 ? 1 : 2, message);
  71. } else {
  72. printf("Message %d: [binary of size %d]\n", peer == peer1 ? 1 : 2, size);
  73. }
  74. }
  75. static void dataChannelCallback(int dc, void *ptr) {
  76. Peer *peer = (Peer *)ptr;
  77. peer->dc = dc;
  78. peer->connected = true;
  79. rtcSetClosedCallback(dc, closedCallback);
  80. rtcSetMessageCallback(dc, messageCallback);
  81. char buffer[256];
  82. if (rtcGetDataChannelLabel(dc, buffer, 256) >= 0)
  83. printf("DataChannel %d: Received with label \"%s\"\n", peer == peer1 ? 1 : 2, buffer);
  84. const char *message = peer == peer1 ? "Hello from 1" : "Hello from 2";
  85. rtcSendMessage(peer->dc, message, -1); // negative size indicates a null-terminated string
  86. }
  87. static Peer *createPeer(const rtcConfiguration *config) {
  88. Peer *peer = (Peer *)malloc(sizeof(Peer));
  89. if (!peer)
  90. return nullptr;
  91. memset(peer, 0, sizeof(Peer));
  92. // Create peer connection
  93. peer->pc = rtcCreatePeerConnection(config);
  94. rtcSetUserPointer(peer->pc, peer);
  95. rtcSetDataChannelCallback(peer->pc, dataChannelCallback);
  96. rtcSetLocalDescriptionCallback(peer->pc, descriptionCallback);
  97. rtcSetLocalCandidateCallback(peer->pc, candidateCallback);
  98. rtcSetStateChangeCallback(peer->pc, stateChangeCallback);
  99. rtcSetGatheringStateChangeCallback(peer->pc, gatheringStateCallback);
  100. return peer;
  101. }
  102. static void deletePeer(Peer *peer) {
  103. if (peer) {
  104. if (peer->dc)
  105. rtcDeleteDataChannel(peer->dc);
  106. if (peer->pc)
  107. rtcDeletePeerConnection(peer->pc);
  108. free(peer);
  109. }
  110. }
  111. int test_capi_main() {
  112. int attempts;
  113. rtcInitLogger(RTC_LOG_DEBUG);
  114. // Create peer 1
  115. rtcConfiguration config1;
  116. memset(&config1, 0, sizeof(config1));
  117. // STUN server example
  118. // const char *iceServers[1] = {"stun:stun.l.google.com:19302"};
  119. // config1.iceServers = iceServers;
  120. // config1.iceServersCount = 1;
  121. peer1 = createPeer(&config1);
  122. if (!peer1)
  123. goto error;
  124. // Create peer 2
  125. rtcConfiguration config2;
  126. memset(&config2, 0, sizeof(config2));
  127. // STUN server example
  128. // config2.iceServers = iceServers;
  129. // config2.iceServersCount = 1;
  130. // Port range example
  131. config2.portRangeBegin = 5000;
  132. config2.portRangeEnd = 6000;
  133. peer2 = createPeer(&config2);
  134. if (!peer2)
  135. goto error;
  136. // Peer 1: Create data channel
  137. peer1->dc = rtcCreateDataChannel(peer1->pc, "test");
  138. rtcSetOpenCallback(peer1->dc, openCallback);
  139. rtcSetClosedCallback(peer1->dc, closedCallback);
  140. rtcSetMessageCallback(peer1->dc, messageCallback);
  141. attempts = 10;
  142. while (!peer2->connected && !peer1->connected && attempts--)
  143. sleep(1);
  144. if (peer1->state != RTC_CONNECTED || peer2->state != RTC_CONNECTED) {
  145. fprintf(stderr, "PeerConnection is not connected\n");
  146. goto error;
  147. }
  148. if (!peer1->connected || !peer2->connected) {
  149. fprintf(stderr, "DataChannel is not connected\n");
  150. goto error;
  151. }
  152. char buffer[256];
  153. if (rtcGetLocalAddress(peer1->pc, buffer, 256) >= 0)
  154. printf("Local address 1: %s\n", buffer);
  155. if (rtcGetRemoteAddress(peer1->pc, buffer, 256) >= 0)
  156. printf("Remote address 1: %s\n", buffer);
  157. if (rtcGetLocalAddress(peer2->pc, buffer, 256) >= 0)
  158. printf("Local address 2: %s\n", buffer);
  159. if (rtcGetRemoteAddress(peer2->pc, buffer, 256) >= 0)
  160. printf("Remote address 2: %s\n", buffer);
  161. deletePeer(peer1);
  162. sleep(1);
  163. deletePeer(peer2);
  164. sleep(1);
  165. printf("Success\n");
  166. return 0;
  167. error:
  168. deletePeer(peer1);
  169. deletePeer(peer2);
  170. return -1;
  171. }
  172. #include <stdexcept>
  173. void test_capi() {
  174. if (test_capi_main())
  175. throw std::runtime_error("Connection failed");
  176. }