tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

android_voip_client.cc (20178B)


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