org_telegram_messenger_voip_Instance.cpp 52 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107
  1. #include "org_telegram_messenger_voip_Instance.h"
  2. #include <jni.h>
  3. #include <sdk/android/native_api/video/wrapper.h>
  4. #include <VideoCapturerInterface.h>
  5. #include <platform/android/AndroidInterface.h>
  6. #include <platform/android/AndroidContext.h>
  7. #include <rtc_base/ssl_adapter.h>
  8. #include <modules/utility/include/jvm_android.h>
  9. #include <sdk/android/native_api/base/init.h>
  10. #include <voip/webrtc/media/base/media_constants.h>
  11. #include <tgnet/FileLog.h>
  12. #include <voip/tgcalls/group/GroupInstanceCustomImpl.h>
  13. #include <memory>
  14. #include <utility>
  15. #include <map>
  16. #include "pc/video_track.h"
  17. #include "legacy/InstanceImplLegacy.h"
  18. #include "InstanceImpl.h"
  19. #include "libtgvoip/os/android/AudioOutputOpenSLES.h"
  20. #include "libtgvoip/os/android/AudioInputOpenSLES.h"
  21. #include "libtgvoip/os/android/JNIUtilities.h"
  22. #include "tgcalls/VideoCaptureInterface.h"
  23. #include "tgcalls/v2/InstanceV2Impl.h"
  24. #include "tgcalls/v2_4_0_0/InstanceV2_4_0_0Impl.h"
  25. #include "tgcalls/v2/InstanceV2ReferenceImpl.h"
  26. using namespace tgcalls;
  27. const auto RegisterTag = Register<InstanceImpl>();
  28. const auto RegisterTagLegacy = Register<InstanceImplLegacy>();
  29. const auto RegisterTagV2_4_0_0 = Register<InstanceV2_4_0_0Impl>();
  30. const auto RegisterTagV2_4_0_1 = Register<InstanceV2Impl>();
  31. const auto RegisterTagV2_4_1_2 = Register<InstanceV2ReferenceImpl>();
  32. jclass TrafficStatsClass;
  33. jclass FingerprintClass;
  34. jclass FinalStateClass;
  35. jclass NativeInstanceClass;
  36. jmethodID FinalStateInitMethod;
  37. class RequestMediaChannelDescriptionTaskJava : public RequestMediaChannelDescriptionTask {
  38. public:
  39. RequestMediaChannelDescriptionTaskJava(std::shared_ptr<PlatformContext> platformContext,
  40. std::function<void(std::vector<MediaChannelDescription> &&)> callback) :
  41. _platformContext(std::move(platformContext)),
  42. _callback(std::move(callback)) {
  43. }
  44. void call(JNIEnv *env, jintArray audioSsrcs) {
  45. std::vector<MediaChannelDescription> descriptions;
  46. jint *ssrcsArr = env->GetIntArrayElements(audioSsrcs, nullptr);
  47. jsize size = env->GetArrayLength(audioSsrcs);
  48. for (int i = 0; i < size; i++) {
  49. MediaChannelDescription description;
  50. description.type = MediaChannelDescription::Type::Audio;
  51. description.audioSsrc = ssrcsArr[i];
  52. descriptions.push_back(description);
  53. }
  54. env->ReleaseIntArrayElements(audioSsrcs, ssrcsArr, JNI_ABORT);
  55. _callback(std::move<>(descriptions));
  56. }
  57. private:
  58. void cancel() override {
  59. /*tgvoip::jni::DoWithJNI([&](JNIEnv *env) {
  60. jobject globalRef = ((AndroidContext *) _platformContext.get())->getJavaInstance();
  61. env->CallVoidMethod(globalRef, env->GetMethodID(NativeInstanceClass, "onCancelRequestMediaChannelDescription", "(J)V"), _timestamp);
  62. });*/
  63. }
  64. std::shared_ptr<PlatformContext> _platformContext;
  65. std::function<void(std::vector<MediaChannelDescription> &&)> _callback;
  66. };
  67. class BroadcastPartTaskJava : public BroadcastPartTask {
  68. public:
  69. BroadcastPartTaskJava(std::shared_ptr<PlatformContext> platformContext,
  70. std::function<void(BroadcastPart &&)> callback,
  71. int64_t timestamp, int32_t videoChannel, VideoChannelDescription::Quality quality) :
  72. _platformContext(std::move(platformContext)),
  73. _callback(std::move(callback)),
  74. _timestamp(timestamp),
  75. _videoChannel(videoChannel),
  76. _quality(quality) {
  77. }
  78. void call(int64_t ts, int64_t responseTs, BroadcastPart::Status status, uint8_t *data, int32_t len) {
  79. if (_timestamp != ts) {
  80. return;
  81. }
  82. BroadcastPart part;
  83. part.timestampMilliseconds = _timestamp;
  84. part.responseTimestamp = responseTs / 1000.0;
  85. part.status = status;
  86. if (data != nullptr) {
  87. part.data = std::vector<uint8_t>(data, data + len);
  88. }
  89. _callback(std::move<>(part));
  90. }
  91. bool isValidTaskFor(int64_t timestamp, int32_t videoChannel, VideoChannelDescription::Quality quality) {
  92. if (_videoChannel == 0) {
  93. return _timestamp == timestamp;
  94. } else {
  95. return _timestamp == timestamp && _videoChannel == videoChannel && _quality == quality;
  96. }
  97. }
  98. private:
  99. void cancel() override {
  100. tgvoip::jni::DoWithJNI([&](JNIEnv *env) {
  101. auto context = (AndroidContext *) _platformContext.get();
  102. jobject globalRef = context->getJavaInstance();
  103. env->CallVoidMethod(globalRef, env->GetMethodID(NativeInstanceClass, "onCancelRequestBroadcastPart", "(JII)V"), _timestamp, _videoChannel, (jint) _quality);
  104. if (_videoChannel != 0) {
  105. for (auto videoTaskIter = context->videoStreamTasks.begin(); videoTaskIter != context->videoStreamTasks.end(); videoTaskIter++) {
  106. if (((BroadcastPartTaskJava *) videoTaskIter->get())->isValidTaskFor(_timestamp, _videoChannel, _quality)) {
  107. context->videoStreamTasks.erase(videoTaskIter);
  108. break;
  109. }
  110. }
  111. } else {
  112. for (auto audioTaskIter = context->audioStreamTasks.begin(); audioTaskIter != context->audioStreamTasks.end(); audioTaskIter++) {
  113. if (((BroadcastPartTaskJava *) audioTaskIter->get())->isValidTaskFor(_timestamp, _videoChannel, _quality)) {
  114. context->audioStreamTasks.erase(audioTaskIter);
  115. break;
  116. }
  117. }
  118. }
  119. });
  120. }
  121. std::shared_ptr<PlatformContext> _platformContext;
  122. std::function<void(BroadcastPart &&)> _callback;
  123. int64_t _timestamp;
  124. int32_t _videoChannel;
  125. VideoChannelDescription::Quality _quality;
  126. };
  127. class RequestCurrentTimeTaskJava : public BroadcastPartTask {
  128. public:
  129. RequestCurrentTimeTaskJava(std::function<void(int64_t)> callback) :
  130. _callback(std::move(callback)) {
  131. }
  132. std::function<void(int64_t)> _callback;
  133. private:
  134. void cancel() override {
  135. }
  136. };
  137. class JavaObject {
  138. private:
  139. JNIEnv *env;
  140. jobject obj;
  141. jclass clazz;
  142. public:
  143. JavaObject(JNIEnv *env, jobject obj) : JavaObject(env, obj, env->GetObjectClass(obj)) {
  144. }
  145. JavaObject(JNIEnv *env, jobject obj, jclass clazz) {
  146. this->env = env;
  147. this->obj = obj;
  148. this->clazz = clazz;
  149. }
  150. jint getIntField(const char *name) {
  151. return env->GetIntField(obj, env->GetFieldID(clazz, name, "I"));
  152. }
  153. jlong getLongField(const char *name) {
  154. return env->GetLongField(obj, env->GetFieldID(clazz, name, "J"));
  155. }
  156. jboolean getBooleanField(const char *name) {
  157. return env->GetBooleanField(obj, env->GetFieldID(clazz, name, "Z"));
  158. }
  159. jdouble getDoubleField(const char *name) {
  160. return env->GetDoubleField(obj, env->GetFieldID(clazz, name, "D"));
  161. }
  162. jbyteArray getByteArrayField(const char *name) {
  163. return (jbyteArray) env->GetObjectField(obj, env->GetFieldID(clazz, name, "[B"));
  164. }
  165. jintArray getIntArrayField(const char *name) {
  166. return (jintArray) env->GetObjectField(obj, env->GetFieldID(clazz, name, "[I"));
  167. }
  168. jstring getStringField(const char *name) {
  169. return (jstring) env->GetObjectField(obj, env->GetFieldID(clazz, name, "Ljava/lang/String;"));
  170. }
  171. jobjectArray getObjectArrayField(const char *name) {
  172. return (jobjectArray) env->GetObjectField(obj, env->GetFieldID(clazz, name, "[Ljava/lang/Object;"));
  173. }
  174. };
  175. struct SetVideoSink {
  176. std::shared_ptr<rtc::VideoSinkInterface<webrtc::VideoFrame>> sink;
  177. VideoChannelDescription::Quality quality;
  178. std::string endpointId;
  179. std::vector<MediaSsrcGroup> ssrcGroups;
  180. };
  181. struct InstanceHolder {
  182. std::unique_ptr<Instance> nativeInstance;
  183. std::unique_ptr<GroupInstanceCustomImpl> groupNativeInstance;
  184. std::shared_ptr<tgcalls::VideoCaptureInterface> _videoCapture;
  185. std::shared_ptr<tgcalls::VideoCaptureInterface> _screenVideoCapture;
  186. std::shared_ptr<rtc::VideoSinkInterface<webrtc::VideoFrame>> _sink;
  187. std::shared_ptr<PlatformContext> _platformContext;
  188. std::map<std::string, SetVideoSink> remoteGroupSinks;
  189. bool useScreencast = false;
  190. };
  191. jlong getInstanceHolderId(JNIEnv *env, jobject obj) {
  192. return env->GetLongField(obj, env->GetFieldID(NativeInstanceClass, "nativePtr", "J"));
  193. }
  194. InstanceHolder *getInstanceHolder(JNIEnv *env, jobject obj) {
  195. return reinterpret_cast<InstanceHolder *>(getInstanceHolderId(env, obj));
  196. }
  197. jint throwNewJavaException(JNIEnv *env, const char *className, const char *message) {
  198. return env->ThrowNew(env->FindClass(className), message);
  199. }
  200. jint throwNewJavaIllegalArgumentException(JNIEnv *env, const char *message) {
  201. return throwNewJavaException(env, "java/lang/IllegalStateException", message);
  202. }
  203. jbyteArray copyVectorToJavaByteArray(JNIEnv *env, const std::vector<uint8_t> &bytes) {
  204. unsigned int size = bytes.size();
  205. jbyteArray bytesArray = env->NewByteArray(size);
  206. env->SetByteArrayRegion(bytesArray, 0, size, (jbyte *) bytes.data());
  207. return bytesArray;
  208. }
  209. void readPersistentState(const char *filePath, PersistentState &persistentState) {
  210. FILE *persistentStateFile = fopen(filePath, "r");
  211. if (persistentStateFile) {
  212. fseek(persistentStateFile, 0, SEEK_END);
  213. auto len = static_cast<size_t>(ftell(persistentStateFile));
  214. fseek(persistentStateFile, 0, SEEK_SET);
  215. if (len < 1024 * 512 && len > 0) {
  216. auto *buffer = static_cast<uint8_t *>(malloc(len));
  217. fread(buffer, 1, len, persistentStateFile);
  218. persistentState.value = std::vector<uint8_t>(buffer, buffer + len);
  219. free(buffer);
  220. }
  221. fclose(persistentStateFile);
  222. }
  223. }
  224. void savePersistentState(const char *filePath, const PersistentState &persistentState) {
  225. FILE *persistentStateFile = fopen(filePath, "w");
  226. if (persistentStateFile) {
  227. fwrite(persistentState.value.data(), 1, persistentState.value.size(), persistentStateFile);
  228. fclose(persistentStateFile);
  229. }
  230. }
  231. NetworkType parseNetworkType(jint networkType) {
  232. switch (networkType) {
  233. case org_telegram_messenger_voip_Instance_NET_TYPE_GPRS:
  234. return NetworkType::Gprs;
  235. case org_telegram_messenger_voip_Instance_NET_TYPE_EDGE:
  236. return NetworkType::Edge;
  237. case org_telegram_messenger_voip_Instance_NET_TYPE_3G:
  238. return NetworkType::ThirdGeneration;
  239. case org_telegram_messenger_voip_Instance_NET_TYPE_HSPA:
  240. return NetworkType::Hspa;
  241. case org_telegram_messenger_voip_Instance_NET_TYPE_LTE:
  242. return NetworkType::Lte;
  243. case org_telegram_messenger_voip_Instance_NET_TYPE_WIFI:
  244. return NetworkType::WiFi;
  245. case org_telegram_messenger_voip_Instance_NET_TYPE_ETHERNET:
  246. return NetworkType::Ethernet;
  247. case org_telegram_messenger_voip_Instance_NET_TYPE_OTHER_HIGH_SPEED:
  248. return NetworkType::OtherHighSpeed;
  249. case org_telegram_messenger_voip_Instance_NET_TYPE_OTHER_LOW_SPEED:
  250. return NetworkType::OtherLowSpeed;
  251. case org_telegram_messenger_voip_Instance_NET_TYPE_DIALUP:
  252. return NetworkType::Dialup;
  253. case org_telegram_messenger_voip_Instance_NET_TYPE_OTHER_MOBILE:
  254. return NetworkType::OtherMobile;
  255. default:
  256. return NetworkType::Unknown;
  257. }
  258. }
  259. DataSaving parseDataSaving(JNIEnv *env, jint dataSaving) {
  260. switch (dataSaving) {
  261. case org_telegram_messenger_voip_Instance_DATA_SAVING_NEVER:
  262. return DataSaving::Never;
  263. case org_telegram_messenger_voip_Instance_DATA_SAVING_MOBILE:
  264. return DataSaving::Mobile;
  265. case org_telegram_messenger_voip_Instance_DATA_SAVING_ALWAYS:
  266. return DataSaving::Always;
  267. case org_telegram_messenger_voip_Instance_DATA_SAVING_ROAMING:
  268. throwNewJavaIllegalArgumentException(env, "DATA_SAVING_ROAMING is not supported");
  269. return DataSaving::Never;
  270. default:
  271. throwNewJavaIllegalArgumentException(env, "Unknown data saving constant: " + dataSaving);
  272. return DataSaving::Never;
  273. }
  274. }
  275. EndpointType parseEndpointType(JNIEnv *env, jint endpointType) {
  276. switch (endpointType) {
  277. case org_telegram_messenger_voip_Instance_ENDPOINT_TYPE_INET:
  278. return EndpointType::Inet;
  279. case org_telegram_messenger_voip_Instance_ENDPOINT_TYPE_LAN:
  280. return EndpointType::Lan;
  281. case org_telegram_messenger_voip_Instance_ENDPOINT_TYPE_TCP_RELAY:
  282. return EndpointType::TcpRelay;
  283. case org_telegram_messenger_voip_Instance_ENDPOINT_TYPE_UDP_RELAY:
  284. return EndpointType::UdpRelay;
  285. default:
  286. throwNewJavaIllegalArgumentException(env, std::string("Unknown endpoint type: ").append(std::to_string(endpointType)).c_str());
  287. return EndpointType::UdpRelay;
  288. }
  289. }
  290. jint asJavaState(const State &state) {
  291. switch (state) {
  292. case State::WaitInit:
  293. return org_telegram_messenger_voip_Instance_STATE_WAIT_INIT;
  294. case State::WaitInitAck:
  295. return org_telegram_messenger_voip_Instance_STATE_WAIT_INIT_ACK;
  296. case State::Established:
  297. return org_telegram_messenger_voip_Instance_STATE_ESTABLISHED;
  298. case State::Failed:
  299. return org_telegram_messenger_voip_Instance_STATE_FAILED;
  300. case State::Reconnecting:
  301. return org_telegram_messenger_voip_Instance_STATE_RECONNECTING;
  302. }
  303. }
  304. jobject asJavaTrafficStats(JNIEnv *env, const TrafficStats &trafficStats) {
  305. jmethodID initMethodId = env->GetMethodID(TrafficStatsClass, "<init>", "(JJJJ)V");
  306. return env->NewObject(TrafficStatsClass, initMethodId, (jlong) trafficStats.bytesSentWifi, (jlong) trafficStats.bytesReceivedWifi, (jlong) trafficStats.bytesSentMobile, (jlong) trafficStats.bytesReceivedMobile);
  307. }
  308. jobject asJavaFinalState(JNIEnv *env, const FinalState &finalState) {
  309. jbyteArray persistentState = copyVectorToJavaByteArray(env, finalState.persistentState.value);
  310. jstring debugLog = env->NewStringUTF(finalState.debugLog.c_str());
  311. jobject trafficStats = asJavaTrafficStats(env, finalState.trafficStats);
  312. auto isRatingSuggested = static_cast<jboolean>(finalState.isRatingSuggested);
  313. return env->NewObject(FinalStateClass, FinalStateInitMethod, persistentState, debugLog, trafficStats, isRatingSuggested);
  314. }
  315. jobject asJavaFingerprint(JNIEnv *env, const std::string& hash, const std::string& setup, const std::string& fingerprint) {
  316. jstring hashStr = env->NewStringUTF(hash.c_str());
  317. jstring setupStr = env->NewStringUTF(setup.c_str());
  318. jstring fingerprintStr = env->NewStringUTF(fingerprint.c_str());
  319. jmethodID initMethodId = env->GetMethodID(FingerprintClass, "<init>", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
  320. return env->NewObject(FingerprintClass, initMethodId, hashStr, setupStr, fingerprintStr);
  321. }
  322. extern "C" {
  323. bool webrtcLoaded = false;
  324. void initWebRTC(JNIEnv *env) {
  325. if (webrtcLoaded) {
  326. return;
  327. }
  328. JavaVM* vm;
  329. env->GetJavaVM(&vm);
  330. webrtc::InitAndroid(vm);
  331. webrtc::JVM::Initialize(vm);
  332. rtc::InitializeSSL();
  333. webrtcLoaded = true;
  334. NativeInstanceClass = static_cast<jclass>(env->NewGlobalRef(env->FindClass("org/telegram/messenger/voip/NativeInstance")));
  335. TrafficStatsClass = static_cast<jclass>(env->NewGlobalRef(env->FindClass("org/telegram/messenger/voip/Instance$TrafficStats")));
  336. FingerprintClass = static_cast<jclass>(env->NewGlobalRef(env->FindClass("org/telegram/messenger/voip/Instance$Fingerprint")));
  337. FinalStateClass = static_cast<jclass>(env->NewGlobalRef(env->FindClass("org/telegram/messenger/voip/Instance$FinalState")));
  338. FinalStateInitMethod = env->GetMethodID(FinalStateClass, "<init>", "([BLjava/lang/String;Lorg/telegram/messenger/voip/Instance$TrafficStats;Z)V");
  339. }
  340. extern "C"
  341. JNIEXPORT jlong JNICALL Java_org_telegram_messenger_voip_NativeInstance_makeGroupNativeInstance(JNIEnv *env, jclass clazz, jobject instanceObj, jstring logFilePath, jboolean highQuality, jlong videoCapturer, jboolean screencast, jboolean noiseSupression) {
  342. initWebRTC(env);
  343. std::shared_ptr<VideoCaptureInterface> videoCapture = videoCapturer ? std::shared_ptr<VideoCaptureInterface>(reinterpret_cast<VideoCaptureInterface *>(videoCapturer)) : nullptr;
  344. std::shared_ptr<PlatformContext> platformContext;
  345. if (videoCapture) {
  346. platformContext = videoCapture->getPlatformContext();
  347. ((AndroidContext *) platformContext.get())->setJavaInstance(env, instanceObj);
  348. } else {
  349. platformContext = std::make_shared<AndroidContext>(env, instanceObj, screencast);
  350. }
  351. GroupInstanceDescriptor descriptor = {
  352. .threads = StaticThreads::getThreads(),
  353. .config = {
  354. .need_log = true,
  355. .logPath = {tgvoip::jni::JavaStringToStdString(env, logFilePath)},
  356. },
  357. .networkStateUpdated = [platformContext](GroupNetworkState state) {
  358. tgvoip::jni::DoWithJNI([platformContext, state](JNIEnv *env) {
  359. jobject globalRef = ((AndroidContext *) platformContext.get())->getJavaInstance();
  360. env->CallVoidMethod(globalRef, env->GetMethodID(NativeInstanceClass, "onNetworkStateUpdated", "(ZZ)V"), state.isConnected, state.isTransitioningFromBroadcastToRtc);
  361. });
  362. },
  363. .audioLevelsUpdated = [platformContext](GroupLevelsUpdate const &update) {
  364. tgvoip::jni::DoWithJNI([platformContext, update](JNIEnv *env) {
  365. unsigned int size = update.updates.size();
  366. jintArray intArray = env->NewIntArray(size);
  367. jfloatArray floatArray = env->NewFloatArray(size);
  368. jbooleanArray boolArray = env->NewBooleanArray(size);
  369. jint intFill[size];
  370. jfloat floatFill[size];
  371. jboolean boolFill[size];
  372. for (int a = 0; a < size; a++) {
  373. intFill[a] = update.updates[a].ssrc;
  374. floatFill[a] = update.updates[a].value.isMuted ? 0 : update.updates[a].value.level;
  375. boolFill[a] = !update.updates[a].value.isMuted && update.updates[a].value.voice;
  376. }
  377. env->SetIntArrayRegion(intArray, 0, size, intFill);
  378. env->SetFloatArrayRegion(floatArray, 0, size, floatFill);
  379. env->SetBooleanArrayRegion(boolArray, 0, size, boolFill);
  380. jobject globalRef = ((AndroidContext *) platformContext.get())->getJavaInstance();
  381. env->CallVoidMethod(globalRef, env->GetMethodID(NativeInstanceClass, "onAudioLevelsUpdated", "([I[F[Z)V"), intArray, floatArray, boolArray);
  382. env->DeleteLocalRef(intArray);
  383. env->DeleteLocalRef(floatArray);
  384. env->DeleteLocalRef(boolArray);
  385. });
  386. },
  387. .videoCapture = videoCapture,
  388. .videoContentType = screencast ? VideoContentType::Screencast : VideoContentType::Generic,
  389. .initialEnableNoiseSuppression = (bool) noiseSupression,
  390. .platformContext = platformContext
  391. };
  392. if (!screencast) {
  393. descriptor.requestAudioBroadcastPart = [](std::shared_ptr<PlatformContext> platformContext, int64_t timestamp, int64_t duration, std::function<void(BroadcastPart &&)> callback) -> std::shared_ptr<BroadcastPartTask> {
  394. std::shared_ptr<BroadcastPartTask> task = std::make_shared<BroadcastPartTaskJava>(platformContext, callback, timestamp, 0, VideoChannelDescription::Quality::Full);
  395. ((AndroidContext *) platformContext.get())->audioStreamTasks.push_back(task);
  396. tgvoip::jni::DoWithJNI([platformContext, timestamp, duration, task](JNIEnv *env) {
  397. jobject globalRef = ((AndroidContext *) platformContext.get())->getJavaInstance();
  398. env->CallVoidMethod(globalRef, env->GetMethodID(NativeInstanceClass, "onRequestBroadcastPart", "(JJII)V"), timestamp, duration, 0, 0);
  399. });
  400. return task;
  401. };
  402. descriptor.requestVideoBroadcastPart = [](std::shared_ptr<PlatformContext> platformContext, int64_t timestamp, int64_t duration, int32_t video_channel, VideoChannelDescription::Quality quality, std::function<void(BroadcastPart &&)> callback) -> std::shared_ptr<BroadcastPartTask> {
  403. std::shared_ptr<BroadcastPartTask> task = std::make_shared<BroadcastPartTaskJava>(platformContext, callback, timestamp, video_channel, quality);
  404. ((AndroidContext *) platformContext.get())->videoStreamTasks.push_back(task);
  405. tgvoip::jni::DoWithJNI([platformContext, timestamp, duration, task, video_channel, quality](JNIEnv *env) {
  406. jobject globalRef = ((AndroidContext *) platformContext.get())->getJavaInstance();
  407. env->CallVoidMethod(globalRef, env->GetMethodID(NativeInstanceClass, "onRequestBroadcastPart", "(JJII)V"), timestamp, duration, video_channel, (jint) quality);
  408. });
  409. return task;
  410. };
  411. descriptor.requestMediaChannelDescriptions = [platformContext](std::vector<uint32_t> const &ssrcs, std::function<void(std::vector<MediaChannelDescription> &&)> callback) -> std::shared_ptr<RequestMediaChannelDescriptionTask> {
  412. std::shared_ptr<RequestMediaChannelDescriptionTaskJava> task = std::make_shared<RequestMediaChannelDescriptionTaskJava>(platformContext, callback);
  413. ((AndroidContext *) platformContext.get())->descriptionTasks.push_back(task);
  414. tgvoip::jni::DoWithJNI([platformContext, ssrcs, task](JNIEnv *env) {
  415. unsigned int size = ssrcs.size();
  416. jintArray intArray = env->NewIntArray(size);
  417. jint intFill[size];
  418. for (int a = 0; a < size; a++) {
  419. intFill[a] = ssrcs[a];
  420. }
  421. env->SetIntArrayRegion(intArray, 0, size, intFill);
  422. jobject globalRef = ((AndroidContext *) platformContext.get())->getJavaInstance();
  423. env->CallVoidMethod(globalRef, env->GetMethodID(NativeInstanceClass, "onParticipantDescriptionsRequired", "(J[I)V"), (jlong) task.get(), intArray);
  424. env->DeleteLocalRef(intArray);
  425. });
  426. return task;
  427. };
  428. descriptor.requestCurrentTime = [platformContext](std::function<void(int64_t)> callback) -> std::shared_ptr<BroadcastPartTask> {
  429. std::shared_ptr<RequestCurrentTimeTaskJava> task = std::make_shared<RequestCurrentTimeTaskJava>(callback);
  430. tgvoip::jni::DoWithJNI([platformContext, task](JNIEnv *env) {
  431. jobject globalRef = ((AndroidContext *) platformContext.get())->getJavaInstance();
  432. env->CallVoidMethod(globalRef, env->GetMethodID(NativeInstanceClass, "requestCurrentTime", "(J)V"), (jlong) task.get());
  433. });
  434. return task;
  435. };
  436. }
  437. auto *holder = new InstanceHolder;
  438. holder->groupNativeInstance = std::make_unique<GroupInstanceCustomImpl>(std::move(descriptor));
  439. holder->_platformContext = platformContext;
  440. holder->_videoCapture = videoCapture;
  441. return reinterpret_cast<jlong>(holder);
  442. }
  443. extern "C"
  444. JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_setJoinResponsePayload(JNIEnv *env, jobject obj, jstring payload) {
  445. InstanceHolder *instance = getInstanceHolder(env, obj);
  446. if (instance->groupNativeInstance == nullptr) {
  447. return;
  448. }
  449. instance->groupNativeInstance->setConnectionMode(GroupConnectionMode::GroupConnectionModeRtc, true, true);
  450. instance->groupNativeInstance->setJoinResponsePayload(tgvoip::jni::JavaStringToStdString(env, payload));
  451. }
  452. extern "C"
  453. JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_prepareForStream(JNIEnv *env, jobject obj, jboolean isRtmpStream) {
  454. InstanceHolder *instance = getInstanceHolder(env, obj);
  455. if (instance->groupNativeInstance == nullptr) {
  456. return;
  457. }
  458. instance->groupNativeInstance->setConnectionMode(GroupConnectionMode::GroupConnectionModeBroadcast, true,
  459. isRtmpStream);
  460. }
  461. void onEmitJoinPayload(const std::shared_ptr<PlatformContext>& platformContext, const GroupJoinPayload& payload) {
  462. JNIEnv *env = webrtc::AttachCurrentThreadIfNeeded();
  463. jobject globalRef = ((AndroidContext *) platformContext.get())->getJavaInstance();
  464. env->CallVoidMethod(globalRef, env->GetMethodID(NativeInstanceClass, "onEmitJoinPayload", "(Ljava/lang/String;I)V"), env->NewStringUTF(payload.json.c_str()), (jint) payload.audioSsrc);
  465. }
  466. extern "C"
  467. JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_resetGroupInstance(JNIEnv *env, jobject obj, jboolean set, jboolean disconnect) {
  468. InstanceHolder *instance = getInstanceHolder(env, obj);
  469. if (instance->groupNativeInstance == nullptr) {
  470. return;
  471. }
  472. if (set) {
  473. instance->groupNativeInstance->setConnectionMode(GroupConnectionMode::GroupConnectionModeNone, !disconnect, true);
  474. }
  475. std::shared_ptr<PlatformContext> platformContext = instance->_platformContext;
  476. instance->groupNativeInstance->emitJoinPayload([platformContext](const GroupJoinPayload& payload) {
  477. onEmitJoinPayload(platformContext, payload);
  478. });
  479. }
  480. void broadcastRequestedSinks(InstanceHolder *instance) {
  481. std::vector<VideoChannelDescription> descriptions;
  482. for (auto & remoteGroupSink : instance->remoteGroupSinks) {
  483. VideoChannelDescription description;
  484. description.endpointId = remoteGroupSink.second.endpointId;
  485. description.ssrcGroups = remoteGroupSink.second.ssrcGroups;
  486. description.maxQuality = remoteGroupSink.second.quality;
  487. descriptions.push_back(std::move(description));
  488. }
  489. instance->groupNativeInstance->setRequestedVideoChannels(std::move(descriptions));
  490. }
  491. extern "C"
  492. JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_setNoiseSuppressionEnabled(JNIEnv *env, jobject obj, jboolean enabled) {
  493. InstanceHolder *instance = getInstanceHolder(env, obj);
  494. if (instance->groupNativeInstance == nullptr) {
  495. return;
  496. }
  497. instance->groupNativeInstance->setIsNoiseSuppressionEnabled(enabled);
  498. }
  499. extern "C"
  500. JNIEXPORT jlong JNICALL Java_org_telegram_messenger_voip_NativeInstance_addIncomingVideoOutput(JNIEnv *env, jobject obj, jint quality, jstring endpointId, jobjectArray ssrcGroups, jobject remoteSink) {
  501. InstanceHolder *instance = getInstanceHolder(env, obj);
  502. if (instance->groupNativeInstance == nullptr) {
  503. return 0;
  504. }
  505. SetVideoSink sink;
  506. std::string endpointIdStr = tgvoip::jni::JavaStringToStdString(env, endpointId);
  507. std::shared_ptr<rtc::VideoSinkInterface<webrtc::VideoFrame>> ptr = webrtc::JavaToNativeVideoSink(env, remoteSink);
  508. sink.sink = ptr;
  509. sink.endpointId = endpointIdStr;
  510. if (ssrcGroups) {
  511. for (int i = 0, size = env->GetArrayLength(ssrcGroups); i < size; i++) {
  512. JavaObject javaObject(env, env->GetObjectArrayElement(ssrcGroups, i));
  513. MediaSsrcGroup ssrcGroup;
  514. ssrcGroup.semantics = tgvoip::jni::JavaStringToStdString(env, javaObject.getStringField("semantics"));
  515. jintArray ssrcsArray = javaObject.getIntArrayField("ssrcs");
  516. jint *elements = env->GetIntArrayElements(ssrcsArray, nullptr);
  517. for (int j = 0, size2 = env->GetArrayLength(ssrcsArray); j < size2; j++) {
  518. ssrcGroup.ssrcs.push_back(elements[j]);
  519. }
  520. env->ReleaseIntArrayElements(ssrcsArray, elements, JNI_ABORT);
  521. sink.ssrcGroups.push_back(std::move(ssrcGroup));
  522. }
  523. }
  524. sink.quality = (VideoChannelDescription::Quality) quality;
  525. instance->remoteGroupSinks[endpointIdStr] = std::move(sink);
  526. broadcastRequestedSinks(instance);
  527. instance->groupNativeInstance->addIncomingVideoOutput(endpointIdStr, ptr);
  528. return reinterpret_cast<intptr_t>(ptr.get());
  529. }
  530. extern "C"
  531. JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_removeIncomingVideoOutput(JNIEnv *env, jobject obj, jlong nativeRemoteSink) {
  532. InstanceHolder *instance = getInstanceHolder(env, obj);
  533. if (instance->groupNativeInstance == nullptr) {
  534. return;
  535. }
  536. if (nativeRemoteSink == 0) {
  537. instance->remoteGroupSinks.clear();
  538. } else {
  539. for (auto iter = instance->remoteGroupSinks.begin(); iter != instance->remoteGroupSinks.end(); iter++) {
  540. if (reinterpret_cast<intptr_t>(iter->second.sink.get()) == nativeRemoteSink) {
  541. instance->remoteGroupSinks.erase(iter);
  542. break;
  543. }
  544. }
  545. }
  546. broadcastRequestedSinks(instance);
  547. }
  548. extern "C"
  549. JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_setVideoEndpointQuality(JNIEnv *env, jobject obj, jstring endpointId, jint quality) {
  550. InstanceHolder *instance = getInstanceHolder(env, obj);
  551. if (instance->groupNativeInstance == nullptr) {
  552. return;
  553. }
  554. broadcastRequestedSinks(instance);
  555. auto sink = instance->remoteGroupSinks.find(tgvoip::jni::JavaStringToStdString(env, endpointId));
  556. if (sink == instance->remoteGroupSinks.end()) {
  557. return;
  558. }
  559. sink->second.quality = (VideoChannelDescription::Quality) quality;
  560. broadcastRequestedSinks(instance);
  561. }
  562. extern "C"
  563. JNIEXPORT jlong JNICALL Java_org_telegram_messenger_voip_NativeInstance_makeNativeInstance(JNIEnv *env, jclass clazz, jstring version, jobject instanceObj, jobject config, jstring persistentStateFilePath, jobjectArray endpoints, jobject proxyClass, jint networkType, jobject encryptionKey, jobject remoteSink, jlong videoCapturer, jfloat aspectRatio) {
  564. initWebRTC(env);
  565. JavaObject configObject(env, config);
  566. JavaObject encryptionKeyObject(env, encryptionKey);
  567. std::string v = tgvoip::jni::JavaStringToStdString(env, version);
  568. jbyteArray valueByteArray = encryptionKeyObject.getByteArrayField("value");
  569. auto *valueBytes = (uint8_t *) env->GetByteArrayElements(valueByteArray, nullptr);
  570. auto encryptionKeyValue = std::make_shared<std::array<uint8_t, 256>>();
  571. memcpy(encryptionKeyValue->data(), valueBytes, 256);
  572. env->ReleaseByteArrayElements(valueByteArray, (jbyte *) valueBytes, JNI_ABORT);
  573. std::shared_ptr<VideoCaptureInterface> videoCapture = videoCapturer ? std::shared_ptr<VideoCaptureInterface>(reinterpret_cast<VideoCaptureInterface *>(videoCapturer)) : nullptr;
  574. std::shared_ptr<PlatformContext> platformContext;
  575. if (videoCapture) {
  576. platformContext = videoCapture->getPlatformContext();
  577. ((AndroidContext *) platformContext.get())->setJavaInstance(env, instanceObj);
  578. } else {
  579. platformContext = std::make_shared<AndroidContext>(env, instanceObj, false);
  580. }
  581. Descriptor descriptor = {
  582. .config = Config{
  583. .initializationTimeout = configObject.getDoubleField("initializationTimeout"),
  584. .receiveTimeout = configObject.getDoubleField("receiveTimeout"),
  585. .dataSaving = parseDataSaving(env, configObject.getIntField("dataSaving")),
  586. .enableP2P = configObject.getBooleanField("enableP2p") == JNI_TRUE,
  587. .enableStunMarking = configObject.getBooleanField("enableSm") == JNI_TRUE,
  588. .enableAEC = configObject.getBooleanField("enableAec") == JNI_TRUE,
  589. .enableNS = configObject.getBooleanField("enableNs") == JNI_TRUE,
  590. .enableAGC = configObject.getBooleanField("enableAgc") == JNI_TRUE,
  591. .enableVolumeControl = true,
  592. .logPath = {tgvoip::jni::JavaStringToStdString(env, configObject.getStringField("logPath"))},
  593. .statsLogPath = {tgvoip::jni::JavaStringToStdString(env, configObject.getStringField("statsLogPath"))},
  594. .maxApiLayer = configObject.getIntField("maxApiLayer"),
  595. .enableHighBitrateVideo = true,
  596. .preferredVideoCodecs = {cricket::kVp9CodecName}
  597. },
  598. .encryptionKey = EncryptionKey(
  599. std::move(encryptionKeyValue),
  600. encryptionKeyObject.getBooleanField("isOutgoing") == JNI_TRUE),
  601. .videoCapture = videoCapture,
  602. .stateUpdated = [platformContext](State state) {
  603. jint javaState = asJavaState(state);
  604. jobject globalRef = ((AndroidContext *) platformContext.get())->getJavaInstance();
  605. tgvoip::jni::DoWithJNI([globalRef, javaState](JNIEnv *env) {
  606. env->CallVoidMethod(globalRef, env->GetMethodID(NativeInstanceClass, "onStateUpdated", "(I)V"), javaState);
  607. });
  608. },
  609. .signalBarsUpdated = [platformContext](int count) {
  610. jobject globalRef = ((AndroidContext *) platformContext.get())->getJavaInstance();
  611. tgvoip::jni::DoWithJNI([globalRef, count](JNIEnv *env) {
  612. env->CallVoidMethod(globalRef, env->GetMethodID(NativeInstanceClass, "onSignalBarsUpdated", "(I)V"), count);
  613. });
  614. },
  615. .audioLevelUpdated = [platformContext](float level) {
  616. tgvoip::jni::DoWithJNI([platformContext, level](JNIEnv *env) {
  617. jintArray intArray = nullptr;
  618. jfloatArray floatArray = env->NewFloatArray(1);
  619. jbooleanArray boolArray = nullptr;
  620. jfloat floatFill[1];
  621. floatFill[0] = level;
  622. env->SetFloatArrayRegion(floatArray, 0, 1, floatFill);
  623. jobject globalRef = ((AndroidContext *) platformContext.get())->getJavaInstance();
  624. env->CallVoidMethod(globalRef, env->GetMethodID(NativeInstanceClass, "onAudioLevelsUpdated", "([I[F[Z)V"), intArray, floatArray, boolArray);
  625. env->DeleteLocalRef(floatArray);
  626. });
  627. },
  628. .remoteMediaStateUpdated = [platformContext](AudioState audioState, VideoState videoState) {
  629. jobject globalRef = ((AndroidContext *) platformContext.get())->getJavaInstance();
  630. tgvoip::jni::DoWithJNI([globalRef, audioState, videoState](JNIEnv *env) {
  631. env->CallVoidMethod(globalRef, env->GetMethodID(NativeInstanceClass, "onRemoteMediaStateUpdated", "(II)V"), (jint) audioState, (jint )videoState);
  632. });
  633. },
  634. .signalingDataEmitted = [platformContext](const std::vector<uint8_t> &data) {
  635. jobject globalRef = ((AndroidContext *) platformContext.get())->getJavaInstance();
  636. tgvoip::jni::DoWithJNI([globalRef, data](JNIEnv *env) {
  637. jbyteArray arr = copyVectorToJavaByteArray(env, data);
  638. env->CallVoidMethod(globalRef, env->GetMethodID(NativeInstanceClass, "onSignalingData", "([B)V"), arr);
  639. env->DeleteLocalRef(arr);
  640. });
  641. },
  642. .platformContext = platformContext,
  643. };
  644. for (int i = 0, size = env->GetArrayLength(endpoints); i < size; i++) {
  645. JavaObject endpointObject(env, env->GetObjectArrayElement(endpoints, i));
  646. bool isRtc = endpointObject.getBooleanField("isRtc");
  647. if (isRtc) {
  648. RtcServer rtcServer;
  649. rtcServer.host = tgvoip::jni::JavaStringToStdString(env, endpointObject.getStringField("ipv4"));
  650. rtcServer.port = static_cast<uint16_t>(endpointObject.getIntField("port"));
  651. rtcServer.login = tgvoip::jni::JavaStringToStdString(env, endpointObject.getStringField("username"));
  652. rtcServer.password = tgvoip::jni::JavaStringToStdString(env, endpointObject.getStringField("password"));
  653. rtcServer.isTurn = endpointObject.getBooleanField("turn");
  654. descriptor.rtcServers.push_back(std::move(rtcServer));
  655. } else {
  656. Endpoint endpoint;
  657. endpoint.endpointId = endpointObject.getLongField("id");
  658. endpoint.host = EndpointHost{tgvoip::jni::JavaStringToStdString(env, endpointObject.getStringField("ipv4")), tgvoip::jni::JavaStringToStdString(env, endpointObject.getStringField("ipv6"))};
  659. endpoint.port = static_cast<uint16_t>(endpointObject.getIntField("port"));
  660. endpoint.type = parseEndpointType(env, endpointObject.getIntField("type"));
  661. jbyteArray peerTag = endpointObject.getByteArrayField("peerTag");
  662. if (peerTag && env->GetArrayLength(peerTag)) {
  663. jbyte *peerTagBytes = env->GetByteArrayElements(peerTag, nullptr);
  664. memcpy(endpoint.peerTag, peerTagBytes, 16);
  665. env->ReleaseByteArrayElements(peerTag, peerTagBytes, JNI_ABORT);
  666. }
  667. descriptor.endpoints.push_back(std::move(endpoint));
  668. }
  669. }
  670. if (!env->IsSameObject(proxyClass, nullptr)) {
  671. JavaObject proxyObject(env, proxyClass);
  672. descriptor.proxy = std::make_unique<Proxy>();
  673. descriptor.proxy->host = tgvoip::jni::JavaStringToStdString(env, proxyObject.getStringField("host"));
  674. descriptor.proxy->port = static_cast<uint16_t>(proxyObject.getIntField("port"));
  675. descriptor.proxy->login = tgvoip::jni::JavaStringToStdString(env, proxyObject.getStringField("login"));
  676. descriptor.proxy->password = tgvoip::jni::JavaStringToStdString(env, proxyObject.getStringField("password"));
  677. }
  678. readPersistentState(tgvoip::jni::JavaStringToStdString(env, persistentStateFilePath).c_str(), descriptor.persistentState);
  679. auto *holder = new InstanceHolder;
  680. holder->nativeInstance = tgcalls::Meta::Create(v, std::move(descriptor));
  681. holder->_videoCapture = videoCapture;
  682. holder->_platformContext = platformContext;
  683. holder->_sink = webrtc::JavaToNativeVideoSink(env, remoteSink);
  684. holder->nativeInstance->setIncomingVideoOutput(holder->_sink);
  685. holder->nativeInstance->setNetworkType(parseNetworkType(networkType));
  686. holder->nativeInstance->setRequestedVideoAspect(aspectRatio);
  687. return reinterpret_cast<jlong>(holder);
  688. }
  689. extern "C"
  690. JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_setGlobalServerConfig(JNIEnv *env, jobject obj, jstring serverConfigJson) {
  691. SetLegacyGlobalServerConfig(tgvoip::jni::JavaStringToStdString(env, serverConfigJson));
  692. }
  693. extern "C"
  694. JNIEXPORT jstring JNICALL Java_org_telegram_messenger_voip_NativeInstance_getVersion(JNIEnv *env, jobject obj) {
  695. return env->NewStringUTF(tgvoip::VoIPController::GetVersion());
  696. }
  697. extern "C"
  698. JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_setBufferSize(JNIEnv *env, jobject obj, jint size) {
  699. tgvoip::audio::AudioOutputOpenSLES::nativeBufferSize = (unsigned int) size;
  700. tgvoip::audio::AudioInputOpenSLES::nativeBufferSize = (unsigned int) size;
  701. }
  702. extern "C"
  703. JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_setNetworkType(JNIEnv *env, jobject obj, jint networkType) {
  704. InstanceHolder *instance = getInstanceHolder(env, obj);
  705. if (instance->nativeInstance == nullptr) {
  706. return;
  707. }
  708. instance->nativeInstance->setNetworkType(parseNetworkType(networkType));
  709. }
  710. extern "C"
  711. JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_setMuteMicrophone(JNIEnv *env, jobject obj, jboolean muteMicrophone) {
  712. InstanceHolder *instance = getInstanceHolder(env, obj);
  713. if (instance->nativeInstance != nullptr) {
  714. instance->nativeInstance->setMuteMicrophone(muteMicrophone);
  715. } else if (instance->groupNativeInstance != nullptr) {
  716. instance->groupNativeInstance->setIsMuted(muteMicrophone);
  717. }
  718. }
  719. extern "C"
  720. JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_setVolume(JNIEnv *env, jobject obj, jint ssrc, jdouble volume) {
  721. InstanceHolder *instance = getInstanceHolder(env, obj);
  722. if (instance->groupNativeInstance != nullptr) {
  723. instance->groupNativeInstance->setVolume(ssrc, volume);
  724. }
  725. }
  726. extern "C"
  727. JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_setAudioOutputGainControlEnabled(JNIEnv *env, jobject obj, jboolean enabled) {
  728. InstanceHolder *instance = getInstanceHolder(env, obj);
  729. if (instance->nativeInstance == nullptr) {
  730. return;
  731. }
  732. instance->nativeInstance->setAudioOutputGainControlEnabled(enabled);
  733. }
  734. extern "C"
  735. JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_setEchoCancellationStrength(JNIEnv *env, jobject obj, jint strength) {
  736. InstanceHolder *instance = getInstanceHolder(env, obj);
  737. if (instance->nativeInstance == nullptr) {
  738. return;
  739. }
  740. instance->nativeInstance->setEchoCancellationStrength(strength);
  741. }
  742. extern "C"
  743. JNIEXPORT jstring JNICALL Java_org_telegram_messenger_voip_NativeInstance_getLastError(JNIEnv *env, jobject obj) {
  744. InstanceHolder *instance = getInstanceHolder(env, obj);
  745. if (instance->nativeInstance == nullptr) {
  746. return nullptr;
  747. }
  748. return env->NewStringUTF(instance->nativeInstance->getLastError().c_str());
  749. }
  750. extern "C"
  751. JNIEXPORT jstring JNICALL Java_org_telegram_messenger_voip_NativeInstance_getDebugInfo(JNIEnv *env, jobject obj) {
  752. InstanceHolder *instance = getInstanceHolder(env, obj);
  753. if (instance->nativeInstance == nullptr) {
  754. return nullptr;
  755. }
  756. return env->NewStringUTF(instance->nativeInstance->getDebugInfo().c_str());
  757. }
  758. extern "C"
  759. JNIEXPORT jlong JNICALL Java_org_telegram_messenger_voip_NativeInstance_getPreferredRelayId(JNIEnv *env, jobject obj) {
  760. InstanceHolder *instance = getInstanceHolder(env, obj);
  761. if (instance->nativeInstance == nullptr) {
  762. return 0;
  763. }
  764. return instance->nativeInstance->getPreferredRelayId();
  765. }
  766. extern "C"
  767. JNIEXPORT jobject JNICALL Java_org_telegram_messenger_voip_NativeInstance_getTrafficStats(JNIEnv *env, jobject obj) {
  768. InstanceHolder *instance = getInstanceHolder(env, obj);
  769. if (instance->nativeInstance == nullptr) {
  770. return nullptr;
  771. }
  772. return asJavaTrafficStats(env, instance->nativeInstance->getTrafficStats());
  773. }
  774. extern "C"
  775. JNIEXPORT jbyteArray JNICALL Java_org_telegram_messenger_voip_NativeInstance_getPersistentState(JNIEnv *env, jobject obj) {
  776. InstanceHolder *instance = getInstanceHolder(env, obj);
  777. if (instance->nativeInstance == nullptr) {
  778. return nullptr;
  779. }
  780. return copyVectorToJavaByteArray(env, instance->nativeInstance->getPersistentState().value);
  781. }
  782. extern "C"
  783. JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_stopNative(JNIEnv *env, jobject obj) {
  784. InstanceHolder *instance = getInstanceHolder(env, obj);
  785. if (instance->nativeInstance == nullptr) {
  786. return;
  787. }
  788. instance->nativeInstance->stop([instance](const FinalState& finalState) {
  789. JNIEnv *env = webrtc::AttachCurrentThreadIfNeeded();
  790. jobject globalRef = ((AndroidContext *) instance->_platformContext.get())->getJavaInstance();
  791. const std::string &path = tgvoip::jni::JavaStringToStdString(env, JavaObject(env, globalRef).getStringField("persistentStateFilePath"));
  792. savePersistentState(path.c_str(), finalState.persistentState);
  793. env->CallVoidMethod(globalRef, env->GetMethodID(NativeInstanceClass, "onStop", "(Lorg/telegram/messenger/voip/Instance$FinalState;)V"), asJavaFinalState(env, finalState));
  794. delete instance;
  795. });
  796. }
  797. extern "C"
  798. JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_stopGroupNative(JNIEnv *env, jobject obj) {
  799. InstanceHolder *instance = getInstanceHolder(env, obj);
  800. if (instance->groupNativeInstance == nullptr) {
  801. return;
  802. }
  803. instance->groupNativeInstance->stop();
  804. instance->groupNativeInstance.reset();
  805. delete instance;
  806. }
  807. extern "C"
  808. JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_onStreamPartAvailable(JNIEnv *env, jobject obj, jlong ts, jobject byteBuffer, jint size, jlong responseTs, jint videoChannel, jint quality) {
  809. InstanceHolder *instance = getInstanceHolder(env, obj);
  810. if (instance->groupNativeInstance == nullptr) {
  811. return;
  812. }
  813. auto context = (AndroidContext *) instance->_platformContext.get();
  814. std::shared_ptr<BroadcastPartTask> task;
  815. auto q = (VideoChannelDescription::Quality) quality;
  816. if (videoChannel != 0) {
  817. for (auto videoTaskIter = context->videoStreamTasks.begin(); videoTaskIter != context->videoStreamTasks.end(); videoTaskIter++) {
  818. if (((BroadcastPartTaskJava *) videoTaskIter->get())->isValidTaskFor(ts, videoChannel, q)) {
  819. task = *videoTaskIter;
  820. context->videoStreamTasks.erase(videoTaskIter);
  821. break;
  822. }
  823. }
  824. } else {
  825. for (auto audioTaskIter = context->audioStreamTasks.begin(); audioTaskIter != context->audioStreamTasks.end(); audioTaskIter++) {
  826. if (((BroadcastPartTaskJava *) audioTaskIter->get())->isValidTaskFor(ts, 0, q)) {
  827. task = *audioTaskIter;
  828. context->audioStreamTasks.erase(audioTaskIter);
  829. break;
  830. }
  831. }
  832. }
  833. if (task != nullptr) {
  834. if (byteBuffer != nullptr) {
  835. auto buf = (uint8_t *) env->GetDirectBufferAddress(byteBuffer);
  836. ((BroadcastPartTaskJava *) task.get())->call(ts, responseTs, BroadcastPart::Status::Success, buf, size);
  837. } else {
  838. ((BroadcastPartTaskJava *) task.get())->call(ts, responseTs, size == 0 ? BroadcastPart::Status::NotReady : BroadcastPart::Status::ResyncNeeded, nullptr, 0);
  839. }
  840. }
  841. }
  842. extern "C"
  843. JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_onMediaDescriptionAvailable(JNIEnv *env, jobject obj, jlong taskPtr, jintArray ssrcs) {
  844. InstanceHolder *instance = getInstanceHolder(env, obj);
  845. if (instance->groupNativeInstance == nullptr) {
  846. return;
  847. }
  848. auto task = reinterpret_cast<RequestMediaChannelDescriptionTaskJava *>(taskPtr);
  849. task->call(env, ssrcs);
  850. auto context = (AndroidContext *) instance->_platformContext.get();
  851. for (auto iter = context->descriptionTasks.begin(); iter != context->descriptionTasks.end(); iter++) {
  852. if (reinterpret_cast<intptr_t>(iter->get()) == taskPtr) {
  853. context->descriptionTasks.erase(iter);
  854. break;
  855. }
  856. }
  857. }
  858. extern "C"
  859. JNIEXPORT jlong JNICALL Java_org_telegram_messenger_voip_NativeInstance_createVideoCapturer(JNIEnv *env, jclass clazz, jobject localSink, jint type) {
  860. initWebRTC(env);
  861. std::unique_ptr<VideoCaptureInterface> capture;
  862. if (type == 0 || type == 1) {
  863. capture = tgcalls::VideoCaptureInterface::Create(StaticThreads::getThreads(), type == 1 ? "front" : "back", false, std::make_shared<AndroidContext>(env, nullptr, false));
  864. } else {
  865. capture = tgcalls::VideoCaptureInterface::Create(StaticThreads::getThreads(), "screen", true, std::make_shared<AndroidContext>(env, nullptr, true));
  866. }
  867. capture->setOutput(webrtc::JavaToNativeVideoSink(env, localSink));
  868. capture->setState(VideoState::Active);
  869. return reinterpret_cast<intptr_t>(capture.release());
  870. }
  871. extern "C"
  872. JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_activateVideoCapturer(JNIEnv *env, jobject obj, jlong videoCapturer) {
  873. InstanceHolder *instance = getInstanceHolder(env, obj);
  874. if (instance->nativeInstance) {
  875. instance->nativeInstance->setVideoCapture(nullptr);
  876. } else if (instance->groupNativeInstance) {
  877. instance->groupNativeInstance->setVideoSource(nullptr);
  878. }
  879. auto capturer = reinterpret_cast<VideoCaptureInterface *>(videoCapturer);
  880. capturer->setState(VideoState::Active);
  881. }
  882. extern "C"
  883. JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_clearVideoCapturer(JNIEnv *env, jobject obj) {
  884. InstanceHolder *instance = getInstanceHolder(env, obj);
  885. if (instance->nativeInstance) {
  886. instance->nativeInstance->setVideoCapture(nullptr);
  887. } else if (instance->groupNativeInstance) {
  888. instance->groupNativeInstance->setVideoSource(nullptr);
  889. }
  890. }
  891. extern "C"
  892. JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_destroyVideoCapturer(JNIEnv *env, jclass clazz, jlong videoCapturer) {
  893. auto capturer = reinterpret_cast<VideoCaptureInterface *>(videoCapturer);
  894. delete capturer;
  895. }
  896. extern "C"
  897. JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_switchCameraCapturer(JNIEnv *env, jclass clazz, jlong videoCapturer, jboolean front) {
  898. auto capturer = reinterpret_cast<VideoCaptureInterface *>(videoCapturer);
  899. capturer->switchToDevice(front ? "front" : "back", false);
  900. }
  901. extern "C"
  902. JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_setVideoStateCapturer(JNIEnv *env, jclass clazz, jlong videoCapturer, jint videoState) {
  903. auto capturer = reinterpret_cast<VideoCaptureInterface *>(videoCapturer);
  904. capturer->setState(static_cast<VideoState>(videoState));
  905. }
  906. extern "C"
  907. JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_switchCamera(JNIEnv *env, jobject obj, jboolean front) {
  908. InstanceHolder *instance = getInstanceHolder(env, obj);
  909. if (instance->_videoCapture == nullptr) {
  910. return;
  911. }
  912. instance->_videoCapture->switchToDevice(front ? "front" : "back", false);
  913. }
  914. extern "C"
  915. JNIEXPORT jboolean JNICALL Java_org_telegram_messenger_voip_NativeInstance_hasVideoCapturer(JNIEnv *env, jobject obj) {
  916. InstanceHolder *instance = getInstanceHolder(env, obj);
  917. if (instance->_videoCapture == nullptr) {
  918. return JNI_FALSE;
  919. }
  920. return JNI_TRUE;
  921. }
  922. extern "C"
  923. JNIEXPORT void Java_org_telegram_messenger_voip_NativeInstance_setVideoState(JNIEnv *env, jobject obj, jint state) {
  924. InstanceHolder *instance = getInstanceHolder(env, obj);
  925. std::shared_ptr<tgcalls::VideoCaptureInterface> capturer = instance->useScreencast ? instance->_screenVideoCapture : instance->_videoCapture;
  926. if (capturer == nullptr) {
  927. return;
  928. }
  929. capturer->setState(static_cast<VideoState>(state));
  930. }
  931. extern "C"
  932. JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_setupOutgoingVideo(JNIEnv *env, jobject obj, jobject localSink, jint type) {
  933. InstanceHolder *instance = getInstanceHolder(env, obj);
  934. std::shared_ptr<tgcalls::VideoCaptureInterface> capturer;
  935. if (type == 0 || type == 1) {
  936. if (instance->_videoCapture == nullptr) {
  937. instance->_videoCapture = tgcalls::VideoCaptureInterface::Create(StaticThreads::getThreads(), type == 1 ? "front" : "back", false, std::make_shared<AndroidContext>(env, nullptr, false));
  938. }
  939. capturer = instance->_videoCapture;
  940. instance->useScreencast = false;
  941. } else {
  942. if (instance->_screenVideoCapture == nullptr) {
  943. instance->_screenVideoCapture = tgcalls::VideoCaptureInterface::Create(StaticThreads::getThreads(), "screen", true, std::make_shared<AndroidContext>(env, nullptr, true));
  944. }
  945. capturer = instance->_screenVideoCapture;
  946. instance->useScreencast = true;
  947. }
  948. capturer->setOutput(webrtc::JavaToNativeVideoSink(env, localSink));
  949. capturer->setState(VideoState::Active);
  950. if (instance->nativeInstance) {
  951. instance->nativeInstance->setVideoCapture(capturer);
  952. } else if (instance->groupNativeInstance) {
  953. instance->groupNativeInstance->setVideoCapture(capturer);
  954. }
  955. }
  956. extern "C"
  957. JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_setupOutgoingVideoCreated(JNIEnv *env, jobject obj, jlong videoCapturer) {
  958. if (videoCapturer == 0) {
  959. return;
  960. }
  961. InstanceHolder *instance = getInstanceHolder(env, obj);
  962. if (instance->_videoCapture == nullptr) {
  963. instance->_videoCapture = std::shared_ptr<VideoCaptureInterface>(reinterpret_cast<VideoCaptureInterface *>(videoCapturer));
  964. }
  965. instance->_videoCapture->setState(VideoState::Active);
  966. if (instance->nativeInstance) {
  967. instance->nativeInstance->setVideoCapture(instance->_videoCapture);
  968. instance->useScreencast = false;
  969. } else if (instance->groupNativeInstance) {
  970. instance->groupNativeInstance->setVideoCapture(instance->_videoCapture);
  971. }
  972. }
  973. extern "C"
  974. JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_onSignalingDataReceive(JNIEnv *env, jobject obj, jbyteArray value) {
  975. InstanceHolder *instance = getInstanceHolder(env, obj);
  976. if (instance->nativeInstance == nullptr) {
  977. return;
  978. }
  979. auto *valueBytes = (uint8_t *) env->GetByteArrayElements(value, nullptr);
  980. const size_t size = env->GetArrayLength(value);
  981. auto array = std::vector<uint8_t>(size);
  982. memcpy(&array[0], valueBytes, size);
  983. instance->nativeInstance->receiveSignalingData(array);
  984. env->ReleaseByteArrayElements(value, (jbyte *) valueBytes, JNI_ABORT);
  985. }
  986. extern "C"
  987. JNIEXPORT void JNICALL Java_org_telegram_messenger_voip_NativeInstance_onRequestTimeComplete(JNIEnv *env, jobject obj, jlong taskPtr, jlong currentTime) {
  988. InstanceHolder *instance = getInstanceHolder(env, obj);
  989. if (instance->groupNativeInstance == nullptr) {
  990. return;
  991. }
  992. auto task = reinterpret_cast<RequestCurrentTimeTaskJava *>(taskPtr);
  993. task->_callback(currentTime);
  994. }
  995. }