• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
37 namespace {
38 
39 // Connects a UDP socket to a public address and returns the local
40 // address associated with it. Since it binds to the "any" address
41 // internally, it returns the default local address on a multi-homed
42 // endpoint. Implementation copied from
43 // BasicNetworkManager::QueryDefaultLocalAddress.
QueryDefaultLocalAddress(int family)44 rtc::IPAddress QueryDefaultLocalAddress(int family) {
45   const char kPublicIPv4Host[] = "8.8.8.8";
46   const char kPublicIPv6Host[] = "2001:4860:4860::8888";
47   const int kPublicPort = 53;
48   std::unique_ptr<rtc::Thread> thread = rtc::Thread::CreateWithSocketServer();
49 
50   RTC_DCHECK(thread->socketserver() != nullptr);
51   RTC_DCHECK(family == AF_INET || family == AF_INET6);
52 
53   std::unique_ptr<rtc::AsyncSocket> socket(
54       thread->socketserver()->CreateAsyncSocket(family, SOCK_DGRAM));
55   if (!socket) {
56     RTC_LOG_ERR(LERROR) << "Socket creation failed";
57     return rtc::IPAddress();
58   }
59 
60   auto host = family == AF_INET ? kPublicIPv4Host : kPublicIPv6Host;
61   if (socket->Connect(rtc::SocketAddress(host, kPublicPort)) < 0) {
62     if (socket->GetError() != ENETUNREACH &&
63         socket->GetError() != EHOSTUNREACH) {
64       RTC_LOG(LS_INFO) << "Connect failed with " << socket->GetError();
65     }
66     return rtc::IPAddress();
67   }
68   return socket->GetLocalAddress().ipaddr();
69 }
70 
71 // Assigned payload type for supported built-in codecs. PCMU, PCMA,
72 // and G722 have set payload types. Whereas opus, ISAC, and ILBC
73 // have dynamic payload types.
74 enum class PayloadType : int {
75   kPcmu = 0,
76   kPcma = 8,
77   kG722 = 9,
78   kOpus = 96,
79   kIsac = 97,
80   kIlbc = 98,
81 };
82 
83 // Returns the payload type corresponding to codec_name. Only
84 // supports the built-in codecs.
GetPayloadType(const std::string & codec_name)85 int GetPayloadType(const std::string& codec_name) {
86   RTC_DCHECK(codec_name == "PCMU" || codec_name == "PCMA" ||
87              codec_name == "G722" || codec_name == "opus" ||
88              codec_name == "ISAC" || codec_name == "ILBC");
89 
90   if (codec_name == "PCMU") {
91     return static_cast<int>(PayloadType::kPcmu);
92   } else if (codec_name == "PCMA") {
93     return static_cast<int>(PayloadType::kPcma);
94   } else if (codec_name == "G722") {
95     return static_cast<int>(PayloadType::kG722);
96   } else if (codec_name == "opus") {
97     return static_cast<int>(PayloadType::kOpus);
98   } else if (codec_name == "ISAC") {
99     return static_cast<int>(PayloadType::kIsac);
100   } else if (codec_name == "ILBC") {
101     return static_cast<int>(PayloadType::kIlbc);
102   }
103 
104   RTC_NOTREACHED();
105   return -1;
106 }
107 
108 }  // namespace
109 
110 namespace webrtc_examples {
111 
AndroidVoipClient(JNIEnv * env,const webrtc::JavaParamRef<jobject> & application_context)112 AndroidVoipClient::AndroidVoipClient(
113     JNIEnv* env,
114     const webrtc::JavaParamRef<jobject>& application_context) {
115   voip_thread_ = rtc::Thread::CreateWithSocketServer();
116   voip_thread_->Start();
117 
118   webrtc::VoipEngineConfig config;
119   config.encoder_factory = webrtc::CreateBuiltinAudioEncoderFactory();
120   config.decoder_factory = webrtc::CreateBuiltinAudioDecoderFactory();
121   config.task_queue_factory = webrtc::CreateDefaultTaskQueueFactory();
122   config.audio_device_module =
123       webrtc::CreateJavaAudioDeviceModule(env, application_context.obj());
124   config.audio_processing = webrtc::AudioProcessingBuilder().Create();
125 
126   supported_codecs_ = config.encoder_factory->GetSupportedEncoders();
127 
128   // Due to consistent thread requirement on
129   // modules/audio_device/android/audio_device_template.h,
130   // code is invoked in the context of voip_thread_.
131   voip_thread_->Invoke<void>(RTC_FROM_HERE, [&] {
132     voip_engine_ = webrtc::CreateVoipEngine(std::move(config));
133     if (!voip_engine_) {
134       RTC_LOG(LS_ERROR) << "VoipEngine creation failed";
135     }
136   });
137 }
138 
~AndroidVoipClient()139 AndroidVoipClient::~AndroidVoipClient() {
140   voip_thread_->Stop();
141 }
142 
Create(JNIEnv * env,const webrtc::JavaParamRef<jobject> & application_context)143 AndroidVoipClient* AndroidVoipClient::Create(
144     JNIEnv* env,
145     const webrtc::JavaParamRef<jobject>& application_context) {
146   // Using `new` to access a non-public constructor.
147   auto voip_client =
148       absl::WrapUnique(new AndroidVoipClient(env, application_context));
149   if (!voip_client->voip_engine_) {
150     return nullptr;
151   }
152   return voip_client.release();
153 }
154 
GetSupportedCodecs(JNIEnv * env)155 webrtc::ScopedJavaLocalRef<jobject> AndroidVoipClient::GetSupportedCodecs(
156     JNIEnv* env) {
157   std::vector<std::string> names;
158   for (const webrtc::AudioCodecSpec& spec : supported_codecs_) {
159     names.push_back(spec.format.name);
160   }
161   webrtc::ScopedJavaLocalRef<jstring> (*convert_function)(
162       JNIEnv*, const std::string&) = &webrtc::NativeToJavaString;
163   return NativeToJavaList(env, names, convert_function);
164 }
165 
GetLocalIPAddress(JNIEnv * env)166 webrtc::ScopedJavaLocalRef<jstring> AndroidVoipClient::GetLocalIPAddress(
167     JNIEnv* env) {
168   rtc::IPAddress ipv4_address = QueryDefaultLocalAddress(AF_INET);
169   if (!ipv4_address.IsNil()) {
170     return webrtc::NativeToJavaString(env, ipv4_address.ToString());
171   }
172   rtc::IPAddress ipv6_address = QueryDefaultLocalAddress(AF_INET6);
173   if (!ipv6_address.IsNil()) {
174     return webrtc::NativeToJavaString(env, ipv6_address.ToString());
175   }
176   return webrtc::NativeToJavaString(env, "");
177 }
178 
SetEncoder(JNIEnv * env,const webrtc::JavaRef<jstring> & j_encoder_string)179 void AndroidVoipClient::SetEncoder(
180     JNIEnv* env,
181     const webrtc::JavaRef<jstring>& j_encoder_string) {
182   if (!channel_) {
183     RTC_LOG(LS_ERROR) << "Channel has not been created";
184     return;
185   }
186   const std::string& chosen_encoder =
187       webrtc::JavaToNativeString(env, j_encoder_string);
188   for (const webrtc::AudioCodecSpec& encoder : supported_codecs_) {
189     if (encoder.format.name == chosen_encoder) {
190       voip_engine_->Codec().SetSendCodec(
191           *channel_, GetPayloadType(encoder.format.name), encoder.format);
192       break;
193     }
194   }
195 }
196 
SetDecoders(JNIEnv * env,const webrtc::JavaParamRef<jobject> & j_decoder_strings)197 void AndroidVoipClient::SetDecoders(
198     JNIEnv* env,
199     const webrtc::JavaParamRef<jobject>& j_decoder_strings) {
200   if (!channel_) {
201     RTC_LOG(LS_ERROR) << "Channel has not been created";
202     return;
203   }
204   std::vector<std::string> chosen_decoders =
205       webrtc::JavaListToNativeVector<std::string, jstring>(
206           env, j_decoder_strings, &webrtc::JavaToNativeString);
207   std::map<int, webrtc::SdpAudioFormat> decoder_specs;
208 
209   for (const webrtc::AudioCodecSpec& decoder : supported_codecs_) {
210     if (std::find(chosen_decoders.begin(), chosen_decoders.end(),
211                   decoder.format.name) != chosen_decoders.end()) {
212       decoder_specs.insert(
213           {GetPayloadType(decoder.format.name), decoder.format});
214     }
215   }
216 
217   voip_engine_->Codec().SetReceiveCodecs(*channel_, decoder_specs);
218 }
219 
SetLocalAddress(JNIEnv * env,const webrtc::JavaRef<jstring> & j_ip_address_string,jint j_port_number_int)220 void AndroidVoipClient::SetLocalAddress(
221     JNIEnv* env,
222     const webrtc::JavaRef<jstring>& j_ip_address_string,
223     jint j_port_number_int) {
224   const std::string& ip_address =
225       webrtc::JavaToNativeString(env, j_ip_address_string);
226   rtp_local_address_ = rtc::SocketAddress(ip_address, j_port_number_int);
227   rtcp_local_address_ = rtc::SocketAddress(ip_address, j_port_number_int + 1);
228 }
229 
SetRemoteAddress(JNIEnv * env,const webrtc::JavaRef<jstring> & j_ip_address_string,jint j_port_number_int)230 void AndroidVoipClient::SetRemoteAddress(
231     JNIEnv* env,
232     const webrtc::JavaRef<jstring>& j_ip_address_string,
233     jint j_port_number_int) {
234   const std::string& ip_address =
235       webrtc::JavaToNativeString(env, j_ip_address_string);
236   rtp_remote_address_ = rtc::SocketAddress(ip_address, j_port_number_int);
237   rtcp_remote_address_ = rtc::SocketAddress(ip_address, j_port_number_int + 1);
238 }
239 
StartSession(JNIEnv * env)240 jboolean AndroidVoipClient::StartSession(JNIEnv* env) {
241   // Due to consistent thread requirement on
242   // modules/utility/source/process_thread_impl.cc,
243   // code is invoked in the context of voip_thread_.
244   channel_ = voip_thread_->Invoke<absl::optional<webrtc::ChannelId>>(
245       RTC_FROM_HERE,
246       [this] { return voip_engine_->Base().CreateChannel(this, 0); });
247   if (!channel_) {
248     RTC_LOG(LS_ERROR) << "Channel creation failed";
249     return false;
250   }
251 
252   rtp_socket_.reset(rtc::AsyncUDPSocket::Create(voip_thread_->socketserver(),
253                                                 rtp_local_address_));
254   if (!rtp_socket_) {
255     RTC_LOG_ERR(LERROR) << "Socket creation failed";
256     return false;
257   }
258   rtp_socket_->SignalReadPacket.connect(
259       this, &AndroidVoipClient::OnSignalReadRTPPacket);
260 
261   rtcp_socket_.reset(rtc::AsyncUDPSocket::Create(voip_thread_->socketserver(),
262                                                  rtcp_local_address_));
263   if (!rtcp_socket_) {
264     RTC_LOG_ERR(LERROR) << "Socket creation failed";
265     return false;
266   }
267   rtcp_socket_->SignalReadPacket.connect(
268       this, &AndroidVoipClient::OnSignalReadRTCPPacket);
269 
270   return true;
271 }
272 
StopSession(JNIEnv * env)273 jboolean AndroidVoipClient::StopSession(JNIEnv* env) {
274   if (!channel_) {
275     RTC_LOG(LS_ERROR) << "Channel has not been created";
276     return false;
277   }
278   if (!StopSend(env) || !StopPlayout(env)) {
279     return false;
280   }
281 
282   rtp_socket_->Close();
283   rtcp_socket_->Close();
284   // Due to consistent thread requirement on
285   // modules/utility/source/process_thread_impl.cc,
286   // code is invoked in the context of voip_thread_.
287   voip_thread_->Invoke<void>(RTC_FROM_HERE, [this] {
288     voip_engine_->Base().ReleaseChannel(*channel_);
289   });
290   channel_ = absl::nullopt;
291   return true;
292 }
293 
StartSend(JNIEnv * env)294 jboolean AndroidVoipClient::StartSend(JNIEnv* env) {
295   if (!channel_) {
296     RTC_LOG(LS_ERROR) << "Channel has not been created";
297     return false;
298   }
299   // Due to consistent thread requirement on
300   // modules/audio_device/android/opensles_recorder.cc,
301   // code is invoked in the context of voip_thread_.
302   return voip_thread_->Invoke<bool>(RTC_FROM_HERE, [this] {
303     return voip_engine_->Base().StartSend(*channel_);
304   });
305 }
306 
StopSend(JNIEnv * env)307 jboolean AndroidVoipClient::StopSend(JNIEnv* env) {
308   if (!channel_) {
309     RTC_LOG(LS_ERROR) << "Channel has not been created";
310     return false;
311   }
312   // Due to consistent thread requirement on
313   // modules/audio_device/android/opensles_recorder.cc,
314   // code is invoked in the context of voip_thread_.
315   return voip_thread_->Invoke<bool>(RTC_FROM_HERE, [this] {
316     return voip_engine_->Base().StopSend(*channel_);
317   });
318 }
319 
StartPlayout(JNIEnv * env)320 jboolean AndroidVoipClient::StartPlayout(JNIEnv* env) {
321   if (!channel_) {
322     RTC_LOG(LS_ERROR) << "Channel has not been created";
323     return false;
324   }
325   // Due to consistent thread requirement on
326   // modules/audio_device/android/opensles_player.cc,
327   // code is invoked in the context of voip_thread_.
328   return voip_thread_->Invoke<bool>(RTC_FROM_HERE, [this] {
329     return voip_engine_->Base().StartPlayout(*channel_);
330   });
331 }
332 
StopPlayout(JNIEnv * env)333 jboolean AndroidVoipClient::StopPlayout(JNIEnv* env) {
334   if (!channel_) {
335     RTC_LOG(LS_ERROR) << "Channel has not been created";
336     return false;
337   }
338   // Due to consistent thread requirement on
339   // modules/audio_device/android/opensles_player.cc,
340   // code is invoked in the context of voip_thread_.
341   return voip_thread_->Invoke<bool>(RTC_FROM_HERE, [this] {
342     return voip_engine_->Base().StopPlayout(*channel_);
343   });
344 }
345 
Delete(JNIEnv * env)346 void AndroidVoipClient::Delete(JNIEnv* env) {
347   delete this;
348 }
349 
SendRtp(const uint8_t * packet,size_t length,const webrtc::PacketOptions & options)350 bool AndroidVoipClient::SendRtp(const uint8_t* packet,
351                                 size_t length,
352                                 const webrtc::PacketOptions& options) {
353   if (!rtp_socket_->SendTo(packet, length, rtp_remote_address_,
354                            rtc::PacketOptions())) {
355     RTC_LOG(LS_ERROR) << "Failed to send RTP packet";
356     return false;
357   }
358   return true;
359 }
360 
SendRtcp(const uint8_t * packet,size_t length)361 bool AndroidVoipClient::SendRtcp(const uint8_t* packet, size_t length) {
362   if (!rtcp_socket_->SendTo(packet, length, rtcp_remote_address_,
363                             rtc::PacketOptions())) {
364     RTC_LOG(LS_ERROR) << "Failed to send RTCP packet";
365     return false;
366   }
367   return true;
368 }
369 
OnSignalReadRTPPacket(rtc::AsyncPacketSocket * socket,const char * rtp_packet,size_t size,const rtc::SocketAddress & addr,const int64_t & timestamp)370 void AndroidVoipClient::OnSignalReadRTPPacket(rtc::AsyncPacketSocket* socket,
371                                               const char* rtp_packet,
372                                               size_t size,
373                                               const rtc::SocketAddress& addr,
374                                               const int64_t& timestamp) {
375   if (!channel_) {
376     RTC_LOG(LS_ERROR) << "Channel has not been created";
377     return;
378   }
379   voip_engine_->Network().ReceivedRTPPacket(
380       *channel_, rtc::ArrayView<const uint8_t>(
381                      reinterpret_cast<const uint8_t*>(rtp_packet), size));
382 }
383 
OnSignalReadRTCPPacket(rtc::AsyncPacketSocket * socket,const char * rtcp_packet,size_t size,const rtc::SocketAddress & addr,const int64_t & timestamp)384 void AndroidVoipClient::OnSignalReadRTCPPacket(rtc::AsyncPacketSocket* socket,
385                                                const char* rtcp_packet,
386                                                size_t size,
387                                                const rtc::SocketAddress& addr,
388                                                const int64_t& timestamp) {
389   if (!channel_) {
390     RTC_LOG(LS_ERROR) << "Channel has not been created";
391     return;
392   }
393   voip_engine_->Network().ReceivedRTCPPacket(
394       *channel_, rtc::ArrayView<const uint8_t>(
395                      reinterpret_cast<const uint8_t*>(rtcp_packet), size));
396 }
397 
JNI_VoipClient_CreateClient(JNIEnv * env,const webrtc::JavaParamRef<jobject> & application_context)398 static jlong JNI_VoipClient_CreateClient(
399     JNIEnv* env,
400     const webrtc::JavaParamRef<jobject>& application_context) {
401   return webrtc::NativeToJavaPointer(
402       AndroidVoipClient::Create(env, application_context));
403 }
404 
405 }  // namespace webrtc_examples
406