tg_voip_jni.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. //
  2. // libtgvoip is free and unencumbered public domain software.
  3. // For more information, see http://unlicense.org or the UNLICENSE file
  4. // you should have received with this source code distribution.
  5. //
  6. #include <jni.h>
  7. #include <string.h>
  8. #include <map>
  9. #include <string>
  10. #include <vector>
  11. #include "libtgvoip/VoIPServerConfig.h"
  12. #include "libtgvoip/VoIPController.h"
  13. #include "libtgvoip/os/android/AudioOutputOpenSLES.h"
  14. #include "libtgvoip/os/android/AudioInputOpenSLES.h"
  15. #include "libtgvoip/os/android/AudioInputAndroid.h"
  16. #include "libtgvoip/os/android/AudioOutputAndroid.h"
  17. #include "libtgvoip/audio/Resampler.h"
  18. #include "libtgvoip/os/android/JNIUtilities.h"
  19. #include "libtgvoip/PrivateDefines.h"
  20. #include "libtgvoip/logging.h"
  21. #include "../c_utils.h"
  22. #ifdef TGVOIP_HAS_CONFIG
  23. #include <tgvoip_config.h>
  24. #endif
  25. JavaVM* sharedJVM;
  26. jfieldID audioRecordInstanceFld=NULL;
  27. jfieldID audioTrackInstanceFld=NULL;
  28. jmethodID setStateMethod=NULL;
  29. jmethodID setSignalBarsMethod=NULL;
  30. jmethodID setSelfStreamsMethod=NULL;
  31. jmethodID setParticipantAudioEnabledMethod=NULL;
  32. jclass jniUtilitiesClass=NULL;
  33. struct ImplDataAndroid{
  34. jobject javaObject;
  35. std::string persistentStateFile="";
  36. };
  37. #ifndef TGVOIP_PACKAGE_PATH
  38. #define TGVOIP_PACKAGE_PATH "org/telegram/messenger/voip"
  39. #endif
  40. using namespace tgvoip;
  41. using namespace tgvoip::audio;
  42. namespace tgvoip {
  43. #pragma mark - Callbacks
  44. void updateConnectionState(VoIPController *cntrlr, int state) {
  45. ImplDataAndroid *impl = (ImplDataAndroid *) cntrlr->implData;
  46. jni::AttachAndCallVoidMethod(setStateMethod, impl->javaObject, state);
  47. }
  48. void updateSignalBarCount(VoIPController *cntrlr, int count) {
  49. ImplDataAndroid *impl = (ImplDataAndroid *) cntrlr->implData;
  50. jni::AttachAndCallVoidMethod(setSignalBarsMethod, impl->javaObject, count);
  51. }
  52. #pragma mark - VoIPController
  53. jlong VoIPController_nativeInit(JNIEnv *env, jobject thiz, jstring persistentStateFile) {
  54. ImplDataAndroid *impl = new ImplDataAndroid();
  55. impl->javaObject = env->NewGlobalRef(thiz);
  56. if (persistentStateFile) {
  57. impl->persistentStateFile = jni::JavaStringToStdString(env, persistentStateFile);
  58. }
  59. VoIPController *cntrlr = new VoIPController();
  60. cntrlr->implData = impl;
  61. VoIPController::Callbacks callbacks;
  62. callbacks.connectionStateChanged = updateConnectionState;
  63. callbacks.signalBarCountChanged = updateSignalBarCount;
  64. cntrlr->SetCallbacks(callbacks);
  65. if (!impl->persistentStateFile.empty()) {
  66. FILE *f = fopen(impl->persistentStateFile.c_str(), "r");
  67. if (f) {
  68. fseek(f, 0, SEEK_END);
  69. size_t len = static_cast<size_t>(ftell(f));
  70. fseek(f, 0, SEEK_SET);
  71. if (len < 1024 * 512 && len > 0) {
  72. char *fbuf = static_cast<char *>(malloc(len));
  73. fread(fbuf, 1, len, f);
  74. std::vector<uint8_t> state(fbuf, fbuf + len);
  75. free(fbuf);
  76. cntrlr->SetPersistentState(state);
  77. }
  78. fclose(f);
  79. }
  80. }
  81. return (jlong) (intptr_t) cntrlr;
  82. }
  83. void VoIPController_nativeStart(JNIEnv *env, jobject thiz, jlong inst) {
  84. ((VoIPController *) (intptr_t) inst)->Start();
  85. }
  86. void VoIPController_nativeConnect(JNIEnv *env, jobject thiz, jlong inst) {
  87. ((VoIPController *) (intptr_t) inst)->Connect();
  88. }
  89. void VoIPController_nativeSetProxy(JNIEnv *env, jobject thiz, jlong inst, jstring _address, jint port, jstring _username, jstring _password) {
  90. ((VoIPController *) (intptr_t) inst)->SetProxy(PROXY_SOCKS5, jni::JavaStringToStdString(env, _address), (uint16_t) port, jni::JavaStringToStdString(env, _username), jni::JavaStringToStdString(env, _password));
  91. }
  92. void VoIPController_nativeSetEncryptionKey(JNIEnv *env, jobject thiz, jlong inst, jbyteArray key, jboolean isOutgoing) {
  93. jbyte *akey = env->GetByteArrayElements(key, NULL);
  94. ((VoIPController *) (intptr_t) inst)->SetEncryptionKey((char *) akey, isOutgoing);
  95. env->ReleaseByteArrayElements(key, akey, JNI_ABORT);
  96. }
  97. void VoIPController_nativeSetNativeBufferSize(JNIEnv *env, jclass thiz, jint size) {
  98. AudioOutputOpenSLES::nativeBufferSize = (unsigned int) size;
  99. AudioInputOpenSLES::nativeBufferSize = (unsigned int) size;
  100. }
  101. void VoIPController_nativeRelease(JNIEnv *env, jobject thiz, jlong inst) {
  102. //env->DeleteGlobalRef(AudioInputAndroid::jniClass);
  103. VoIPController *ctlr = ((VoIPController *) (intptr_t) inst);
  104. ImplDataAndroid *impl = (ImplDataAndroid *) ctlr->implData;
  105. ctlr->Stop();
  106. std::vector<uint8_t> state = ctlr->GetPersistentState();
  107. delete ctlr;
  108. env->DeleteGlobalRef(impl->javaObject);
  109. if (!impl->persistentStateFile.empty()) {
  110. FILE *f = fopen(impl->persistentStateFile.c_str(), "w");
  111. if (f) {
  112. fwrite(state.data(), 1, state.size(), f);
  113. fclose(f);
  114. }
  115. }
  116. delete impl;
  117. }
  118. jstring VoIPController_nativeGetDebugString(JNIEnv *env, jobject thiz, jlong inst) {
  119. std::string str = ((VoIPController *) (intptr_t) inst)->GetDebugString();
  120. return env->NewStringUTF(str.c_str());
  121. }
  122. void VoIPController_nativeSetNetworkType(JNIEnv *env, jobject thiz, jlong inst, jint type) {
  123. ((VoIPController *) (intptr_t) inst)->SetNetworkType(type);
  124. }
  125. void VoIPController_nativeSetMicMute(JNIEnv *env, jobject thiz, jlong inst, jboolean mute) {
  126. ((VoIPController *) (intptr_t) inst)->SetMicMute(mute);
  127. }
  128. void VoIPController_nativeSetConfig(JNIEnv *env, jobject thiz, jlong inst, jdouble recvTimeout, jdouble initTimeout, jint dataSavingMode, jboolean enableAEC, jboolean enableNS, jboolean enableAGC, jstring logFilePath, jstring statsDumpPath, jboolean logPacketStats) {
  129. VoIPController::Config cfg;
  130. cfg.initTimeout = initTimeout;
  131. cfg.recvTimeout = recvTimeout;
  132. cfg.dataSaving = dataSavingMode;
  133. cfg.enableAEC = enableAEC;
  134. cfg.enableNS = enableNS;
  135. cfg.enableAGC = enableAGC;
  136. cfg.enableCallUpgrade = false;
  137. cfg.logPacketStats = logPacketStats;
  138. if (logFilePath) {
  139. cfg.logFilePath = jni::JavaStringToStdString(env, logFilePath);
  140. }
  141. if (statsDumpPath) {
  142. cfg.statsDumpFilePath = jni::JavaStringToStdString(env, statsDumpPath);
  143. }
  144. ((VoIPController *) (intptr_t) inst)->SetConfig(cfg);
  145. }
  146. void VoIPController_nativeDebugCtl(JNIEnv *env, jobject thiz, jlong inst, jint request, jint param) {
  147. ((VoIPController *) (intptr_t) inst)->DebugCtl(request, param);
  148. }
  149. jstring VoIPController_nativeGetVersion(JNIEnv *env, jclass clasz) {
  150. return env->NewStringUTF(VoIPController::GetVersion());
  151. }
  152. jlong VoIPController_nativeGetPreferredRelayID(JNIEnv *env, jclass clasz, jlong inst) {
  153. return ((VoIPController *) (intptr_t) inst)->GetPreferredRelayID();
  154. }
  155. jint VoIPController_nativeGetLastError(JNIEnv *env, jclass clasz, jlong inst) {
  156. return ((VoIPController *) (intptr_t) inst)->GetLastError();
  157. }
  158. void VoIPController_nativeGetStats(JNIEnv *env, jclass clasz, jlong inst, jobject stats) {
  159. VoIPController::TrafficStats _stats;
  160. ((VoIPController *) (intptr_t) inst)->GetStats(&_stats);
  161. jclass cls = env->GetObjectClass(stats);
  162. env->SetLongField(stats, env->GetFieldID(cls, "bytesSentWifi", "J"), _stats.bytesSentWifi);
  163. env->SetLongField(stats, env->GetFieldID(cls, "bytesSentMobile", "J"), _stats.bytesSentMobile);
  164. env->SetLongField(stats, env->GetFieldID(cls, "bytesRecvdWifi", "J"), _stats.bytesRecvdWifi);
  165. env->SetLongField(stats, env->GetFieldID(cls, "bytesRecvdMobile", "J"), _stats.bytesRecvdMobile);
  166. }
  167. jstring VoIPController_nativeGetDebugLog(JNIEnv *env, jobject thiz, jlong inst) {
  168. VoIPController *ctlr = ((VoIPController *) (intptr_t) inst);
  169. std::string log = ctlr->GetDebugLog();
  170. return env->NewStringUTF(log.c_str());
  171. }
  172. void VoIPController_nativeSetAudioOutputGainControlEnabled(JNIEnv *env, jclass clasz, jlong inst, jboolean enabled) {
  173. ((VoIPController *) (intptr_t) inst)->SetAudioOutputGainControlEnabled(enabled);
  174. }
  175. void VoIPController_nativeSetEchoCancellationStrength(JNIEnv *env, jclass cls, jlong inst, jint strength) {
  176. ((VoIPController *) (intptr_t) inst)->SetEchoCancellationStrength(strength);
  177. }
  178. jint VoIPController_nativeGetPeerCapabilities(JNIEnv *env, jclass cls, jlong inst) {
  179. return ((VoIPController *) (intptr_t) inst)->GetPeerCapabilities();
  180. }
  181. jboolean VoIPController_nativeNeedRate(JNIEnv *env, jclass cls, jlong inst) {
  182. return static_cast<jboolean>(((VoIPController *) (intptr_t) inst)->NeedRate());
  183. }
  184. jint VoIPController_getConnectionMaxLayer(JNIEnv *env, jclass cls) {
  185. return VoIPController::GetConnectionMaxLayer();
  186. }
  187. void AudioRecordJNI_nativeCallback(JNIEnv *env, jobject thiz, jobject buffer) {
  188. jlong inst = env->GetLongField(thiz, audioRecordInstanceFld);
  189. AudioInputAndroid *in = (AudioInputAndroid *) (intptr_t) inst;
  190. in->HandleCallback(env, buffer);
  191. }
  192. void AudioTrackJNI_nativeCallback(JNIEnv *env, jobject thiz, jbyteArray buffer) {
  193. jlong inst = env->GetLongField(thiz, audioTrackInstanceFld);
  194. AudioOutputAndroid *in = (AudioOutputAndroid *) (intptr_t) inst;
  195. in->HandleCallback(env, buffer);
  196. }
  197. void VoIPServerConfig_nativeSetConfig(JNIEnv *env, jclass clasz, jstring jsonString) {
  198. ServerConfig::GetSharedInstance()->Update(jni::JavaStringToStdString(env, jsonString));
  199. }
  200. jint Resampler_convert44to48(JNIEnv *env, jclass cls, jobject from, jobject to) {
  201. return (jint) tgvoip::audio::Resampler::Convert44To48((int16_t *) env->GetDirectBufferAddress(from), (int16_t *) env->GetDirectBufferAddress(to), (size_t) (env->GetDirectBufferCapacity(from) / 2), (size_t) (env->GetDirectBufferCapacity(to) / 2));
  202. }
  203. jint Resampler_convert48to44(JNIEnv *env, jclass cls, jobject from, jobject to) {
  204. return (jint) tgvoip::audio::Resampler::Convert48To44((int16_t *) env->GetDirectBufferAddress(from), (int16_t *) env->GetDirectBufferAddress(to), (size_t) (env->GetDirectBufferCapacity(from) / 2), (size_t) (env->GetDirectBufferCapacity(to) / 2));
  205. }
  206. template<int level>
  207. void VLog_log(JNIEnv *env, jclass cls, jstring jmsg) {
  208. const char *format = "[java] %s";
  209. std::string msg = jni::JavaStringToStdString(env, jmsg);
  210. switch (level) {
  211. case 0:
  212. LOGV(format, msg.c_str());
  213. break;
  214. case 1:
  215. LOGD(format, msg.c_str());
  216. break;
  217. case 2:
  218. LOGI(format, msg.c_str());
  219. break;
  220. case 3:
  221. LOGW(format, msg.c_str());
  222. break;
  223. case 4:
  224. LOGE(format, msg.c_str());
  225. break;
  226. default:
  227. break;
  228. }
  229. }
  230. }
  231. extern "C" {
  232. int tgvoipOnJNILoad(JavaVM *vm, JNIEnv *env) {
  233. jclass controller = env->FindClass(TGVOIP_PACKAGE_PATH "/VoIPController");
  234. if (env->ExceptionCheck()) {
  235. env->ExceptionClear(); // is returning NULL from FindClass not enough?
  236. }
  237. jclass audioRecordJNI = env->FindClass(TGVOIP_PACKAGE_PATH "/AudioRecordJNI");
  238. jclass audioTrackJNI = env->FindClass(TGVOIP_PACKAGE_PATH "/AudioTrackJNI");
  239. jclass serverConfig = env->FindClass(TGVOIP_PACKAGE_PATH "/VoIPServerConfig");
  240. jclass resampler = env->FindClass(TGVOIP_PACKAGE_PATH "/Resampler");
  241. if (env->ExceptionCheck()) {
  242. env->ExceptionClear(); // is returning NULL from FindClass not enough?
  243. }
  244. jclass vlog = env->FindClass(TGVOIP_PACKAGE_PATH "/VLog");
  245. if (env->ExceptionCheck()) {
  246. env->ExceptionClear();
  247. }
  248. assert(controller && audioRecordJNI && audioTrackJNI && serverConfig && resampler);
  249. audioRecordInstanceFld = env->GetFieldID(audioRecordJNI, "nativeInst", "J");
  250. audioTrackInstanceFld = env->GetFieldID(audioTrackJNI, "nativeInst", "J");
  251. env->GetJavaVM(&sharedJVM);
  252. if (!AudioInputAndroid::jniClass) {
  253. jclass cls = env->FindClass(TGVOIP_PACKAGE_PATH "/AudioRecordJNI");
  254. AudioInputAndroid::jniClass = (jclass) env->NewGlobalRef(cls);
  255. AudioInputAndroid::initMethod = env->GetMethodID(cls, "init", "(IIII)V");
  256. AudioInputAndroid::releaseMethod = env->GetMethodID(cls, "release", "()V");
  257. AudioInputAndroid::startMethod = env->GetMethodID(cls, "start", "()Z");
  258. AudioInputAndroid::stopMethod = env->GetMethodID(cls, "stop", "()V");
  259. AudioInputAndroid::getEnabledEffectsMaskMethod = env->GetMethodID(cls, "getEnabledEffectsMask", "()I");
  260. cls = env->FindClass(TGVOIP_PACKAGE_PATH "/AudioTrackJNI");
  261. AudioOutputAndroid::jniClass = (jclass) env->NewGlobalRef(cls);
  262. AudioOutputAndroid::initMethod = env->GetMethodID(cls, "init", "(IIII)V");
  263. AudioOutputAndroid::releaseMethod = env->GetMethodID(cls, "release", "()V");
  264. AudioOutputAndroid::startMethod = env->GetMethodID(cls, "start", "()V");
  265. AudioOutputAndroid::stopMethod = env->GetMethodID(cls, "stop", "()V");
  266. }
  267. setStateMethod = env->GetMethodID(controller, "handleStateChange", "(I)V");
  268. setSignalBarsMethod = env->GetMethodID(controller, "handleSignalBarsChange", "(I)V");
  269. if (!jniUtilitiesClass) {
  270. jniUtilitiesClass = (jclass) env->NewGlobalRef(env->FindClass(TGVOIP_PACKAGE_PATH "/JNIUtilities"));
  271. }
  272. // VoIPController
  273. JNINativeMethod controllerMethods[] = {
  274. {"nativeInit", "(Ljava/lang/String;)J", (void *) &tgvoip::VoIPController_nativeInit},
  275. {"nativeStart", "(J)V", (void *) &tgvoip::VoIPController_nativeStart},
  276. {"nativeConnect", "(J)V", (void *) &tgvoip::VoIPController_nativeConnect},
  277. {"nativeSetProxy", "(JLjava/lang/String;ILjava/lang/String;Ljava/lang/String;)V", (void *) &tgvoip::VoIPController_nativeSetProxy},
  278. {"nativeSetEncryptionKey", "(J[BZ)V", (void *) &tgvoip::VoIPController_nativeSetEncryptionKey},
  279. {"nativeSetNativeBufferSize", "(I)V", (void *) &tgvoip::VoIPController_nativeSetNativeBufferSize},
  280. {"nativeRelease", "(J)V", (void *) &tgvoip::VoIPController_nativeRelease},
  281. {"nativeGetDebugString", "(J)Ljava/lang/String;", (void *) &tgvoip::VoIPController_nativeGetDebugString},
  282. {"nativeSetNetworkType", "(JI)V", (void *) &tgvoip::VoIPController_nativeSetNetworkType},
  283. {"nativeSetMicMute", "(JZ)V", (void *) &tgvoip::VoIPController_nativeSetMicMute},
  284. {"nativeSetConfig", "(JDDIZZZLjava/lang/String;Ljava/lang/String;Z)V", (void *) &tgvoip::VoIPController_nativeSetConfig},
  285. {"nativeDebugCtl", "(JII)V", (void *) &tgvoip::VoIPController_nativeDebugCtl},
  286. {"nativeGetVersion", "()Ljava/lang/String;", (void *) &tgvoip::VoIPController_nativeGetVersion},
  287. {"nativeGetPreferredRelayID", "(J)J", (void *) &tgvoip::VoIPController_nativeGetPreferredRelayID},
  288. {"nativeGetLastError", "(J)I", (void *) &tgvoip::VoIPController_nativeGetLastError},
  289. {"nativeGetStats", "(JL" TGVOIP_PACKAGE_PATH "/VoIPController$Stats;)V", (void *) &tgvoip::VoIPController_nativeGetStats},
  290. {"nativeGetDebugLog", "(J)Ljava/lang/String;", (void *) &tgvoip::VoIPController_nativeGetDebugLog},
  291. {"nativeSetAudioOutputGainControlEnabled", "(JZ)V", (void *) &tgvoip::VoIPController_nativeSetAudioOutputGainControlEnabled},
  292. {"nativeSetEchoCancellationStrength", "(JI)V", (void *) &tgvoip::VoIPController_nativeSetEchoCancellationStrength},
  293. {"nativeGetPeerCapabilities", "(J)I", (void *) &tgvoip::VoIPController_nativeGetPeerCapabilities},
  294. {"nativeNeedRate", "(J)Z", (void *) &tgvoip::VoIPController_nativeNeedRate},
  295. {"getConnectionMaxLayer", "()I", (void *) &tgvoip::VoIPController_getConnectionMaxLayer}
  296. };
  297. env->RegisterNatives(controller, controllerMethods, sizeof(controllerMethods) / sizeof(JNINativeMethod));
  298. // AudioRecordJNI
  299. JNINativeMethod audioRecordMethods[] = {
  300. {"nativeCallback", "(Ljava/nio/ByteBuffer;)V", (void *) &tgvoip::AudioRecordJNI_nativeCallback}
  301. };
  302. env->RegisterNatives(audioRecordJNI, audioRecordMethods, sizeof(audioRecordMethods) / sizeof(JNINativeMethod));
  303. // AudioTrackJNI
  304. JNINativeMethod audioTrackMethods[] = {
  305. {"nativeCallback", "([B)V", (void *) &tgvoip::AudioTrackJNI_nativeCallback}
  306. };
  307. env->RegisterNatives(audioTrackJNI, audioTrackMethods, sizeof(audioTrackMethods) / sizeof(JNINativeMethod));
  308. // VoIPServerConfig
  309. JNINativeMethod serverConfigMethods[] = {
  310. {"nativeSetConfig", "(Ljava/lang/String;)V", (void *) &tgvoip::VoIPServerConfig_nativeSetConfig}
  311. };
  312. env->RegisterNatives(serverConfig, serverConfigMethods, sizeof(serverConfigMethods) / sizeof(JNINativeMethod));
  313. // Resampler
  314. JNINativeMethod resamplerMethods[] = {
  315. {"convert44to48", "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;)I", (void *) &tgvoip::Resampler_convert44to48},
  316. {"convert48to44", "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;)I", (void *) &tgvoip::Resampler_convert48to44}
  317. };
  318. env->RegisterNatives(resampler, resamplerMethods, sizeof(resamplerMethods) / sizeof(JNINativeMethod));
  319. if (vlog) {
  320. // VLog
  321. JNINativeMethod vlogMethods[] = {
  322. {"v", "(Ljava/lang/String;)V", (void *) &tgvoip::VLog_log<0>},
  323. {"d", "(Ljava/lang/String;)V", (void *) &tgvoip::VLog_log<1>},
  324. {"i", "(Ljava/lang/String;)V", (void *) &tgvoip::VLog_log<2>},
  325. {"w", "(Ljava/lang/String;)V", (void *) &tgvoip::VLog_log<3>},
  326. {"e", "(Ljava/lang/String;)V", (void *) &tgvoip::VLog_log<4>}
  327. };
  328. env->RegisterNatives(vlog, vlogMethods, sizeof(vlogMethods) / sizeof(JNINativeMethod));
  329. }
  330. return JNI_TRUE;
  331. }
  332. }