1 /*
2 * Copyright 2020 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "examples/androidvoip/jni/android_voip_client.h"
12
13 #include <errno.h>
14 #include <sys/socket.h>
15 #include <algorithm>
16 #include <map>
17 #include <memory>
18 #include <unordered_map>
19 #include <unordered_set>
20 #include <utility>
21 #include <vector>
22
23 #include "absl/memory/memory.h"
24 #include "api/audio_codecs/builtin_audio_decoder_factory.h"
25 #include "api/audio_codecs/builtin_audio_encoder_factory.h"
26 #include "api/task_queue/default_task_queue_factory.h"
27 #include "api/voip/voip_codec.h"
28 #include "api/voip/voip_engine_factory.h"
29 #include "api/voip/voip_network.h"
30 #include "examples/androidvoip/generated_jni/VoipClient_jni.h"
31 #include "rtc_base/logging.h"
32 #include "rtc_base/network.h"
33 #include "rtc_base/socket_server.h"
34 #include "sdk/android/native_api/audio_device_module/audio_device_android.h"
35 #include "sdk/android/native_api/jni/java_types.h"
36 #include "sdk/android/native_api/jni/jvm.h"
37 #include "sdk/android/native_api/jni/scoped_java_ref.h"
38
39 namespace {
40
41 #define RUN_ON_VOIP_THREAD(method, ...) \
42 if (!voip_thread_->IsCurrent()) { \
43 voip_thread_->PostTask( \
44 std::bind(&AndroidVoipClient::method, this, ##__VA_ARGS__)); \
45 return; \
46 } \
47 RTC_DCHECK_RUN_ON(voip_thread_.get());
48
49 // Connects a UDP socket to a public address and returns the local
50 // address associated with it. Since it binds to the "any" address
51 // internally, it returns the default local address on a multi-homed
52 // endpoint. Implementation copied from
53 // BasicNetworkManager::QueryDefaultLocalAddress.
QueryDefaultLocalAddress(int family)54 rtc::IPAddress QueryDefaultLocalAddress(int family) {
55 const char kPublicIPv4Host[] = "8.8.8.8";
56 const char kPublicIPv6Host[] = "2001:4860:4860::8888";
57 const int kPublicPort = 53;
58 std::unique_ptr<rtc::Thread> thread = rtc::Thread::CreateWithSocketServer();
59
60 RTC_DCHECK(thread->socketserver() != nullptr);
61 RTC_DCHECK(family == AF_INET || family == AF_INET6);
62
63 std::unique_ptr<rtc::Socket> socket(
64 thread->socketserver()->CreateSocket(family, SOCK_DGRAM));
65 if (!socket) {
66 RTC_LOG_ERR(LS_ERROR) << "Socket creation failed";
67 return rtc::IPAddress();
68 }
69
70 auto host = family == AF_INET ? kPublicIPv4Host : kPublicIPv6Host;
71 if (socket->Connect(rtc::SocketAddress(host, kPublicPort)) < 0) {
72 if (socket->GetError() != ENETUNREACH &&
73 socket->GetError() != EHOSTUNREACH) {
74 RTC_LOG(LS_INFO) << "Connect failed with " << socket->GetError();
75 }
76 return rtc::IPAddress();
77 }
78 return socket->GetLocalAddress().ipaddr();
79 }
80
81 // Assigned payload type for supported built-in codecs. PCMU, PCMA,
82 // and G722 have set payload types. Whereas opus, ISAC, and ILBC
83 // have dynamic payload types.
84 enum class PayloadType : int {
85 kPcmu = 0,
86 kPcma = 8,
87 kG722 = 9,
88 kOpus = 96,
89 kIsac = 97,
90 kIlbc = 98,
91 };
92
93 // Returns the payload type corresponding to codec_name. Only
94 // supports the built-in codecs.
GetPayloadType(const std::string & codec_name)95 int GetPayloadType(const std::string& codec_name) {
96 RTC_DCHECK(codec_name == "PCMU" || codec_name == "PCMA" ||
97 codec_name == "G722" || codec_name == "opus" ||
98 codec_name == "ISAC" || codec_name == "ILBC");
99
100 if (codec_name == "PCMU") {
101 return static_cast<int>(PayloadType::kPcmu);
102 } else if (codec_name == "PCMA") {
103 return static_cast<int>(PayloadType::kPcma);
104 } else if (codec_name == "G722") {
105 return static_cast<int>(PayloadType::kG722);
106 } else if (codec_name == "opus") {
107 return static_cast<int>(PayloadType::kOpus);
108 } else if (codec_name == "ISAC") {
109 return static_cast<int>(PayloadType::kIsac);
110 } else if (codec_name == "ILBC") {
111 return static_cast<int>(PayloadType::kIlbc);
112 }
113
114 RTC_DCHECK_NOTREACHED();
115 return -1;
116 }
117
118 } // namespace
119
120 namespace webrtc_examples {
121
Init(JNIEnv * env,const webrtc::JavaParamRef<jobject> & application_context)122 void AndroidVoipClient::Init(
123 JNIEnv* env,
124 const webrtc::JavaParamRef<jobject>& application_context) {
125 webrtc::VoipEngineConfig config;
126 config.encoder_factory = webrtc::CreateBuiltinAudioEncoderFactory();
127 config.decoder_factory = webrtc::CreateBuiltinAudioDecoderFactory();
128 config.task_queue_factory = webrtc::CreateDefaultTaskQueueFactory();
129 config.audio_device_module =
130 webrtc::CreateJavaAudioDeviceModule(env, application_context.obj());
131 config.audio_processing = webrtc::AudioProcessingBuilder().Create();
132
133 voip_thread_->Start();
134
135 // Due to consistent thread requirement on
136 // modules/audio_device/android/audio_device_template.h,
137 // code is invoked in the context of voip_thread_.
138 voip_thread_->BlockingCall([this, &config] {
139 RTC_DCHECK_RUN_ON(voip_thread_.get());
140
141 supported_codecs_ = config.encoder_factory->GetSupportedEncoders();
142 env_ = webrtc::AttachCurrentThreadIfNeeded();
143 voip_engine_ = webrtc::CreateVoipEngine(std::move(config));
144 });
145 }
146
~AndroidVoipClient()147 AndroidVoipClient::~AndroidVoipClient() {
148 voip_thread_->BlockingCall([this] {
149 RTC_DCHECK_RUN_ON(voip_thread_.get());
150
151 JavaVM* jvm = nullptr;
152 env_->GetJavaVM(&jvm);
153 if (!jvm) {
154 RTC_LOG(LS_ERROR) << "Failed to retrieve JVM";
155 return;
156 }
157 jint res = jvm->DetachCurrentThread();
158 if (res != JNI_OK) {
159 RTC_LOG(LS_ERROR) << "DetachCurrentThread failed: " << res;
160 }
161 });
162
163 voip_thread_->Stop();
164 }
165
Create(JNIEnv * env,const webrtc::JavaParamRef<jobject> & application_context,const webrtc::JavaParamRef<jobject> & j_voip_client)166 AndroidVoipClient* AndroidVoipClient::Create(
167 JNIEnv* env,
168 const webrtc::JavaParamRef<jobject>& application_context,
169 const webrtc::JavaParamRef<jobject>& j_voip_client) {
170 // Using `new` to access a non-public constructor.
171 auto voip_client =
172 absl::WrapUnique(new AndroidVoipClient(env, j_voip_client));
173 voip_client->Init(env, application_context);
174 return voip_client.release();
175 }
176
GetSupportedCodecs(JNIEnv * env)177 void AndroidVoipClient::GetSupportedCodecs(JNIEnv* env) {
178 RUN_ON_VOIP_THREAD(GetSupportedCodecs, env);
179
180 std::vector<std::string> names;
181 for (const webrtc::AudioCodecSpec& spec : supported_codecs_) {
182 names.push_back(spec.format.name);
183 }
184 webrtc::ScopedJavaLocalRef<jstring> (*convert_function)(
185 JNIEnv*, const std::string&) = &webrtc::NativeToJavaString;
186 Java_VoipClient_onGetSupportedCodecsCompleted(
187 env_, j_voip_client_, NativeToJavaList(env_, names, convert_function));
188 }
189
GetLocalIPAddress(JNIEnv * env)190 void AndroidVoipClient::GetLocalIPAddress(JNIEnv* env) {
191 RUN_ON_VOIP_THREAD(GetLocalIPAddress, env);
192
193 std::string local_ip_address;
194 rtc::IPAddress ipv4_address = QueryDefaultLocalAddress(AF_INET);
195 if (!ipv4_address.IsNil()) {
196 local_ip_address = ipv4_address.ToString();
197 } else {
198 rtc::IPAddress ipv6_address = QueryDefaultLocalAddress(AF_INET6);
199 if (!ipv6_address.IsNil()) {
200 local_ip_address = ipv6_address.ToString();
201 }
202 }
203 Java_VoipClient_onGetLocalIPAddressCompleted(
204 env_, j_voip_client_, webrtc::NativeToJavaString(env_, local_ip_address));
205 }
206
SetEncoder(const std::string & encoder)207 void AndroidVoipClient::SetEncoder(const std::string& encoder) {
208 RTC_DCHECK_RUN_ON(voip_thread_.get());
209
210 if (!channel_) {
211 RTC_LOG(LS_ERROR) << "Channel has not been created";
212 return;
213 }
214 for (const webrtc::AudioCodecSpec& codec : supported_codecs_) {
215 if (codec.format.name == encoder) {
216 webrtc::VoipResult result = voip_engine_->Codec().SetSendCodec(
217 *channel_, GetPayloadType(codec.format.name), codec.format);
218 RTC_CHECK(result == webrtc::VoipResult::kOk);
219 return;
220 }
221 }
222 }
223
SetEncoder(JNIEnv * env,const webrtc::JavaParamRef<jstring> & j_encoder_string)224 void AndroidVoipClient::SetEncoder(
225 JNIEnv* env,
226 const webrtc::JavaParamRef<jstring>& j_encoder_string) {
227 const std::string& chosen_encoder =
228 webrtc::JavaToNativeString(env, j_encoder_string);
229 voip_thread_->PostTask(
230 [this, chosen_encoder] { SetEncoder(chosen_encoder); });
231 }
232
SetDecoders(const std::vector<std::string> & decoders)233 void AndroidVoipClient::SetDecoders(const std::vector<std::string>& decoders) {
234 RTC_DCHECK_RUN_ON(voip_thread_.get());
235
236 if (!channel_) {
237 RTC_LOG(LS_ERROR) << "Channel has not been created";
238 return;
239 }
240 std::map<int, webrtc::SdpAudioFormat> decoder_specs;
241 for (const webrtc::AudioCodecSpec& codec : supported_codecs_) {
242 if (std::find(decoders.begin(), decoders.end(), codec.format.name) !=
243 decoders.end()) {
244 decoder_specs.insert({GetPayloadType(codec.format.name), codec.format});
245 }
246 }
247
248 webrtc::VoipResult result =
249 voip_engine_->Codec().SetReceiveCodecs(*channel_, decoder_specs);
250 RTC_CHECK(result == webrtc::VoipResult::kOk);
251 }
252
SetDecoders(JNIEnv * env,const webrtc::JavaParamRef<jobject> & j_decoder_strings)253 void AndroidVoipClient::SetDecoders(
254 JNIEnv* env,
255 const webrtc::JavaParamRef<jobject>& j_decoder_strings) {
256 const std::vector<std::string>& chosen_decoders =
257 webrtc::JavaListToNativeVector<std::string, jstring>(
258 env, j_decoder_strings, &webrtc::JavaToNativeString);
259 voip_thread_->PostTask(
260 [this, chosen_decoders] { SetDecoders(chosen_decoders); });
261 }
262
SetLocalAddress(const std::string & ip_address,const int port_number)263 void AndroidVoipClient::SetLocalAddress(const std::string& ip_address,
264 const int port_number) {
265 RTC_DCHECK_RUN_ON(voip_thread_.get());
266
267 rtp_local_address_ = rtc::SocketAddress(ip_address, port_number);
268 rtcp_local_address_ = rtc::SocketAddress(ip_address, port_number + 1);
269 }
270
SetLocalAddress(JNIEnv * env,const webrtc::JavaParamRef<jstring> & j_ip_address_string,jint j_port_number_int)271 void AndroidVoipClient::SetLocalAddress(
272 JNIEnv* env,
273 const webrtc::JavaParamRef<jstring>& j_ip_address_string,
274 jint j_port_number_int) {
275 const std::string& ip_address =
276 webrtc::JavaToNativeString(env, j_ip_address_string);
277 voip_thread_->PostTask([this, ip_address, j_port_number_int] {
278 SetLocalAddress(ip_address, j_port_number_int);
279 });
280 }
281
SetRemoteAddress(const std::string & ip_address,const int port_number)282 void AndroidVoipClient::SetRemoteAddress(const std::string& ip_address,
283 const int port_number) {
284 RTC_DCHECK_RUN_ON(voip_thread_.get());
285
286 rtp_remote_address_ = rtc::SocketAddress(ip_address, port_number);
287 rtcp_remote_address_ = rtc::SocketAddress(ip_address, port_number + 1);
288 }
289
SetRemoteAddress(JNIEnv * env,const webrtc::JavaParamRef<jstring> & j_ip_address_string,jint j_port_number_int)290 void AndroidVoipClient::SetRemoteAddress(
291 JNIEnv* env,
292 const webrtc::JavaParamRef<jstring>& j_ip_address_string,
293 jint j_port_number_int) {
294 const std::string& ip_address =
295 webrtc::JavaToNativeString(env, j_ip_address_string);
296 voip_thread_->PostTask([this, ip_address, j_port_number_int] {
297 SetRemoteAddress(ip_address, j_port_number_int);
298 });
299 }
300
StartSession(JNIEnv * env)301 void AndroidVoipClient::StartSession(JNIEnv* env) {
302 RUN_ON_VOIP_THREAD(StartSession, env);
303
304 // CreateChannel guarantees to return valid channel id.
305 channel_ = voip_engine_->Base().CreateChannel(this, absl::nullopt);
306
307 rtp_socket_.reset(rtc::AsyncUDPSocket::Create(voip_thread_->socketserver(),
308 rtp_local_address_));
309 if (!rtp_socket_) {
310 RTC_LOG_ERR(LS_ERROR) << "Socket creation failed";
311 Java_VoipClient_onStartSessionCompleted(env_, j_voip_client_,
312 /*isSuccessful=*/false);
313 return;
314 }
315 rtp_socket_->SignalReadPacket.connect(
316 this, &AndroidVoipClient::OnSignalReadRTPPacket);
317
318 rtcp_socket_.reset(rtc::AsyncUDPSocket::Create(voip_thread_->socketserver(),
319 rtcp_local_address_));
320 if (!rtcp_socket_) {
321 RTC_LOG_ERR(LS_ERROR) << "Socket creation failed";
322 Java_VoipClient_onStartSessionCompleted(env_, j_voip_client_,
323 /*isSuccessful=*/false);
324 return;
325 }
326 rtcp_socket_->SignalReadPacket.connect(
327 this, &AndroidVoipClient::OnSignalReadRTCPPacket);
328 Java_VoipClient_onStartSessionCompleted(env_, j_voip_client_,
329 /*isSuccessful=*/true);
330 }
331
StopSession(JNIEnv * env)332 void AndroidVoipClient::StopSession(JNIEnv* env) {
333 RUN_ON_VOIP_THREAD(StopSession, env);
334
335 if (!channel_) {
336 RTC_LOG(LS_ERROR) << "Channel has not been created";
337 Java_VoipClient_onStopSessionCompleted(env_, j_voip_client_,
338 /*isSuccessful=*/false);
339 return;
340 }
341 if (voip_engine_->Base().StopSend(*channel_) != webrtc::VoipResult::kOk ||
342 voip_engine_->Base().StopPlayout(*channel_) != webrtc::VoipResult::kOk) {
343 Java_VoipClient_onStopSessionCompleted(env_, j_voip_client_,
344 /*isSuccessful=*/false);
345 return;
346 }
347
348 rtp_socket_->Close();
349 rtcp_socket_->Close();
350
351 webrtc::VoipResult result = voip_engine_->Base().ReleaseChannel(*channel_);
352 RTC_CHECK(result == webrtc::VoipResult::kOk);
353
354 channel_ = absl::nullopt;
355 Java_VoipClient_onStopSessionCompleted(env_, j_voip_client_,
356 /*isSuccessful=*/true);
357 }
358
StartSend(JNIEnv * env)359 void AndroidVoipClient::StartSend(JNIEnv* env) {
360 RUN_ON_VOIP_THREAD(StartSend, env);
361
362 if (!channel_) {
363 RTC_LOG(LS_ERROR) << "Channel has not been created";
364 Java_VoipClient_onStartSendCompleted(env_, j_voip_client_,
365 /*isSuccessful=*/false);
366 return;
367 }
368 bool sending_started =
369 (voip_engine_->Base().StartSend(*channel_) == webrtc::VoipResult::kOk);
370 Java_VoipClient_onStartSendCompleted(env_, j_voip_client_, sending_started);
371 }
372
StopSend(JNIEnv * env)373 void AndroidVoipClient::StopSend(JNIEnv* env) {
374 RUN_ON_VOIP_THREAD(StopSend, env);
375
376 if (!channel_) {
377 RTC_LOG(LS_ERROR) << "Channel has not been created";
378 Java_VoipClient_onStopSendCompleted(env_, j_voip_client_,
379 /*isSuccessful=*/false);
380 return;
381 }
382 bool sending_stopped =
383 (voip_engine_->Base().StopSend(*channel_) == webrtc::VoipResult::kOk);
384 Java_VoipClient_onStopSendCompleted(env_, j_voip_client_, sending_stopped);
385 }
386
StartPlayout(JNIEnv * env)387 void AndroidVoipClient::StartPlayout(JNIEnv* env) {
388 RUN_ON_VOIP_THREAD(StartPlayout, env);
389
390 if (!channel_) {
391 RTC_LOG(LS_ERROR) << "Channel has not been created";
392 Java_VoipClient_onStartPlayoutCompleted(env_, j_voip_client_,
393 /*isSuccessful=*/false);
394 return;
395 }
396 bool playout_started =
397 (voip_engine_->Base().StartPlayout(*channel_) == webrtc::VoipResult::kOk);
398 Java_VoipClient_onStartPlayoutCompleted(env_, j_voip_client_,
399 playout_started);
400 }
401
StopPlayout(JNIEnv * env)402 void AndroidVoipClient::StopPlayout(JNIEnv* env) {
403 RUN_ON_VOIP_THREAD(StopPlayout, env);
404
405 if (!channel_) {
406 RTC_LOG(LS_ERROR) << "Channel has not been created";
407 Java_VoipClient_onStopPlayoutCompleted(env_, j_voip_client_,
408 /*isSuccessful=*/false);
409 return;
410 }
411 bool playout_stopped =
412 (voip_engine_->Base().StopPlayout(*channel_) == webrtc::VoipResult::kOk);
413 Java_VoipClient_onStopPlayoutCompleted(env_, j_voip_client_, playout_stopped);
414 }
415
Delete(JNIEnv * env)416 void AndroidVoipClient::Delete(JNIEnv* env) {
417 delete this;
418 }
419
SendRtpPacket(const std::vector<uint8_t> & packet_copy)420 void AndroidVoipClient::SendRtpPacket(const std::vector<uint8_t>& packet_copy) {
421 RTC_DCHECK_RUN_ON(voip_thread_.get());
422
423 if (!rtp_socket_->SendTo(packet_copy.data(), packet_copy.size(),
424 rtp_remote_address_, rtc::PacketOptions())) {
425 RTC_LOG(LS_ERROR) << "Failed to send RTP packet";
426 }
427 }
428
SendRtp(const uint8_t * packet,size_t length,const webrtc::PacketOptions & options)429 bool AndroidVoipClient::SendRtp(const uint8_t* packet,
430 size_t length,
431 const webrtc::PacketOptions& options) {
432 std::vector<uint8_t> packet_copy(packet, packet + length);
433 voip_thread_->PostTask([this, packet_copy = std::move(packet_copy)] {
434 SendRtpPacket(packet_copy);
435 });
436 return true;
437 }
438
SendRtcpPacket(const std::vector<uint8_t> & packet_copy)439 void AndroidVoipClient::SendRtcpPacket(
440 const std::vector<uint8_t>& packet_copy) {
441 RTC_DCHECK_RUN_ON(voip_thread_.get());
442
443 if (!rtcp_socket_->SendTo(packet_copy.data(), packet_copy.size(),
444 rtcp_remote_address_, rtc::PacketOptions())) {
445 RTC_LOG(LS_ERROR) << "Failed to send RTCP packet";
446 }
447 }
448
SendRtcp(const uint8_t * packet,size_t length)449 bool AndroidVoipClient::SendRtcp(const uint8_t* packet, size_t length) {
450 std::vector<uint8_t> packet_copy(packet, packet + length);
451 voip_thread_->PostTask([this, packet_copy = std::move(packet_copy)] {
452 SendRtcpPacket(packet_copy);
453 });
454 return true;
455 }
456
ReadRTPPacket(const std::vector<uint8_t> & packet_copy)457 void AndroidVoipClient::ReadRTPPacket(const std::vector<uint8_t>& packet_copy) {
458 RTC_DCHECK_RUN_ON(voip_thread_.get());
459
460 if (!channel_) {
461 RTC_LOG(LS_ERROR) << "Channel has not been created";
462 return;
463 }
464 webrtc::VoipResult result = voip_engine_->Network().ReceivedRTPPacket(
465 *channel_,
466 rtc::ArrayView<const uint8_t>(packet_copy.data(), packet_copy.size()));
467 RTC_CHECK(result == webrtc::VoipResult::kOk);
468 }
469
OnSignalReadRTPPacket(rtc::AsyncPacketSocket * socket,const char * rtp_packet,size_t size,const rtc::SocketAddress & addr,const int64_t & timestamp)470 void AndroidVoipClient::OnSignalReadRTPPacket(rtc::AsyncPacketSocket* socket,
471 const char* rtp_packet,
472 size_t size,
473 const rtc::SocketAddress& addr,
474 const int64_t& timestamp) {
475 std::vector<uint8_t> packet_copy(rtp_packet, rtp_packet + size);
476 voip_thread_->PostTask([this, packet_copy = std::move(packet_copy)] {
477 ReadRTPPacket(packet_copy);
478 });
479 }
480
ReadRTCPPacket(const std::vector<uint8_t> & packet_copy)481 void AndroidVoipClient::ReadRTCPPacket(
482 const std::vector<uint8_t>& packet_copy) {
483 RTC_DCHECK_RUN_ON(voip_thread_.get());
484
485 if (!channel_) {
486 RTC_LOG(LS_ERROR) << "Channel has not been created";
487 return;
488 }
489 webrtc::VoipResult result = voip_engine_->Network().ReceivedRTCPPacket(
490 *channel_,
491 rtc::ArrayView<const uint8_t>(packet_copy.data(), packet_copy.size()));
492 RTC_CHECK(result == webrtc::VoipResult::kOk);
493 }
494
OnSignalReadRTCPPacket(rtc::AsyncPacketSocket * socket,const char * rtcp_packet,size_t size,const rtc::SocketAddress & addr,const int64_t & timestamp)495 void AndroidVoipClient::OnSignalReadRTCPPacket(rtc::AsyncPacketSocket* socket,
496 const char* rtcp_packet,
497 size_t size,
498 const rtc::SocketAddress& addr,
499 const int64_t& timestamp) {
500 std::vector<uint8_t> packet_copy(rtcp_packet, rtcp_packet + size);
501 voip_thread_->PostTask([this, packet_copy = std::move(packet_copy)] {
502 ReadRTCPPacket(packet_copy);
503 });
504 }
505
JNI_VoipClient_CreateClient(JNIEnv * env,const webrtc::JavaParamRef<jobject> & application_context,const webrtc::JavaParamRef<jobject> & j_voip_client)506 static jlong JNI_VoipClient_CreateClient(
507 JNIEnv* env,
508 const webrtc::JavaParamRef<jobject>& application_context,
509 const webrtc::JavaParamRef<jobject>& j_voip_client) {
510 return webrtc::NativeToJavaPointer(
511 AndroidVoipClient::Create(env, application_context, j_voip_client));
512 }
513
514 } // namespace webrtc_examples
515