OpenTera WebRTC API (C++) 1.2.5
OpenTera WebRTC C++ Library API Documentation

Examples

Data Channel Client Example

1 #include <OpenteraWebrtcNativeClient/DataChannelClient.h>
2 
3 #include <iostream>
4 
5 using namespace opentera;
6 using namespace std;
7 
8 int main(int argc, char* argv[])
9 {
10  vector<IceServer> iceServers;
11  if (!IceServer::fetchFromServer("http://localhost:8080/iceservers", "abc", iceServers))
12  {
13  cout << "IceServer::fetchFromServer failed" << endl;
14  iceServers.clear();
15  }
16 
17  auto signalingServerConfiguration =
18  SignalingServerConfiguration::create("ws://localhost:8080/signaling", "C++", "chat", "abc");
19  auto webrtcConfiguration = WebrtcConfiguration::create(iceServers);
20  auto dataChannelConfiguration = DataChannelConfiguration::create();
21  DataChannelClient client(signalingServerConfiguration, webrtcConfiguration, dataChannelConfiguration);
22 
23  client.setOnSignalingConnectionOpened(
24  []()
25  {
26  // This callback is called from the internal client thread.
27  cout << "OnSignalingConnectionOpened" << endl;
28  });
29  client.setOnSignalingConnectionClosed(
30  []()
31  {
32  // This callback is called from the internal client thread.
33  cout << "OnSignalingConnectionClosed" << endl;
34  });
35  client.setOnSignalingConnectionError(
36  [](const string& error)
37  {
38  // This callback is called from the internal client thread.
39  cout << "OnSignalingConnectionError:" << endl << "\t" << error;
40  });
41 
42  client.setOnRoomClientsChanged(
43  [](const vector<RoomClient>& roomClients)
44  {
45  // This callback is called from the internal client thread.
46  cout << "OnRoomClientsChanged:" << endl;
47  for (const auto& c : roomClients)
48  {
49  cout << "\tid=" << c.id() << ", name=" << c.name() << ", isConnected=" << c.isConnected() << endl;
50  }
51  });
52 
53  client.setOnClientConnected(
54  [](const Client& client)
55  {
56  // This callback is called from the internal client thread.
57  cout << "OnClientConnected:" << endl;
58  cout << "\tid=" << client.id() << ", name=" << client.name() << endl;
59  });
60  client.setOnClientDisconnected(
61  [](const Client& client)
62  {
63  // This callback is called from the internal client thread.
64  cout << "OnClientDisconnected:" << endl;
65  cout << "\tid=" << client.id() << ", name=" << client.name() << endl;
66  });
67  client.setOnClientConnectionFailed(
68  [](const Client& client)
69  {
70  // This callback is called from the internal client thread.
71  cout << "OnClientConnectionFailed:" << endl;
72  cout << "\tid=" << client.id() << ", name=" << client.name() << endl;
73  });
74 
75  client.setOnError(
76  [](const string& error)
77  {
78  // This callback is called from the internal client thread.
79  cout << "error:" << endl;
80  cout << "\t" << error << endl;
81  });
82 
83  client.setLogger(
84  [](const string& message)
85  {
86  // This callback is called from the internal client thread.
87  cout << "log:" << endl;
88  cout << "\t" << message << endl;
89  });
90 
91  client.setOnDataChannelOpened(
92  [](const Client& client)
93  {
94  // This callback is called from the internal client thread.
95  cout << "OnDataChannelOpened:" << endl;
96  cout << "\tid=" << client.id() << ", name=" << client.name() << endl;
97  });
98  client.setOnDataChannelClosed(
99  [](const Client& client)
100  {
101  // This callback is called from the internal client thread.
102  cout << "OnDataChannelClosed:" << endl;
103  cout << "\tid=" << client.id() << ", name=" << client.name() << endl;
104  });
105  client.setOnDataChannelError(
106  [](const Client& client, const string& error)
107  {
108  // This callback is called from the internal client thread.
109  cout << "OnDataChannelError:" << endl;
110  cout << "\tid=" << client.id() << ", name=" << client.name() << endl;
111  cout << "\t" << error << endl;
112  });
113  client.setOnDataChannelMessageString(
114  [](const Client& client, const string& message)
115  {
116  // This callback is called from the internal client thread.
117  cout << "setOnDataChannelMessageString:" << endl;
118  cout << "\tid=" << client.id() << ", name=" << client.name() << endl;
119  cout << "\t" << message << endl;
120  });
121 
122  client.connect();
123 
124  cin.get();
125 
126  return 0;
127 }
Represents a peer client.
Definition: Client.h:14
const std::string & id() const
Returns the client id.
Definition: Client.h:43
const std::string & name() const
Returns the client name.
Definition: Client.h:49
Represents a client for data channel communication.
Definition: DataChannelClient.h:16
static DataChannelConfiguration create()
Creates a data channel configuration with default values.
Definition: DataChannelConfiguration.h:62
static bool fetchFromServer(const std::string &url, const std::string &password, std::vector< IceServer > &iceServers, bool verifyCertificate=true)
Fetches the ice servers from the signaling server.
Definition: IceServer.cpp:61
static SignalingServerConfiguration create(std::string url, std::string clientName, std::string room)
Creates an signaling server configuration with the specified values.
Definition: SignalingServerConfiguration.h:64
static WebrtcConfiguration create()
Creates a WebRTC peer connection configuration with default values.
Definition: WebrtcConfiguration.h:39

Video Stream Client Example

1 #include <OpenteraWebrtcNativeClient/StreamClient.h>
2 
3 #include <opencv2/core.hpp>
4 #include <opencv2/videoio.hpp>
5 #include <opencv2/highgui.hpp>
6 
7 #include <cmath>
8 #include <iostream>
9 #include <thread>
10 #include <vector>
11 #include <cstdlib>
12 
13 using namespace opentera;
14 using namespace std;
15 
16 class CvVideoCaptureVideoSource : public VideoSource
17 {
18  atomic_bool m_stopped;
19  thread m_thread;
20  string m_path;
21 
22 public:
23  CvVideoCaptureVideoSource(string path)
24  : VideoSource(VideoSourceConfiguration::create(false, true)),
25  m_stopped(false),
26  m_thread(&CvVideoCaptureVideoSource::run, this),
27  m_path(move(path))
28  {
29  }
30 
31  ~CvVideoCaptureVideoSource() override
32  {
33  m_stopped.store(true);
34  m_thread.join();
35  }
36 
37 private:
38  void run()
39  {
40  cv::VideoCapture cap;
41  cv::Mat bgrImg;
42 
43  while (!m_stopped.load())
44  {
45  cap.open(m_path);
46  if (!cap.isOpened())
47  {
48  cerr << "Invalid video file" << endl;
49  exit(EXIT_FAILURE);
50  }
51 
52  auto frameDuration = chrono::microseconds(static_cast<int>(1e6 / cap.get(cv::CAP_PROP_FPS)));
53  auto frameTime = chrono::steady_clock::now();
54  while (!m_stopped.load())
55  {
56  cap.read(bgrImg);
57  if (bgrImg.empty())
58  {
59  break;
60  }
61 
62  int64_t timestampUs =
63  chrono::duration_cast<chrono::microseconds>(chrono::steady_clock::now().time_since_epoch()).count();
64  sendFrame(bgrImg, timestampUs);
65 
66  frameTime += frameDuration;
67  this_thread::sleep_until(frameTime);
68  }
69  }
70  }
71 };
72 
73 constexpr uint32_t SoundCardTotalDelayMs = 0;
74 constexpr int BitsPerSample = 16;
75 constexpr int SampleRate = 48000;
76 constexpr size_t NumberOfChannels = 1;
77 constexpr chrono::milliseconds SinAudioSourceFrameDuration = 10ms;
78 constexpr chrono::milliseconds SinAudioSourceSleepBuffer = 2ms;
79 constexpr int16_t SinAudioSourceAmplitude = 15000;
80 
81 class SinAudioSource : public AudioSource
82 {
83  atomic_bool m_stopped;
84  thread m_thread;
85 
86 public:
87  SinAudioSource()
88  : AudioSource(
89  AudioSourceConfiguration::create(SoundCardTotalDelayMs),
90  BitsPerSample,
91  SampleRate,
92  NumberOfChannels),
93  m_stopped(false),
94  m_thread(&SinAudioSource::run, this)
95  {
96  }
97 
98  ~SinAudioSource() override
99  {
100  m_stopped.store(true);
101  m_thread.join();
102  }
103 
104 private:
105  void run()
106  {
107  vector<int16_t> data(SinAudioSourceFrameDuration.count() * SampleRate / 1000, 0);
108  double t = 0;
109  for (size_t i = 0; i < data.size(); i++)
110  {
111  data[i] = static_cast<int16_t>(SinAudioSourceAmplitude * sin(t));
112  t += 2 * M_PI / static_cast<double>(data.size());
113  }
114 
115  while (!m_stopped.load())
116  {
117  sendFrame(data.data(), data.size() * sizeof(int16_t) / bytesPerFrame());
118 
119  auto start = chrono::steady_clock::now();
120  this_thread::sleep_for(SinAudioSourceFrameDuration - SinAudioSourceSleepBuffer);
121  while ((chrono::steady_clock::now() - start) < SinAudioSourceFrameDuration);
122  }
123  }
124 };
125 
126 int main(int argc, char* argv[])
127 {
128  if (argc != 2)
129  {
130  cout << "Usage: CppStreamClient video_path" << endl;
131  return EXIT_FAILURE;
132  }
133 
134  vector<IceServer> iceServers;
135  if (!IceServer::fetchFromServer("http://localhost:8080/iceservers", "abc", iceServers))
136  {
137  cout << "IceServer::fetchFromServer failed" << endl;
138  iceServers.clear();
139  }
140 
141  auto signalingServerConfiguration =
142  SignalingServerConfiguration::create("ws://localhost:8080/signaling", "C++", "chat", "abc");
143  auto webrtcConfiguration = WebrtcConfiguration::create(iceServers);
144  auto videoStreamConfiguration = VideoStreamConfiguration::create();
145  auto videoSource = make_shared<CvVideoCaptureVideoSource>(argv[1]);
146  auto audioSource = make_shared<SinAudioSource>();
148  client(signalingServerConfiguration, webrtcConfiguration, videoStreamConfiguration, videoSource, audioSource);
149 
150  client.setOnSignalingConnectionOpened(
151  []()
152  {
153  // This callback is called from the internal client thread.
154  cout << "OnSignalingConnectionOpened" << endl;
155  });
156  client.setOnSignalingConnectionClosed(
157  []()
158  {
159  // This callback is called from the internal client thread.
160  cout << "OnSignalingConnectionClosed" << endl;
161  });
162  client.setOnSignalingConnectionError(
163  [](const string& error)
164  {
165  // This callback is called from the internal client thread.
166  cout << "OnSignalingConnectionError:" << endl << "\t" << error;
167  });
168 
169  client.setOnRoomClientsChanged(
170  [](const vector<RoomClient>& roomClients)
171  {
172  // This callback is called from the internal client thread.
173  cout << "OnRoomClientsChanged:" << endl;
174  for (const auto& c : roomClients)
175  {
176  cout << "\tid=" << c.id() << ", name=" << c.name() << ", isConnected=" << c.isConnected() << endl;
177  }
178  });
179 
180  client.setOnClientConnected(
181  [](const Client& client)
182  {
183  // This callback is called from the internal client thread.
184  cout << "OnClientConnected:" << endl;
185  cout << "\tid=" << client.id() << ", name=" << client.name() << endl;
186  cv::namedWindow(client.id(), cv::WINDOW_AUTOSIZE);
187  });
188  client.setOnClientDisconnected(
189  [](const Client& client)
190  {
191  // This callback is called from the internal client thread.
192  cout << "OnClientDisconnected:" << endl;
193  cout << "\tid=" << client.id() << ", name=" << client.name() << endl;
194  cv::destroyWindow(client.id());
195  });
196  client.setOnClientConnectionFailed(
197  [](const Client& client)
198  {
199  // This callback is called from the internal client thread.
200  cout << "OnClientConnectionFailed:" << endl;
201  cout << "\tid=" << client.id() << ", name=" << client.name() << endl;
202  });
203 
204  client.setOnError(
205  [](const string& error)
206  {
207  // This callback is called from the internal client thread.
208  cout << "error:" << endl;
209  cout << "\t" << error << endl;
210  });
211 
212  client.setLogger(
213  [](const string& message)
214  {
215  // This callback is called from the internal client thread.
216  cout << "log:" << endl;
217  cout << "\t" << message << endl;
218  });
219 
220  client.setOnAddRemoteStream(
221  [](const Client& client)
222  {
223  // This callback is called from the internal client thread.
224  cout << "OnAddRemoteStream:" << endl;
225  cout << "\tid=" << client.id() << ", name=" << client.name() << endl;
226  });
227  client.setOnRemoveRemoteStream(
228  [](const Client& client)
229  {
230  // This callback is called from the internal client thread.
231  cout << "OnRemoveRemoteStream:" << endl;
232  cout << "\tid=" << client.id() << ", name=" << client.name() << endl;
233  });
234  client.setOnVideoFrameReceived(
235  [](const Client& client, const cv::Mat& bgrImg, uint64_t timestampUs)
236  {
237  // This callback is called from a WebRTC processing thread.
238  cout << "OnVideoFrameReceived:" << endl;
239  cv::imshow(client.id(), bgrImg);
240  cv::waitKey(1);
241  });
242  client.setOnAudioFrameReceived(
243  [](const Client& client,
244  const void* audioData,
245  int bitsPerSample,
246  int sampleRate,
247  size_t numberOfChannels,
248  size_t numberOfFrames)
249  {
250  // This callback is called from a WebRTC processing thread.
251  cout << "OnAudioFrameReceived:" << endl;
252  cout << "\tid=" << client.id() << ", name=" << client.name() << endl;
253  cout << "\tbitsPerSample=" << bitsPerSample << ", sampleRate = " << sampleRate;
254  cout << ", numberOfChannels = " << numberOfChannels << ", numberOfFrames=" << numberOfFrames << endl;
255  });
256  client.setOnMixedAudioFrameReceived(
257  [](const void* audioData, int bitsPerSample, int sampleRate, size_t numberOfChannels, size_t numberOfFrames)
258  {
259  // This callback is called from the audio device module thread.
260  cout << "OnMixedAudioFrameReceived:" << endl;
261  cout << "\tbitsPerSample=" << bitsPerSample << ", sampleRate=" << sampleRate;
262  cout << ", numberOfChannels=" << numberOfChannels << ", numberOfFrames=" << numberOfFrames << endl;
263  });
264 
265  client.connect();
266 
267  cin.get();
268 
269  return 0;
270 }
Represents a configuration of an audio source that can be added to a WebRTC call.
Definition: AudioSourceConfiguration.h:13
Represents an audio source that can be added to a WebRTC call.
Definition: AudioSource.h:25
A signaling client to join a WebRTC room and stream a video source.
Definition: StreamClient.h:18
Represents a configuration of a video source that can be added to a WebRTC call.
Definition: VideoSourceConfiguration.h:10
Represents a video source that can be added to a WebRTC call.
Definition: VideoSource.h:21
static VideoStreamConfiguration create()
Creates a stream configuration with default values.
Definition: VideoStreamConfiguration.h:60