mirror of
https://github.com/DrKLO/Telegram.git
synced 2024-12-22 06:25:14 +01:00
Update to 6.0.0 (1908)
This commit is contained in:
parent
df90eface5
commit
80c4acfa3b
1160 changed files with 237084 additions and 5423 deletions
|
@ -2,7 +2,7 @@ FROM gradle:6.0.1-jdk8
|
|||
|
||||
ENV ANDROID_SDK_URL https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip
|
||||
ENV ANDROID_API_LEVEL android-29
|
||||
ENV ANDROID_BUILD_TOOLS_VERSION 29.0.2
|
||||
ENV ANDROID_BUILD_TOOLS_VERSION 29.0.3
|
||||
ENV ANDROID_HOME /usr/local/android-sdk-linux
|
||||
ENV ANDROID_NDK_VERSION 20.0.5594570
|
||||
ENV ANDROID_VERSION 29
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import java.security.MessageDigest
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
repositories {
|
||||
|
@ -21,15 +23,15 @@ dependencies {
|
|||
|
||||
compileOnly 'org.checkerframework:checker-qual:2.5.2'
|
||||
compileOnly 'org.checkerframework:checker-compat-qual:2.5.0'
|
||||
implementation 'com.google.firebase:firebase-messaging:20.1.0'
|
||||
implementation 'com.google.firebase:firebase-config:19.1.1'
|
||||
implementation 'com.google.firebase:firebase-messaging:20.1.3'
|
||||
implementation 'com.google.firebase:firebase-config:19.1.3'
|
||||
implementation 'com.google.android.gms:play-services-maps:17.0.0'
|
||||
implementation 'com.google.android.gms:play-services-auth:17.0.0'
|
||||
implementation 'com.google.android.gms:play-services-vision:16.2.0'
|
||||
implementation 'com.google.android.gms:play-services-wallet:17.0.0'
|
||||
implementation 'com.google.android.gms:play-services-wearable:17.0.0'
|
||||
implementation 'com.google.android.gms:play-services-location:17.0.0'
|
||||
implementation 'net.hockeyapp.android:HockeySDK:5.2.0'
|
||||
implementation "com.microsoft.appcenter:appcenter-distribute:3.1.0"
|
||||
implementation "com.microsoft.appcenter:appcenter-crashes:3.1.0"
|
||||
implementation 'com.googlecode.mp4parser:isoparser:1.0.6'
|
||||
implementation 'com.stripe:stripe-android:2.0.2'
|
||||
implementation files('libs/libgsaverification-client.aar')
|
||||
|
@ -37,7 +39,7 @@ dependencies {
|
|||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
buildToolsVersion '29.0.2'
|
||||
buildToolsVersion '29.0.3'
|
||||
ndkVersion "20.0.5594570"
|
||||
|
||||
defaultConfig.applicationId = "org.telegram.messenger"
|
||||
|
@ -283,7 +285,12 @@ android {
|
|||
}
|
||||
}
|
||||
|
||||
defaultConfig.versionCode = 1869
|
||||
defaultConfig.versionCode = 1908
|
||||
|
||||
def tgVoipDexFileName = "libtgvoip.dex"
|
||||
def tgVoipDexClasses = ["AudioRecordJNI", "AudioTrackJNI", "NativeTgVoipDelegate", "NativeTgVoipInstance", "TgVoipNativeLoader", "Resampler", "VLog"]
|
||||
def tgVoipDexClassesPath = "org/telegram/messenger/voip"
|
||||
def dxUtilPath = "${sdkDirectory.path}/build-tools/${buildToolsVersion}/dx"
|
||||
|
||||
applicationVariants.all { variant ->
|
||||
variant.outputs.all { output ->
|
||||
|
@ -306,6 +313,61 @@ android {
|
|||
file(manifestPath).write(manifestContent)
|
||||
}
|
||||
}
|
||||
|
||||
def assembleTgVoipDexTaskName = "assemble${variant.name.capitalize()}TgVoipDex"
|
||||
|
||||
task "${assembleTgVoipDexTaskName}" {
|
||||
doLast {
|
||||
def sourceDir = (File) android.sourceSets.main.java.srcDirs[0]
|
||||
def classesDir = "${buildDir}/intermediates/javac/${variant.name}/classes"
|
||||
def javaDir = "${buildDir}/intermediates/java_tgvoip/${variant.name}/java"
|
||||
def tgVoipDir = new File(classesDir, tgVoipDexClassesPath)
|
||||
def javaVoipDirFile = new File(javaDir, tgVoipDexClassesPath)
|
||||
def tgVoipDexJavaFile = new File(javaVoipDirFile, "TgVoipDex.java")
|
||||
if (!javaVoipDirFile.exists()) {
|
||||
javaVoipDirFile.mkdirs()
|
||||
}
|
||||
def assetsDirFile = new File(buildDir, "intermediates/merged_assets/${variant.name}/out")
|
||||
if (!assetsDirFile.exists()) {
|
||||
assetsDirFile.mkdirs()
|
||||
}
|
||||
def tgVoipDexFile = new File(assetsDirFile, tgVoipDexFileName)
|
||||
|
||||
def classes = tgVoipDir.list(new FilenameFilter() {
|
||||
@Override
|
||||
boolean accept(File dir, String name) {
|
||||
// handle inner and anonymous classes
|
||||
return tgVoipDexClasses.any { name == "${it}.class" || name.startsWith("${it}\$") && name.endsWith(".class") }
|
||||
}
|
||||
}).collect { "${tgVoipDexClassesPath}/${it}" }
|
||||
|
||||
// 1. create libtgvoip.dex
|
||||
exec {
|
||||
workingDir classesDir
|
||||
commandLine([dxUtilPath, "--dex", "--output=${tgVoipDexFile}"] + classes)
|
||||
}
|
||||
|
||||
// 2. remove classes from the main dex
|
||||
project.delete classes.collect { "${classesDir}/${it}" }
|
||||
|
||||
// 3. insert checksum of libtgvoip.dex into TgVoipDex.java
|
||||
def digest = MessageDigest.getInstance("SHA1")
|
||||
def fileInputStream = tgVoipDexFile.newInputStream()
|
||||
def buffer = new byte[4096]
|
||||
def len
|
||||
while ((len = fileInputStream.read(buffer)) > 0) {
|
||||
digest.update(buffer, 0, len)
|
||||
}
|
||||
def dexChecksum = new String(Base64.getEncoder().encode(digest.digest())).trim()
|
||||
tgVoipDexJavaFile.write(new String(new File(sourceDir, "${tgVoipDexClassesPath}/TgVoipDex.java").readBytes()).replace("\$CHECKSUM\$", dexChecksum))
|
||||
exec {
|
||||
commandLine([findJavac(), "-d", classesDir, tgVoipDexJavaFile.absolutePath])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.findByName("compile${variant.name.capitalize()}JavaWithJavac").finalizedBy(assembleTgVoipDexTaskName)
|
||||
tasks.findByName("${assembleTgVoipDexTaskName}").mustRunAfter tasks.findByName("merge${variant.name.capitalize()}Assets")
|
||||
}
|
||||
|
||||
variantFilter { variant ->
|
||||
|
@ -318,7 +380,7 @@ android {
|
|||
defaultConfig {
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 28
|
||||
versionName "5.15.0"
|
||||
versionName "6.0.0"
|
||||
|
||||
vectorDrawables.generatedDensities = ['mdpi', 'hdpi', 'xhdpi', 'xxhdpi']
|
||||
|
||||
|
@ -333,4 +395,31 @@ android {
|
|||
}
|
||||
}
|
||||
|
||||
private static File findJavaHome() {
|
||||
String javaPath = System.getProperty("java.home")
|
||||
if (javaPath != null) {
|
||||
File javaBase = new File(javaPath)
|
||||
if (javaBase.exists()) {
|
||||
if (javaBase.getName().equalsIgnoreCase("jre") && new File(javaBase.getParentFile(), "bin/java").exists()) {
|
||||
return javaBase.getParentFile()
|
||||
} else {
|
||||
return javaBase
|
||||
}
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
private static File findJavac() {
|
||||
File javaHome = findJavaHome()
|
||||
if (javaHome != null) {
|
||||
return new File(javaHome, "bin/javac")
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
|
|
|
@ -95,10 +95,18 @@ endif
|
|||
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
TGVOIP_NATIVE_VERSION := 1.1
|
||||
TGVOIP_ADDITIONAL_CFLAGS := -DTGVOIP_NO_VIDEO
|
||||
include $(MY_LOCAL_PATH)/libtgvoip/Android.mk
|
||||
LOCAL_PATH := $(MY_LOCAL_PATH) # restore local path after include
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
TGVOIP_NATIVE_VERSION := 2.1
|
||||
TGVOIP_ADDITIONAL_CFLAGS := -DTGVOIP_NO_VIDEO
|
||||
include $(MY_LOCAL_PATH)/libtgvoip2/Android.mk
|
||||
LOCAL_PATH := $(MY_LOCAL_PATH) # restore local path after include
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_CPPFLAGS := -Wall -std=c++14 -DANDROID -frtti -DHAVE_PTHREAD -finline-functions -ffast-math -Os
|
||||
|
@ -351,7 +359,7 @@ LOCAL_CFLAGS += -Drestrict='' -D__EMX__ -DOPUS_BUILD -DFIXED_POINT -DUSE_ALLOCA
|
|||
LOCAL_CFLAGS += -DANDROID_NDK -DDISABLE_IMPORTGL -fno-strict-aliasing -fprefetch-loop-arrays -DAVOID_TABLES -DANDROID_TILE_BASED_DECODE -DANDROID_ARMV6_IDCT -ffast-math -D__STDC_CONSTANT_MACROS
|
||||
LOCAL_CPPFLAGS := -DBSD=1 -ffast-math -Os -funroll-loops -std=c++14 -DPACKAGE_NAME='"drinkless/org/ton"'
|
||||
LOCAL_LDLIBS := -ljnigraphics -llog -lz -lEGL -lGLESv2 -landroid
|
||||
LOCAL_STATIC_LIBRARIES := webp sqlite lz4 rlottie tgnet swscale avformat avcodec avresample avutil voip flac
|
||||
LOCAL_STATIC_LIBRARIES := webp sqlite lz4 rlottie tgnet swscale avformat avcodec avresample avutil flac
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
./opus/src/opus.c \
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
APP_PLATFORM := android-16
|
||||
NDK_TOOLCHAIN_VERSION := clang
|
||||
APP_STL := c++_static
|
||||
APP_STL := c++_shared
|
|
@ -219,14 +219,15 @@ static int writeOggPage(ogg_page *page, FILE *os) {
|
|||
return written;
|
||||
}
|
||||
|
||||
const opus_int32 bitrate = 16000;
|
||||
const opus_int32 rate = 16000;
|
||||
const opus_int32 bitrate = 25000;
|
||||
const opus_int32 frame_size = 960;
|
||||
const int with_cvbr = 1;
|
||||
const int max_ogg_delay = 0;
|
||||
const int comment_padding = 512;
|
||||
|
||||
opus_int32 coding_rate = 16000;
|
||||
opus_int32 rate = 48000;
|
||||
opus_int32 coding_rate = 48000;
|
||||
|
||||
ogg_int32_t _packetId;
|
||||
OpusEncoder *_encoder = 0;
|
||||
uint8_t *_packet = 0;
|
||||
|
@ -282,9 +283,12 @@ void cleanupRecorder() {
|
|||
memset(&og, 0, sizeof(ogg_page));
|
||||
}
|
||||
|
||||
int initRecorder(const char *path) {
|
||||
int initRecorder(const char *path, opus_int32 sampleRate) {
|
||||
cleanupRecorder();
|
||||
|
||||
|
||||
coding_rate = sampleRate;
|
||||
rate = sampleRate;
|
||||
|
||||
if (!path) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -305,7 +309,6 @@ int initRecorder(const char *path) {
|
|||
inopt.skip = 0;
|
||||
|
||||
comment_init(&inopt.comments, &inopt.comments_length, opus_get_version_string());
|
||||
coding_rate = 16000;
|
||||
|
||||
if (rate != coding_rate) {
|
||||
LOGE("Invalid rate");
|
||||
|
@ -329,6 +332,7 @@ int initRecorder(const char *path) {
|
|||
_packet = malloc(max_frame_bytes);
|
||||
|
||||
result = opus_encoder_ctl(_encoder, OPUS_SET_BITRATE(bitrate));
|
||||
result = opus_encoder_ctl(_encoder, OPUS_SET_COMPLEXITY(10));
|
||||
if (result != OPUS_OK) {
|
||||
LOGE("Error OPUS_SET_BITRATE returned: %s", opus_strerror(result));
|
||||
return 0;
|
||||
|
@ -409,7 +413,6 @@ int initRecorder(const char *path) {
|
|||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int writeFrame(uint8_t *framePcmBytes, uint32_t frameByteCount) {
|
||||
size_t cur_frame_size = frame_size;
|
||||
_packetId++;
|
||||
|
@ -493,10 +496,10 @@ int writeFrame(uint8_t *framePcmBytes, uint32_t frameByteCount) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
JNIEXPORT jint Java_org_telegram_messenger_MediaController_startRecord(JNIEnv *env, jclass class, jstring path) {
|
||||
JNIEXPORT jint Java_org_telegram_messenger_MediaController_startRecord(JNIEnv *env, jclass class, jstring path, jint sampleRate) {
|
||||
const char *pathStr = (*env)->GetStringUTFChars(env, path, 0);
|
||||
|
||||
int32_t result = initRecorder(pathStr);
|
||||
|
||||
int32_t result = initRecorder(pathStr, sampleRate);
|
||||
|
||||
if (pathStr != 0) {
|
||||
(*env)->ReleaseStringUTFChars(env, path, pathStr);
|
||||
|
|
|
@ -742,8 +742,8 @@ JNIEXPORT void Java_org_telegram_messenger_Utilities_stackBlurBitmap(JNIEnv* env
|
|||
const int divsum = SQUARE((div + 1) >> 1);
|
||||
|
||||
// Small buffers
|
||||
int stack[div * 3];
|
||||
zeroClearInt(stack, div * 3);
|
||||
int stack[div * 4];
|
||||
zeroClearInt(stack, div * 4);
|
||||
|
||||
int vmin[MAX(w, h)];
|
||||
zeroClearInt(vmin, MAX(w, h));
|
||||
|
@ -752,9 +752,11 @@ JNIEXPORT void Java_org_telegram_messenger_Utilities_stackBlurBitmap(JNIEnv* env
|
|||
int *r = malloc(wh * sizeof(int));
|
||||
int *g = malloc(wh * sizeof(int));
|
||||
int *b = malloc(wh * sizeof(int));
|
||||
int *a = malloc(wh * sizeof(int));
|
||||
zeroClearInt(r, wh);
|
||||
zeroClearInt(g, wh);
|
||||
zeroClearInt(b, wh);
|
||||
zeroClearInt(a, wh);
|
||||
|
||||
const size_t dvcount = 256 * divsum;
|
||||
int *dv = malloc(sizeof(int) * dvcount);
|
||||
|
@ -766,36 +768,40 @@ JNIEXPORT void Java_org_telegram_messenger_Utilities_stackBlurBitmap(JNIEnv* env
|
|||
// Variables
|
||||
int x, y;
|
||||
int *sir;
|
||||
int routsum, goutsum, boutsum;
|
||||
int rinsum, ginsum, binsum;
|
||||
int rsum, gsum, bsum, p, yp;
|
||||
int routsum, goutsum, boutsum, aoutsum;
|
||||
int rinsum, ginsum, binsum, ainsum;
|
||||
int rsum, gsum, bsum, asum, p, yp;
|
||||
int stackpointer;
|
||||
int stackstart;
|
||||
int rbs;
|
||||
|
||||
int yw = 0, yi = 0;
|
||||
for (y = 0; y < h; y++) {
|
||||
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
|
||||
ainsum = aoutsum = asum = rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
|
||||
|
||||
for (i = -radius; i <= radius; i++) {
|
||||
sir = &stack[(i + radius) * 3];
|
||||
sir = &stack[(i + radius) * 4];
|
||||
int offset = (y * stride + (MIN(wm, MAX(i, 0))) * 4);
|
||||
sir[0] = pixels[offset];
|
||||
sir[1] = pixels[offset + 1];
|
||||
sir[2] = pixels[offset + 2];
|
||||
sir[3] = pixels[offset + 3];
|
||||
|
||||
rbs = r1 - abs(i);
|
||||
rsum += sir[0] * rbs;
|
||||
gsum += sir[1] * rbs;
|
||||
bsum += sir[2] * rbs;
|
||||
asum += sir[3] * rbs;
|
||||
if (i > 0) {
|
||||
rinsum += sir[0];
|
||||
ginsum += sir[1];
|
||||
binsum += sir[2];
|
||||
ainsum += sir[3];
|
||||
} else {
|
||||
routsum += sir[0];
|
||||
goutsum += sir[1];
|
||||
boutsum += sir[2];
|
||||
aoutsum += sir[3];
|
||||
}
|
||||
}
|
||||
stackpointer = radius;
|
||||
|
@ -804,17 +810,20 @@ JNIEXPORT void Java_org_telegram_messenger_Utilities_stackBlurBitmap(JNIEnv* env
|
|||
r[yi] = dv[rsum];
|
||||
g[yi] = dv[gsum];
|
||||
b[yi] = dv[bsum];
|
||||
a[yi] = dv[asum];
|
||||
|
||||
rsum -= routsum;
|
||||
gsum -= goutsum;
|
||||
bsum -= boutsum;
|
||||
asum -= aoutsum;
|
||||
|
||||
stackstart = stackpointer - radius + div;
|
||||
sir = &stack[(stackstart % div) * 3];
|
||||
sir = &stack[(stackstart % div) * 4];
|
||||
|
||||
routsum -= sir[0];
|
||||
goutsum -= sir[1];
|
||||
boutsum -= sir[2];
|
||||
aoutsum -= sir[3];
|
||||
|
||||
if (y == 0) {
|
||||
vmin[x] = MIN(x + radius + 1, wm);
|
||||
|
@ -824,24 +833,29 @@ JNIEXPORT void Java_org_telegram_messenger_Utilities_stackBlurBitmap(JNIEnv* env
|
|||
sir[0] = pixels[offset];
|
||||
sir[1] = pixels[offset + 1];
|
||||
sir[2] = pixels[offset + 2];
|
||||
sir[3] = pixels[offset + 3];
|
||||
rinsum += sir[0];
|
||||
ginsum += sir[1];
|
||||
binsum += sir[2];
|
||||
ainsum += sir[3];
|
||||
|
||||
rsum += rinsum;
|
||||
gsum += ginsum;
|
||||
bsum += binsum;
|
||||
asum += ainsum;
|
||||
|
||||
stackpointer = (stackpointer + 1) % div;
|
||||
sir = &stack[(stackpointer % div) * 3];
|
||||
sir = &stack[(stackpointer % div) * 4];
|
||||
|
||||
routsum += sir[0];
|
||||
goutsum += sir[1];
|
||||
boutsum += sir[2];
|
||||
aoutsum += sir[3];
|
||||
|
||||
rinsum -= sir[0];
|
||||
ginsum -= sir[1];
|
||||
binsum -= sir[2];
|
||||
ainsum -= sir[3];
|
||||
|
||||
yi++;
|
||||
}
|
||||
|
@ -849,31 +863,35 @@ JNIEXPORT void Java_org_telegram_messenger_Utilities_stackBlurBitmap(JNIEnv* env
|
|||
}
|
||||
|
||||
for (x = 0; x < w; x++) {
|
||||
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
|
||||
ainsum = aoutsum = asum = rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
|
||||
yp = -radius * w;
|
||||
for (i = -radius; i <= radius; i++) {
|
||||
yi = MAX(0, yp) + x;
|
||||
|
||||
sir = &stack[(i + radius) * 3];
|
||||
sir = &stack[(i + radius) * 4];
|
||||
|
||||
sir[0] = r[yi];
|
||||
sir[1] = g[yi];
|
||||
sir[2] = b[yi];
|
||||
sir[3] = a[yi];
|
||||
|
||||
rbs = r1 - abs(i);
|
||||
|
||||
rsum += r[yi] * rbs;
|
||||
gsum += g[yi] * rbs;
|
||||
bsum += b[yi] * rbs;
|
||||
asum += a[yi] * rbs;
|
||||
|
||||
if (i > 0) {
|
||||
rinsum += sir[0];
|
||||
ginsum += sir[1];
|
||||
binsum += sir[2];
|
||||
ainsum += sir[3];
|
||||
} else {
|
||||
routsum += sir[0];
|
||||
goutsum += sir[1];
|
||||
boutsum += sir[2];
|
||||
aoutsum += sir[3];
|
||||
}
|
||||
|
||||
if (i < hm) {
|
||||
|
@ -886,16 +904,19 @@ JNIEXPORT void Java_org_telegram_messenger_Utilities_stackBlurBitmap(JNIEnv* env
|
|||
pixels[offset] = dv[rsum];
|
||||
pixels[offset + 1] = dv[gsum];
|
||||
pixels[offset + 2] = dv[bsum];
|
||||
pixels[offset + 3] = dv[asum];
|
||||
rsum -= routsum;
|
||||
gsum -= goutsum;
|
||||
bsum -= boutsum;
|
||||
asum -= aoutsum;
|
||||
|
||||
stackstart = stackpointer - radius + div;
|
||||
sir = &stack[(stackstart % div) * 3];
|
||||
sir = &stack[(stackstart % div) * 4];
|
||||
|
||||
routsum -= sir[0];
|
||||
goutsum -= sir[1];
|
||||
boutsum -= sir[2];
|
||||
aoutsum -= sir[3];
|
||||
|
||||
if (x == 0) {
|
||||
vmin[y] = (MIN(y + r1, hm)) * w;
|
||||
|
@ -905,25 +926,30 @@ JNIEXPORT void Java_org_telegram_messenger_Utilities_stackBlurBitmap(JNIEnv* env
|
|||
sir[0] = r[p];
|
||||
sir[1] = g[p];
|
||||
sir[2] = b[p];
|
||||
sir[3] = a[p];
|
||||
|
||||
rinsum += sir[0];
|
||||
ginsum += sir[1];
|
||||
binsum += sir[2];
|
||||
ainsum += sir[3];
|
||||
|
||||
rsum += rinsum;
|
||||
gsum += ginsum;
|
||||
bsum += binsum;
|
||||
asum += ainsum;
|
||||
|
||||
stackpointer = (stackpointer + 1) % div;
|
||||
sir = &stack[stackpointer * 3];
|
||||
sir = &stack[stackpointer * 4];
|
||||
|
||||
routsum += sir[0];
|
||||
goutsum += sir[1];
|
||||
boutsum += sir[2];
|
||||
aoutsum += sir[3];
|
||||
|
||||
rinsum -= sir[0];
|
||||
ginsum -= sir[1];
|
||||
binsum -= sir[2];
|
||||
ainsum -= sir[3];
|
||||
|
||||
yi += w;
|
||||
}
|
||||
|
@ -932,6 +958,7 @@ JNIEXPORT void Java_org_telegram_messenger_Utilities_stackBlurBitmap(JNIEnv* env
|
|||
free(r);
|
||||
free(g);
|
||||
free(b);
|
||||
free(a);
|
||||
free(dv);
|
||||
AndroidBitmap_unlockPixels(env, bitmap);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <libtgvoip/client/android/org_telegram_messenger_voip_TgVoip.h>
|
||||
#include "image.h"
|
||||
#include "libtgvoip/client/android/tg_voip_jni.h"
|
||||
|
||||
|
@ -35,9 +36,13 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
|||
if (registerNativeTgNetFunctions(vm, env) != JNI_TRUE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* if (tgvoipOnJniLoad(vm, env) != JNI_TRUE) {
|
||||
return -1;
|
||||
}*/
|
||||
|
||||
//tonLibOnLoad(vm, env);
|
||||
tgvoipRegisterNatives(env);
|
||||
//tgvoipRegisterNatives(env);
|
||||
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
||||
|
|
|
@ -1,13 +1,25 @@
|
|||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
LOCAL_MODULE := voip
|
||||
LOCAL_MODULE := tgvoip${TGVOIP_NATIVE_VERSION}
|
||||
LOCAL_CPPFLAGS := -Wall -std=c++11 -DANDROID -finline-functions -ffast-math -Os -fno-strict-aliasing -O3 -frtti -D__STDC_LIMIT_MACROS -Wno-unknown-pragmas
|
||||
LOCAL_CFLAGS := -O3 -DUSE_KISS_FFT -fexceptions -DWEBRTC_APM_DEBUG_DUMP=0 -DWEBRTC_POSIX -DWEBRTC_ANDROID -D__STDC_LIMIT_MACROS -DFIXED_POINT -DWEBRTC_NS_FLOAT
|
||||
LOCAL_EXPORT_LDLIBS := -llog -lOpenSLES
|
||||
LOCAL_CPPFLAGS += -DBSD=1 -funroll-loops
|
||||
LOCAL_CFLAGS := -O3 -DUSE_KISS_FFT -fexceptions -DWEBRTC_APM_DEBUG_DUMP=0 -DWEBRTC_POSIX -DWEBRTC_ANDROID -D__STDC_LIMIT_MACROS -DWEBRTC_NS_FLOAT
|
||||
LOCAL_CFLAGS += -DNULL=0 -DSOCKLEN_T=socklen_t -DLOCALE_NOT_USED -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64
|
||||
LOCAL_CFLAGS += -Drestrict='' -D__EMX__ -DOPUS_BUILD -DFIXED_POINT -DUSE_ALLOCA -DHAVE_LRINT -DHAVE_LRINTF -fno-math-errno
|
||||
LOCAL_LDLIBS := -llog -lOpenSLES
|
||||
LOCAL_STATIC_LIBRARIES := crypto
|
||||
|
||||
MY_DIR := libtgvoip
|
||||
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../opus/include $(LOCAL_PATH)/../boringssl/include/ $(LOCAL_PATH)/webrtc_dsp/
|
||||
LOCAL_C_INCLUDES := \
|
||||
$(LOCAL_PATH)/../opus/include \
|
||||
$(LOCAL_PATH)/../opus/silk \
|
||||
$(LOCAL_PATH)/../opus/silk/fixed \
|
||||
$(LOCAL_PATH)/../opus/celt \
|
||||
$(LOCAL_PATH)/../opus/ \
|
||||
$(LOCAL_PATH)/../opus/opusfile \
|
||||
$(LOCAL_PATH)/../boringssl/include/ \
|
||||
$(LOCAL_PATH)/webrtc_dsp/
|
||||
|
||||
ifeq ($(TARGET_ARCH_ABI),$(filter $(TARGET_ARCH_ABI),armeabi-v7a arm64-v8a))
|
||||
CC_NEON := cc.neon
|
||||
|
@ -20,6 +32,7 @@ LOCAL_CFLAGS += $(TGVOIP_ADDITIONAL_CFLAGS)
|
|||
|
||||
LOCAL_SRC_FILES := \
|
||||
./logging.cpp \
|
||||
./TgVoip.cpp \
|
||||
./VoIPController.cpp \
|
||||
./VoIPGroupController.cpp \
|
||||
./Buffers.cpp \
|
||||
|
@ -50,6 +63,7 @@ LOCAL_SRC_FILES := \
|
|||
./video/ScreamCongestionController.cpp \
|
||||
./os/android/VideoSourceAndroid.cpp \
|
||||
./os/android/VideoRendererAndroid.cpp \
|
||||
./client/android/org_telegram_messenger_voip_TgVoip.cpp \
|
||||
./client/android/tg_voip_jni.cpp
|
||||
|
||||
# WebRTC signal processing
|
||||
|
@ -271,7 +285,6 @@ LOCAL_SRC_FILES += \
|
|||
./webrtc_dsp/common_audio/resampler/sinc_resampler.cc \
|
||||
./webrtc_dsp/common_audio/resampler/sinusoidal_linear_chirp_source.cc \
|
||||
./webrtc_dsp/common_audio/wav_file.cc \
|
||||
./webrtc_dsp/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.c \
|
||||
./webrtc_dsp/common_audio/third_party/fft4g/fft4g.c \
|
||||
./webrtc_dsp/common_audio/audio_converter.cc \
|
||||
./webrtc_dsp/common_audio/real_fourier.cc \
|
||||
|
@ -289,7 +302,6 @@ LOCAL_SRC_FILES += \
|
|||
./webrtc_dsp/common_audio/signal_processing/sqrt_of_one_minus_x_squared.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/downsample_fast.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/splitting_filter1.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/filter_ar_fast_q12.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/spl_init.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/lpc_to_refl_coef.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/cross_correlation.c \
|
||||
|
@ -304,7 +316,6 @@ LOCAL_SRC_FILES += \
|
|||
./webrtc_dsp/common_audio/signal_processing/resample_fractional.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/real_fft.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/ilbc_specific_functions.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/complex_bit_reverse.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/randomization_functions.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/copy_set_operations.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/resample_by_2.c \
|
||||
|
@ -337,6 +348,11 @@ LOCAL_SRC_FILES += \
|
|||
./webrtc_dsp/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor_arm.S.neon \
|
||||
./webrtc_dsp/common_audio/signal_processing/complex_bit_reverse_arm.S.neon \
|
||||
./webrtc_dsp/common_audio/signal_processing/filter_ar_fast_q12_armv7.S.neon
|
||||
else
|
||||
LOCAL_SRC_FILES += \
|
||||
./webrtc_dsp/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/complex_bit_reverse.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/filter_ar_fast_q12.c
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_ARCH_ABI),$(filter $(TARGET_ARCH_ABI),x86 x86_64))
|
||||
|
@ -347,4 +363,198 @@ LOCAL_SRC_FILES += \
|
|||
./webrtc_dsp/common_audio/resampler/sinc_resampler_sse.cc
|
||||
endif
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
# Opus
|
||||
|
||||
LOCAL_SRC_FILES += \
|
||||
./../opus/src/opus.c \
|
||||
./../opus/src/opus_decoder.c \
|
||||
./../opus/src/opus_encoder.c \
|
||||
./../opus/src/opus_multistream.c \
|
||||
./../opus/src/opus_multistream_encoder.c \
|
||||
./../opus/src/opus_multistream_decoder.c \
|
||||
./../opus/src/repacketizer.c \
|
||||
./../opus/src/analysis.c \
|
||||
./../opus/src/mlp.c \
|
||||
./../opus/src/mlp_data.c \
|
||||
./../opus/src/opus_projection_encoder.c \
|
||||
./../opus/src/opus_projection_decoder.c \
|
||||
./../opus/src/mapping_matrix.c
|
||||
|
||||
ifeq ($(TARGET_ARCH_ABI),$(filter $(TARGET_ARCH_ABI),armeabi-v7a arm64-v8a))
|
||||
LOCAL_ARM_MODE := arm
|
||||
LOCAL_CPPFLAGS += -DLIBYUV_NEON
|
||||
LOCAL_CFLAGS += -DLIBYUV_NEON
|
||||
LOCAL_CFLAGS += -DOPUS_HAVE_RTCD -DOPUS_ARM_ASM
|
||||
LOCAL_SRC_FILES += \
|
||||
./../opus/celt/arm/celt_neon_intr.c.neon \
|
||||
./../opus/celt/arm/pitch_neon_intr.c.neon \
|
||||
./../opus/silk/arm/NSQ_neon.c.neon \
|
||||
./../opus/silk/arm/arm_silk_map.c \
|
||||
./../opus/silk/arm/LPC_inv_pred_gain_neon_intr.c.neon \
|
||||
./../opus/silk/arm/NSQ_del_dec_neon_intr.c.neon \
|
||||
./../opus/silk/arm/biquad_alt_neon_intr.c.neon \
|
||||
./../opus/silk/fixed/arm/warped_autocorrelation_FIX_neon_intr.c.neon
|
||||
|
||||
# LOCAL_SRC_FILES += ./../opus/celt/arm/celt_pitch_xcorr_arm-gnu.S
|
||||
|
||||
else
|
||||
ifeq ($(TARGET_ARCH_ABI),x86)
|
||||
LOCAL_CFLAGS += -Dx86fix
|
||||
LOCAL_CPPFLAGS += -Dx86fix
|
||||
LOCAL_ARM_MODE := arm
|
||||
# LOCAL_SRC_FILES += \
|
||||
# ./libyuv/source/row_x86.asm
|
||||
|
||||
# LOCAL_SRC_FILES += \
|
||||
# ./../opus/celt/x86/celt_lpc_sse.c \
|
||||
# ./../opus/celt/x86/pitch_sse.c \
|
||||
# ./../opus/celt/x86/pitch_sse2.c \
|
||||
# ./../opus/celt/x86/pitch_sse4_1.c \
|
||||
# ./../opus/celt/x86/vq_sse2.c \
|
||||
# ./../opus/celt/x86/x86_celt_map.c \
|
||||
# ./../opus/celt/x86/x86cpu.c \
|
||||
# ./../opus/silk/fixed/x86/burg_modified_FIX_sse.c \
|
||||
# ./../opus/silk/fixed/x86/vector_ops_FIX_sse.c \
|
||||
# ./../opus/silk/x86/NSQ_del_dec_sse.c \
|
||||
# ./../opus/silk/x86/NSQ_sse.c \
|
||||
# ./../opus/silk/x86/VAD_sse.c \
|
||||
# ./../opus/silk/x86/VQ_WMat_sse.c \
|
||||
# ./../opus/silk/x86/x86_silk_map.c
|
||||
endif
|
||||
endif
|
||||
|
||||
LOCAL_SRC_FILES += \
|
||||
./../opus/silk/CNG.c \
|
||||
./../opus/silk/code_signs.c \
|
||||
./../opus/silk/init_decoder.c \
|
||||
./../opus/silk/decode_core.c \
|
||||
./../opus/silk/decode_frame.c \
|
||||
./../opus/silk/decode_parameters.c \
|
||||
./../opus/silk/decode_indices.c \
|
||||
./../opus/silk/decode_pulses.c \
|
||||
./../opus/silk/decoder_set_fs.c \
|
||||
./../opus/silk/dec_API.c \
|
||||
./../opus/silk/enc_API.c \
|
||||
./../opus/silk/encode_indices.c \
|
||||
./../opus/silk/encode_pulses.c \
|
||||
./../opus/silk/gain_quant.c \
|
||||
./../opus/silk/interpolate.c \
|
||||
./../opus/silk/LP_variable_cutoff.c \
|
||||
./../opus/silk/NLSF_decode.c \
|
||||
./../opus/silk/NSQ.c \
|
||||
./../opus/silk/NSQ_del_dec.c \
|
||||
./../opus/silk/PLC.c \
|
||||
./../opus/silk/shell_coder.c \
|
||||
./../opus/silk/tables_gain.c \
|
||||
./../opus/silk/tables_LTP.c \
|
||||
./../opus/silk/tables_NLSF_CB_NB_MB.c \
|
||||
./../opus/silk/tables_NLSF_CB_WB.c \
|
||||
./../opus/silk/tables_other.c \
|
||||
./../opus/silk/tables_pitch_lag.c \
|
||||
./../opus/silk/tables_pulses_per_block.c \
|
||||
./../opus/silk/VAD.c \
|
||||
./../opus/silk/control_audio_bandwidth.c \
|
||||
./../opus/silk/quant_LTP_gains.c \
|
||||
./../opus/silk/VQ_WMat_EC.c \
|
||||
./../opus/silk/HP_variable_cutoff.c \
|
||||
./../opus/silk/NLSF_encode.c \
|
||||
./../opus/silk/NLSF_VQ.c \
|
||||
./../opus/silk/NLSF_unpack.c \
|
||||
./../opus/silk/NLSF_del_dec_quant.c \
|
||||
./../opus/silk/process_NLSFs.c \
|
||||
./../opus/silk/stereo_LR_to_MS.c \
|
||||
./../opus/silk/stereo_MS_to_LR.c \
|
||||
./../opus/silk/check_control_input.c \
|
||||
./../opus/silk/control_SNR.c \
|
||||
./../opus/silk/init_encoder.c \
|
||||
./../opus/silk/control_codec.c \
|
||||
./../opus/silk/A2NLSF.c \
|
||||
./../opus/silk/ana_filt_bank_1.c \
|
||||
./../opus/silk/biquad_alt.c \
|
||||
./../opus/silk/bwexpander_32.c \
|
||||
./../opus/silk/bwexpander.c \
|
||||
./../opus/silk/debug.c \
|
||||
./../opus/silk/decode_pitch.c \
|
||||
./../opus/silk/inner_prod_aligned.c \
|
||||
./../opus/silk/lin2log.c \
|
||||
./../opus/silk/log2lin.c \
|
||||
./../opus/silk/LPC_analysis_filter.c \
|
||||
./../opus/silk/LPC_inv_pred_gain.c \
|
||||
./../opus/silk/table_LSF_cos.c \
|
||||
./../opus/silk/NLSF2A.c \
|
||||
./../opus/silk/NLSF_stabilize.c \
|
||||
./../opus/silk/NLSF_VQ_weights_laroia.c \
|
||||
./../opus/silk/pitch_est_tables.c \
|
||||
./../opus/silk/resampler.c \
|
||||
./../opus/silk/resampler_down2_3.c \
|
||||
./../opus/silk/resampler_down2.c \
|
||||
./../opus/silk/resampler_private_AR2.c \
|
||||
./../opus/silk/resampler_private_down_FIR.c \
|
||||
./../opus/silk/resampler_private_IIR_FIR.c \
|
||||
./../opus/silk/resampler_private_up2_HQ.c \
|
||||
./../opus/silk/resampler_rom.c \
|
||||
./../opus/silk/sigm_Q15.c \
|
||||
./../opus/silk/sort.c \
|
||||
./../opus/silk/sum_sqr_shift.c \
|
||||
./../opus/silk/stereo_decode_pred.c \
|
||||
./../opus/silk/stereo_encode_pred.c \
|
||||
./../opus/silk/stereo_find_predictor.c \
|
||||
./../opus/silk/stereo_quant_pred.c \
|
||||
./../opus/silk/LPC_fit.c
|
||||
|
||||
LOCAL_SRC_FILES += \
|
||||
./../opus/silk/fixed/LTP_analysis_filter_FIX.c \
|
||||
./../opus/silk/fixed/LTP_scale_ctrl_FIX.c \
|
||||
./../opus/silk/fixed/corrMatrix_FIX.c \
|
||||
./../opus/silk/fixed/encode_frame_FIX.c \
|
||||
./../opus/silk/fixed/find_LPC_FIX.c \
|
||||
./../opus/silk/fixed/find_LTP_FIX.c \
|
||||
./../opus/silk/fixed/find_pitch_lags_FIX.c \
|
||||
./../opus/silk/fixed/find_pred_coefs_FIX.c \
|
||||
./../opus/silk/fixed/noise_shape_analysis_FIX.c \
|
||||
./../opus/silk/fixed/process_gains_FIX.c \
|
||||
./../opus/silk/fixed/regularize_correlations_FIX.c \
|
||||
./../opus/silk/fixed/residual_energy16_FIX.c \
|
||||
./../opus/silk/fixed/residual_energy_FIX.c \
|
||||
./../opus/silk/fixed/warped_autocorrelation_FIX.c \
|
||||
./../opus/silk/fixed/apply_sine_window_FIX.c \
|
||||
./../opus/silk/fixed/autocorr_FIX.c \
|
||||
./../opus/silk/fixed/burg_modified_FIX.c \
|
||||
./../opus/silk/fixed/k2a_FIX.c \
|
||||
./../opus/silk/fixed/k2a_Q16_FIX.c \
|
||||
./../opus/silk/fixed/pitch_analysis_core_FIX.c \
|
||||
./../opus/silk/fixed/vector_ops_FIX.c \
|
||||
./../opus/silk/fixed/schur64_FIX.c \
|
||||
./../opus/silk/fixed/schur_FIX.c
|
||||
|
||||
LOCAL_SRC_FILES += \
|
||||
./../opus/celt/bands.c \
|
||||
./../opus/celt/celt.c \
|
||||
./../opus/celt/celt_encoder.c \
|
||||
./../opus/celt/celt_decoder.c \
|
||||
./../opus/celt/cwrs.c \
|
||||
./../opus/celt/entcode.c \
|
||||
./../opus/celt/entdec.c \
|
||||
./../opus/celt/entenc.c \
|
||||
./../opus/celt/kiss_fft.c \
|
||||
./../opus/celt/laplace.c \
|
||||
./../opus/celt/mathops.c \
|
||||
./../opus/celt/mdct.c \
|
||||
./../opus/celt/modes.c \
|
||||
./../opus/celt/pitch.c \
|
||||
./../opus/celt/celt_lpc.c \
|
||||
./../opus/celt/quant_bands.c \
|
||||
./../opus/celt/rate.c \
|
||||
./../opus/celt/vq.c \
|
||||
./../opus/celt/arm/armcpu.c \
|
||||
./../opus/celt/arm/arm_celt_map.c
|
||||
|
||||
LOCAL_SRC_FILES += \
|
||||
./../opus/ogg/bitwise.c \
|
||||
./../opus/ogg/framing.c \
|
||||
./../opus/opusfile/info.c \
|
||||
./../opus/opusfile/internal.c \
|
||||
./../opus/opusfile/opusfile.c \
|
||||
./../opus/opusfile/stream.c
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
|
@ -96,6 +96,7 @@ EchoCanceller::~EchoCanceller(){
|
|||
#ifndef TGVOIP_NO_DSP
|
||||
delete apm;
|
||||
delete audioFrame;
|
||||
delete farendBufferPool;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,8 @@ CFLAGS = -Wall -DHAVE_CONFIG_H -Wno-unknown-pragmas
|
|||
|
||||
lib_LTLIBRARIES = libtgvoip.la
|
||||
|
||||
SRC = VoIPController.cpp \
|
||||
SRC = TgVoip.cpp \
|
||||
VoIPController.cpp \
|
||||
Buffers.cpp \
|
||||
CongestionControl.cpp \
|
||||
EchoCanceller.cpp \
|
||||
|
@ -29,6 +30,7 @@ video/ScreamCongestionController.cpp \
|
|||
json11.cpp
|
||||
|
||||
TGVOIP_HDRS = \
|
||||
TgVoip.h \
|
||||
VoIPController.h \
|
||||
Buffers.h \
|
||||
BlockingQueue.h \
|
||||
|
|
|
@ -808,11 +808,11 @@ am__installdirs = "$(DESTDIR)$(libdir)" \
|
|||
"$(DESTDIR)$(tgvoipincludedir)"
|
||||
LTLIBRARIES = $(lib_LTLIBRARIES)
|
||||
libtgvoip_la_LIBADD =
|
||||
am__libtgvoip_la_SOURCES_DIST = VoIPController.cpp Buffers.cpp \
|
||||
CongestionControl.cpp EchoCanceller.cpp JitterBuffer.cpp \
|
||||
logging.cpp MediaStreamItf.cpp MessageThread.cpp \
|
||||
NetworkSocket.cpp OpusDecoder.cpp OpusEncoder.cpp \
|
||||
PacketReassembler.cpp VoIPGroupController.cpp \
|
||||
am__libtgvoip_la_SOURCES_DIST = TgVoip.cpp VoIPController.cpp \
|
||||
Buffers.cpp CongestionControl.cpp EchoCanceller.cpp \
|
||||
JitterBuffer.cpp logging.cpp MediaStreamItf.cpp \
|
||||
MessageThread.cpp NetworkSocket.cpp OpusDecoder.cpp \
|
||||
OpusEncoder.cpp PacketReassembler.cpp VoIPGroupController.cpp \
|
||||
VoIPServerConfig.cpp audio/AudioIO.cpp audio/AudioInput.cpp \
|
||||
audio/AudioOutput.cpp audio/Resampler.cpp \
|
||||
os/posix/NetworkSocketPosix.cpp video/VideoSource.cpp \
|
||||
|
@ -1421,16 +1421,16 @@ am__libtgvoip_la_SOURCES_DIST = VoIPController.cpp Buffers.cpp \
|
|||
webrtc_dsp/common_audio/vad/include/webrtc_vad.h \
|
||||
webrtc_dsp/common_audio/vad/vad_gmm.h \
|
||||
webrtc_dsp/common_audio/vad/vad_sp.h \
|
||||
webrtc_dsp/common_audio/vad/vad_filterbank.h VoIPController.h \
|
||||
Buffers.h BlockingQueue.h PrivateDefines.h CongestionControl.h \
|
||||
EchoCanceller.h JitterBuffer.h logging.h threading.h \
|
||||
MediaStreamItf.h MessageThread.h NetworkSocket.h OpusDecoder.h \
|
||||
OpusEncoder.h PacketReassembler.h VoIPServerConfig.h \
|
||||
audio/AudioIO.h audio/AudioInput.h audio/AudioOutput.h \
|
||||
audio/Resampler.h os/posix/NetworkSocketPosix.h \
|
||||
video/VideoSource.h video/VideoRenderer.h \
|
||||
video/ScreamCongestionController.h json11.hpp utils.h \
|
||||
os/darwin/AudioInputAudioUnit.h \
|
||||
webrtc_dsp/common_audio/vad/vad_filterbank.h TgVoip.h \
|
||||
VoIPController.h Buffers.h BlockingQueue.h PrivateDefines.h \
|
||||
CongestionControl.h EchoCanceller.h JitterBuffer.h logging.h \
|
||||
threading.h MediaStreamItf.h MessageThread.h NetworkSocket.h \
|
||||
OpusDecoder.h OpusEncoder.h PacketReassembler.h \
|
||||
VoIPServerConfig.h audio/AudioIO.h audio/AudioInput.h \
|
||||
audio/AudioOutput.h audio/Resampler.h \
|
||||
os/posix/NetworkSocketPosix.h video/VideoSource.h \
|
||||
video/VideoRenderer.h video/ScreamCongestionController.h \
|
||||
json11.hpp utils.h os/darwin/AudioInputAudioUnit.h \
|
||||
os/darwin/AudioOutputAudioUnit.h os/darwin/AudioUnitIO.h \
|
||||
os/darwin/AudioInputAudioUnitOSX.h \
|
||||
os/darwin/AudioOutputAudioUnitOSX.h os/darwin/DarwinSpecific.h \
|
||||
|
@ -1736,12 +1736,12 @@ am__dirstamp = $(am__leading_dot)dirstamp
|
|||
@ENABLE_DSP_TRUE@@TARGET_CPU_ARM_FALSE@am__objects_10 = webrtc_dsp/common_audio/signal_processing/complex_bit_reverse.lo \
|
||||
@ENABLE_DSP_TRUE@@TARGET_CPU_ARM_FALSE@ webrtc_dsp/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.lo
|
||||
am__objects_11 =
|
||||
am__objects_12 = VoIPController.lo Buffers.lo CongestionControl.lo \
|
||||
EchoCanceller.lo JitterBuffer.lo logging.lo MediaStreamItf.lo \
|
||||
MessageThread.lo NetworkSocket.lo OpusDecoder.lo \
|
||||
OpusEncoder.lo PacketReassembler.lo VoIPGroupController.lo \
|
||||
VoIPServerConfig.lo audio/AudioIO.lo audio/AudioInput.lo \
|
||||
audio/AudioOutput.lo audio/Resampler.lo \
|
||||
am__objects_12 = TgVoip.lo VoIPController.lo Buffers.lo \
|
||||
CongestionControl.lo EchoCanceller.lo JitterBuffer.lo \
|
||||
logging.lo MediaStreamItf.lo MessageThread.lo NetworkSocket.lo \
|
||||
OpusDecoder.lo OpusEncoder.lo PacketReassembler.lo \
|
||||
VoIPGroupController.lo VoIPServerConfig.lo audio/AudioIO.lo \
|
||||
audio/AudioInput.lo audio/AudioOutput.lo audio/Resampler.lo \
|
||||
os/posix/NetworkSocketPosix.lo video/VideoSource.lo \
|
||||
video/VideoRenderer.lo video/ScreamCongestionController.lo \
|
||||
json11.lo $(am__objects_1) $(am__objects_2) $(am__objects_3) \
|
||||
|
@ -1777,7 +1777,7 @@ am__depfiles_remade = ./$(DEPDIR)/Buffers.Plo \
|
|||
./$(DEPDIR)/MediaStreamItf.Plo ./$(DEPDIR)/MessageThread.Plo \
|
||||
./$(DEPDIR)/NetworkSocket.Plo ./$(DEPDIR)/OpusDecoder.Plo \
|
||||
./$(DEPDIR)/OpusEncoder.Plo ./$(DEPDIR)/PacketReassembler.Plo \
|
||||
./$(DEPDIR)/VoIPController.Plo \
|
||||
./$(DEPDIR)/TgVoip.Plo ./$(DEPDIR)/VoIPController.Plo \
|
||||
./$(DEPDIR)/VoIPGroupController.Plo \
|
||||
./$(DEPDIR)/VoIPServerConfig.Plo ./$(DEPDIR)/json11.Plo \
|
||||
./$(DEPDIR)/logging.Plo \
|
||||
|
@ -2153,8 +2153,8 @@ am__can_run_installinfo = \
|
|||
n|no|NO) false;; \
|
||||
*) (install-info --version) >/dev/null 2>&1;; \
|
||||
esac
|
||||
am__nobase_tgvoipinclude_HEADERS_DIST = VoIPController.h Buffers.h \
|
||||
BlockingQueue.h PrivateDefines.h CongestionControl.h \
|
||||
am__nobase_tgvoipinclude_HEADERS_DIST = TgVoip.h VoIPController.h \
|
||||
Buffers.h BlockingQueue.h PrivateDefines.h CongestionControl.h \
|
||||
EchoCanceller.h JitterBuffer.h logging.h threading.h \
|
||||
MediaStreamItf.h MessageThread.h NetworkSocket.h OpusDecoder.h \
|
||||
OpusEncoder.h PacketReassembler.h VoIPServerConfig.h \
|
||||
|
@ -2347,7 +2347,7 @@ top_builddir = @top_builddir@
|
|||
top_srcdir = @top_srcdir@
|
||||
AUTOMAKE_OPTIONS = foreign
|
||||
lib_LTLIBRARIES = libtgvoip.la
|
||||
SRC = VoIPController.cpp Buffers.cpp CongestionControl.cpp \
|
||||
SRC = TgVoip.cpp VoIPController.cpp Buffers.cpp CongestionControl.cpp \
|
||||
EchoCanceller.cpp JitterBuffer.cpp logging.cpp \
|
||||
MediaStreamItf.cpp MessageThread.cpp NetworkSocket.cpp \
|
||||
OpusDecoder.cpp OpusEncoder.cpp PacketReassembler.cpp \
|
||||
|
@ -2359,7 +2359,7 @@ SRC = VoIPController.cpp Buffers.cpp CongestionControl.cpp \
|
|||
$(am__append_10) $(am__append_12) $(am__append_14) \
|
||||
$(am__append_16) $(am__append_18) $(am__append_21) \
|
||||
$(am__append_22) $(am__append_23)
|
||||
TGVOIP_HDRS = VoIPController.h Buffers.h BlockingQueue.h \
|
||||
TGVOIP_HDRS = TgVoip.h VoIPController.h Buffers.h BlockingQueue.h \
|
||||
PrivateDefines.h CongestionControl.h EchoCanceller.h \
|
||||
JitterBuffer.h logging.h threading.h MediaStreamItf.h \
|
||||
MessageThread.h NetworkSocket.h OpusDecoder.h OpusEncoder.h \
|
||||
|
@ -3638,6 +3638,7 @@ distclean-compile:
|
|||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/OpusDecoder.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/OpusEncoder.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PacketReassembler.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TgVoip.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/VoIPController.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/VoIPGroupController.Plo@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/VoIPServerConfig.Plo@am__quote@ # am--include-marker
|
||||
|
@ -4506,6 +4507,7 @@ distclean: distclean-am
|
|||
-rm -f ./$(DEPDIR)/OpusDecoder.Plo
|
||||
-rm -f ./$(DEPDIR)/OpusEncoder.Plo
|
||||
-rm -f ./$(DEPDIR)/PacketReassembler.Plo
|
||||
-rm -f ./$(DEPDIR)/TgVoip.Plo
|
||||
-rm -f ./$(DEPDIR)/VoIPController.Plo
|
||||
-rm -f ./$(DEPDIR)/VoIPGroupController.Plo
|
||||
-rm -f ./$(DEPDIR)/VoIPServerConfig.Plo
|
||||
|
@ -4869,6 +4871,7 @@ maintainer-clean: maintainer-clean-am
|
|||
-rm -f ./$(DEPDIR)/OpusDecoder.Plo
|
||||
-rm -f ./$(DEPDIR)/OpusEncoder.Plo
|
||||
-rm -f ./$(DEPDIR)/PacketReassembler.Plo
|
||||
-rm -f ./$(DEPDIR)/TgVoip.Plo
|
||||
-rm -f ./$(DEPDIR)/VoIPController.Plo
|
||||
-rm -f ./$(DEPDIR)/VoIPGroupController.Plo
|
||||
-rm -f ./$(DEPDIR)/VoIPServerConfig.Plo
|
||||
|
|
|
@ -364,8 +364,8 @@ bool NetworkSocketTCPObfuscated::IsFailed(){
|
|||
NetworkSocketSOCKS5Proxy::NetworkSocketSOCKS5Proxy(NetworkSocket *tcp, NetworkSocket *udp, std::string username, std::string password) : NetworkSocketWrapper(udp ? PROTO_UDP : PROTO_TCP){
|
||||
this->tcp=tcp;
|
||||
this->udp=udp;
|
||||
this->username=username;
|
||||
this->password=password;
|
||||
this->username=std::move(username);
|
||||
this->password=std::move(password);
|
||||
connectedAddress=NULL;
|
||||
}
|
||||
|
||||
|
|
433
TMessagesProj/jni/libtgvoip/TgVoip.cpp
Normal file
433
TMessagesProj/jni/libtgvoip/TgVoip.cpp
Normal file
|
@ -0,0 +1,433 @@
|
|||
#include "TgVoip.h"
|
||||
|
||||
#include "VoIPController.h"
|
||||
#include "VoIPServerConfig.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifndef TGVOIP_USE_CUSTOM_CRYPTO
|
||||
extern "C" {
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/aes.h>
|
||||
//#include <openssl/modes.h>
|
||||
#include <openssl/rand.h>
|
||||
}
|
||||
|
||||
void tgvoip_openssl_aes_ige_encrypt(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv){
|
||||
AES_KEY akey;
|
||||
AES_set_encrypt_key(key, 32*8, &akey);
|
||||
AES_ige_encrypt(in, out, length, &akey, iv, AES_ENCRYPT);
|
||||
}
|
||||
|
||||
void tgvoip_openssl_aes_ige_decrypt(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv){
|
||||
AES_KEY akey;
|
||||
AES_set_decrypt_key(key, 32*8, &akey);
|
||||
AES_ige_encrypt(in, out, length, &akey, iv, AES_DECRYPT);
|
||||
}
|
||||
|
||||
void tgvoip_openssl_rand_bytes(uint8_t* buffer, size_t len){
|
||||
RAND_bytes(buffer, len);
|
||||
}
|
||||
|
||||
void tgvoip_openssl_sha1(uint8_t* msg, size_t len, uint8_t* output){
|
||||
SHA1(msg, len, output);
|
||||
}
|
||||
|
||||
void tgvoip_openssl_sha256(uint8_t* msg, size_t len, uint8_t* output){
|
||||
SHA256(msg, len, output);
|
||||
}
|
||||
|
||||
void tgvoip_openssl_aes_ctr_encrypt(uint8_t* inout, size_t length, uint8_t* key, uint8_t* iv, uint8_t* ecount, uint32_t* num){
|
||||
AES_KEY akey;
|
||||
AES_set_encrypt_key(key, 32*8, &akey);
|
||||
AES_ctr128_encrypt(inout, inout, length, &akey, iv, ecount, num);
|
||||
}
|
||||
|
||||
void tgvoip_openssl_aes_cbc_encrypt(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv){
|
||||
AES_KEY akey;
|
||||
AES_set_encrypt_key(key, 256, &akey);
|
||||
AES_cbc_encrypt(in, out, length, &akey, iv, AES_ENCRYPT);
|
||||
}
|
||||
|
||||
void tgvoip_openssl_aes_cbc_decrypt(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv){
|
||||
AES_KEY akey;
|
||||
AES_set_decrypt_key(key, 256, &akey);
|
||||
AES_cbc_encrypt(in, out, length, &akey, iv, AES_DECRYPT);
|
||||
}
|
||||
|
||||
|
||||
tgvoip::CryptoFunctions tgvoip::VoIPController::crypto={
|
||||
tgvoip_openssl_rand_bytes,
|
||||
tgvoip_openssl_sha1,
|
||||
tgvoip_openssl_sha256,
|
||||
tgvoip_openssl_aes_ige_encrypt,
|
||||
tgvoip_openssl_aes_ige_decrypt,
|
||||
tgvoip_openssl_aes_ctr_encrypt,
|
||||
tgvoip_openssl_aes_cbc_encrypt,
|
||||
tgvoip_openssl_aes_cbc_decrypt
|
||||
};
|
||||
#else
|
||||
struct TgVoipCrypto {
|
||||
void (*rand_bytes)(uint8_t* buffer, size_t length);
|
||||
void (*sha1)(uint8_t* msg, size_t length, uint8_t* output);
|
||||
void (*sha256)(uint8_t* msg, size_t length, uint8_t* output);
|
||||
void (*aes_ige_encrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv);
|
||||
void (*aes_ige_decrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv);
|
||||
void (*aes_ctr_encrypt)(uint8_t* inout, size_t length, uint8_t* key, uint8_t* iv, uint8_t* ecount, uint32_t* num);
|
||||
void (*aes_cbc_encrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv);
|
||||
void (*aes_cbc_decrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv);
|
||||
};
|
||||
tgvoip::CryptoFunctions tgvoip::VoIPController::crypto; // set it yourself upon initialization
|
||||
#endif
|
||||
|
||||
|
||||
class TgVoipImpl : public TgVoip {
|
||||
private:
|
||||
tgvoip::VoIPController *controller_;
|
||||
std::function<void(TgVoipState)> onStateUpdated_;
|
||||
std::function<void(int)> onSignalBarsUpdated_;
|
||||
public:
|
||||
TgVoipImpl(
|
||||
std::vector<TgVoipEndpoint> const &endpoints,
|
||||
TgVoipPersistentState const &persistentState,
|
||||
std::unique_ptr<TgVoipProxy> const &proxy,
|
||||
TgVoipConfig const &config,
|
||||
TgVoipEncryptionKey const &encryptionKey,
|
||||
TgVoipNetworkType initialNetworkType
|
||||
#ifdef TGVOIP_USE_CUSTOM_CRYPTO
|
||||
,
|
||||
TgVoipCrypto const &crypto
|
||||
#endif
|
||||
#ifdef TGVOIP_USE_CALLBACK_AUDIO_IO
|
||||
,
|
||||
TgVoipAudioDataCallbacks const &audioDataCallbacks
|
||||
#endif
|
||||
) {
|
||||
#ifdef TGVOIP_USE_CUSTOM_CRYPTO
|
||||
tgvoip::VoIPController::crypto.sha1 = crypto.sha1;
|
||||
tgvoip::VoIPController::crypto.sha256 = crypto.sha256;
|
||||
tgvoip::VoIPController::crypto.rand_bytes = crypto.rand_bytes;
|
||||
tgvoip::VoIPController::crypto.aes_ige_encrypt = crypto.aes_ige_encrypt;
|
||||
tgvoip::VoIPController::crypto.aes_ige_decrypt = crypto.aes_ige_decrypt;
|
||||
tgvoip::VoIPController::crypto.aes_ctr_encrypt = crypto.aes_ctr_encrypt;
|
||||
#endif
|
||||
|
||||
controller_ = new tgvoip::VoIPController();
|
||||
controller_->implData = this;
|
||||
|
||||
#ifdef TGVOIP_USE_CALLBACK_AUDIO_IO
|
||||
controller_->SetAudioDataCallbacks(audioDataCallbacks.input, audioDataCallbacks.output, audioDataCallbacks.preprocessed);
|
||||
#endif
|
||||
|
||||
controller_->SetPersistentState(persistentState.value);
|
||||
|
||||
if (proxy != nullptr) {
|
||||
controller_->SetProxy(tgvoip::PROXY_SOCKS5, proxy->host, proxy->port, proxy->login, proxy->password);
|
||||
}
|
||||
|
||||
auto callbacks = tgvoip::VoIPController::Callbacks();
|
||||
callbacks.connectionStateChanged = &TgVoipImpl::controllerStateCallback;
|
||||
callbacks.groupCallKeyReceived = nullptr;
|
||||
callbacks.groupCallKeySent = nullptr;
|
||||
callbacks.signalBarCountChanged = &TgVoipImpl::signalBarsCallback;
|
||||
callbacks.upgradeToGroupCallRequested = nullptr;
|
||||
controller_->SetCallbacks(callbacks);
|
||||
|
||||
std::vector<tgvoip::Endpoint> mappedEndpoints;
|
||||
for (auto endpoint : endpoints) {
|
||||
bool isIpv6 = false;
|
||||
struct in6_addr addrIpV6;
|
||||
if (inet_pton(AF_INET6, endpoint.host.c_str(), &addrIpV6)) {
|
||||
isIpv6 = true;
|
||||
}
|
||||
|
||||
tgvoip::Endpoint::Type mappedType;
|
||||
switch (endpoint.type) {
|
||||
case TgVoipEndpointType::UdpRelay:
|
||||
mappedType = tgvoip::Endpoint::Type::UDP_RELAY;
|
||||
break;
|
||||
case TgVoipEndpointType::Lan:
|
||||
mappedType = tgvoip::Endpoint::Type::UDP_P2P_LAN;
|
||||
break;
|
||||
case TgVoipEndpointType::Inet:
|
||||
mappedType = tgvoip::Endpoint::Type::UDP_P2P_INET;
|
||||
break;
|
||||
case TgVoipEndpointType::TcpRelay:
|
||||
mappedType = tgvoip::Endpoint::Type::TCP_RELAY;
|
||||
break;
|
||||
default:
|
||||
mappedType = tgvoip::Endpoint::Type::UDP_RELAY;
|
||||
break;
|
||||
}
|
||||
|
||||
tgvoip::IPv4Address address(isIpv6 ? std::string() : endpoint.host);
|
||||
tgvoip::IPv6Address addressv6(isIpv6 ? endpoint.host : std::string());
|
||||
|
||||
mappedEndpoints.emplace_back(endpoint.endpointId, endpoint.port, address, addressv6, mappedType, endpoint.peerTag);
|
||||
}
|
||||
|
||||
int mappedDataSaving;
|
||||
switch (config.dataSaving) {
|
||||
case TgVoipDataSaving::Mobile:
|
||||
mappedDataSaving = tgvoip::DATA_SAVING_MOBILE;
|
||||
break;
|
||||
case TgVoipDataSaving::Always:
|
||||
mappedDataSaving = tgvoip::DATA_SAVING_ALWAYS;
|
||||
break;
|
||||
default:
|
||||
mappedDataSaving = tgvoip::DATA_SAVING_NEVER;
|
||||
break;
|
||||
}
|
||||
|
||||
tgvoip::VoIPController::Config mappedConfig(
|
||||
config.initializationTimeout,
|
||||
config.receiveTimeout,
|
||||
mappedDataSaving,
|
||||
config.enableAEC,
|
||||
config.enableNS,
|
||||
config.enableAGC,
|
||||
config.enableCallUpgrade
|
||||
);
|
||||
mappedConfig.logFilePath = config.logPath;
|
||||
mappedConfig.statsDumpFilePath = "";
|
||||
|
||||
controller_->SetConfig(mappedConfig);
|
||||
|
||||
setNetworkType(initialNetworkType);
|
||||
|
||||
std::vector<uint8_t> encryptionKeyValue = encryptionKey.value;
|
||||
controller_->SetEncryptionKey((char *)(encryptionKeyValue.data()), encryptionKey.isOutgoing);
|
||||
controller_->SetRemoteEndpoints(mappedEndpoints, config.enableP2P, config.maxApiLayer);
|
||||
|
||||
controller_->Start();
|
||||
|
||||
controller_->Connect();
|
||||
}
|
||||
|
||||
~TgVoipImpl() override = default;
|
||||
|
||||
void setOnStateUpdated(std::function<void(TgVoipState)> onStateUpdated) override {
|
||||
onStateUpdated_ = onStateUpdated;
|
||||
}
|
||||
|
||||
void setOnSignalBarsUpdated(std::function<void(int)> onSignalBarsUpdated) override {
|
||||
onSignalBarsUpdated_ = onSignalBarsUpdated;
|
||||
}
|
||||
|
||||
void setNetworkType(TgVoipNetworkType networkType) override {
|
||||
int mappedType;
|
||||
|
||||
switch (networkType) {
|
||||
case TgVoipNetworkType::Unknown:
|
||||
mappedType = tgvoip::NET_TYPE_UNKNOWN;
|
||||
break;
|
||||
case TgVoipNetworkType::Gprs:
|
||||
mappedType = tgvoip::NET_TYPE_GPRS;
|
||||
break;
|
||||
case TgVoipNetworkType::Edge:
|
||||
mappedType = tgvoip::NET_TYPE_EDGE;
|
||||
break;
|
||||
case TgVoipNetworkType::ThirdGeneration:
|
||||
mappedType = tgvoip::NET_TYPE_3G;
|
||||
break;
|
||||
case TgVoipNetworkType::Hspa:
|
||||
mappedType = tgvoip::NET_TYPE_HSPA;
|
||||
break;
|
||||
case TgVoipNetworkType::Lte:
|
||||
mappedType = tgvoip::NET_TYPE_LTE;
|
||||
break;
|
||||
case TgVoipNetworkType::WiFi:
|
||||
mappedType = tgvoip::NET_TYPE_WIFI;
|
||||
break;
|
||||
case TgVoipNetworkType::Ethernet:
|
||||
mappedType = tgvoip::NET_TYPE_ETHERNET;
|
||||
break;
|
||||
case TgVoipNetworkType::OtherHighSpeed:
|
||||
mappedType = tgvoip::NET_TYPE_OTHER_HIGH_SPEED;
|
||||
break;
|
||||
case TgVoipNetworkType::OtherLowSpeed:
|
||||
mappedType = tgvoip::NET_TYPE_OTHER_LOW_SPEED;
|
||||
break;
|
||||
case TgVoipNetworkType::OtherMobile:
|
||||
mappedType = tgvoip::NET_TYPE_OTHER_MOBILE;
|
||||
break;
|
||||
case TgVoipNetworkType::Dialup:
|
||||
mappedType = tgvoip::NET_TYPE_DIALUP;
|
||||
break;
|
||||
default:
|
||||
mappedType = tgvoip::NET_TYPE_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
controller_->SetNetworkType(mappedType);
|
||||
}
|
||||
|
||||
void setMuteMicrophone(bool muteMicrophone) override {
|
||||
controller_->SetMicMute(muteMicrophone);
|
||||
}
|
||||
|
||||
void setAudioOutputGainControlEnabled(bool enabled) override {
|
||||
controller_->SetAudioOutputGainControlEnabled(enabled);
|
||||
}
|
||||
|
||||
void setEchoCancellationStrength(int strength) override {
|
||||
controller_->SetEchoCancellationStrength(strength);
|
||||
}
|
||||
|
||||
std::string getLastError() override {
|
||||
switch (controller_->GetLastError()) {
|
||||
case tgvoip::ERROR_INCOMPATIBLE: return "ERROR_INCOMPATIBLE";
|
||||
case tgvoip::ERROR_TIMEOUT: return "ERROR_TIMEOUT";
|
||||
case tgvoip::ERROR_AUDIO_IO: return "ERROR_AUDIO_IO";
|
||||
case tgvoip::ERROR_PROXY: return "ERROR_PROXY";
|
||||
default: return "ERROR_UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
std::string getDebugInfo() override {
|
||||
return controller_->GetDebugString();
|
||||
}
|
||||
|
||||
int64_t getPreferredRelayId() override {
|
||||
return controller_->GetPreferredRelayID();
|
||||
}
|
||||
|
||||
TgVoipTrafficStats getTrafficStats() override {
|
||||
tgvoip::VoIPController::TrafficStats stats;
|
||||
controller_->GetStats(&stats);
|
||||
return {
|
||||
.bytesSentWifi = stats.bytesSentWifi,
|
||||
.bytesReceivedWifi = stats.bytesRecvdWifi,
|
||||
.bytesSentMobile = stats.bytesSentMobile,
|
||||
.bytesReceivedMobile = stats.bytesRecvdMobile
|
||||
};
|
||||
}
|
||||
|
||||
TgVoipPersistentState getPersistentState() override {
|
||||
return {controller_->GetPersistentState()};
|
||||
}
|
||||
|
||||
TgVoipFinalState stop() override {
|
||||
controller_->Stop();
|
||||
|
||||
TgVoipFinalState finalState = {
|
||||
.trafficStats = getTrafficStats(),
|
||||
.persistentState = getPersistentState(),
|
||||
.debugLog = controller_->GetDebugLog(),
|
||||
.isRatingSuggested = controller_->NeedRate()
|
||||
};
|
||||
|
||||
delete controller_;
|
||||
controller_ = nullptr;
|
||||
|
||||
return finalState;
|
||||
}
|
||||
|
||||
static void controllerStateCallback(tgvoip::VoIPController *controller, int state) {
|
||||
auto *self = (TgVoipImpl *) controller->implData;
|
||||
if (self->onStateUpdated_) {
|
||||
TgVoipState mappedState;
|
||||
switch (state) {
|
||||
case tgvoip::STATE_WAIT_INIT:
|
||||
mappedState = TgVoipState::WaitInit;
|
||||
break;
|
||||
case tgvoip::STATE_WAIT_INIT_ACK:
|
||||
mappedState = TgVoipState::WaitInitAck;
|
||||
break;
|
||||
case tgvoip::STATE_ESTABLISHED:
|
||||
mappedState = TgVoipState::Estabilished;
|
||||
break;
|
||||
case tgvoip::STATE_FAILED:
|
||||
mappedState = TgVoipState::Failed;
|
||||
break;
|
||||
case tgvoip::STATE_RECONNECTING:
|
||||
mappedState = TgVoipState::Reconnecting;
|
||||
break;
|
||||
default:
|
||||
mappedState = TgVoipState::Estabilished;
|
||||
break;
|
||||
}
|
||||
|
||||
self->onStateUpdated_(mappedState);
|
||||
}
|
||||
}
|
||||
|
||||
static void signalBarsCallback(tgvoip::VoIPController *controller, int signalBars) {
|
||||
auto *self = (TgVoipImpl *) controller->implData;
|
||||
if (self->onSignalBarsUpdated_) {
|
||||
self->onSignalBarsUpdated_(signalBars);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
std::function<void(std::string const &)> globalLoggingFunction;
|
||||
|
||||
void __tgvoip_call_tglog(const char *format, ...){
|
||||
va_list vaArgs;
|
||||
va_start(vaArgs, format);
|
||||
|
||||
va_list vaCopy;
|
||||
va_copy(vaCopy, vaArgs);
|
||||
const int length = std::vsnprintf(nullptr, 0, format, vaCopy);
|
||||
va_end(vaCopy);
|
||||
|
||||
std::vector<char> zc(length + 1);
|
||||
std::vsnprintf(zc.data(), zc.size(), format, vaArgs);
|
||||
va_end(vaArgs);
|
||||
|
||||
if (globalLoggingFunction != nullptr) {
|
||||
globalLoggingFunction(std::string(zc.data(), zc.size()));
|
||||
}
|
||||
}
|
||||
|
||||
void TgVoip::setLoggingFunction(std::function<void(std::string const &)> loggingFunction) {
|
||||
globalLoggingFunction = loggingFunction;
|
||||
}
|
||||
|
||||
void TgVoip::setGlobalServerConfig(const std::string &serverConfig) {
|
||||
tgvoip::ServerConfig::GetSharedInstance()->Update(serverConfig);
|
||||
}
|
||||
|
||||
int TgVoip::getConnectionMaxLayer() {
|
||||
return tgvoip::VoIPController::GetConnectionMaxLayer();
|
||||
}
|
||||
|
||||
std::string TgVoip::getVersion() {
|
||||
return tgvoip::VoIPController::GetVersion();
|
||||
}
|
||||
|
||||
TgVoip *TgVoip::makeInstance(
|
||||
TgVoipConfig const &config,
|
||||
TgVoipPersistentState const &persistentState,
|
||||
std::vector<TgVoipEndpoint> const &endpoints,
|
||||
std::unique_ptr<TgVoipProxy> const &proxy,
|
||||
TgVoipNetworkType initialNetworkType,
|
||||
TgVoipEncryptionKey const &encryptionKey
|
||||
#ifdef TGVOIP_USE_CUSTOM_CRYPTO
|
||||
,
|
||||
TgVoipCrypto const &crypto
|
||||
#endif
|
||||
#ifdef TGVOIP_USE_CALLBACK_AUDIO_IO
|
||||
,
|
||||
TgVoipAudioDataCallbacks const &audioDataCallbacks
|
||||
#endif
|
||||
) {
|
||||
return new TgVoipImpl(
|
||||
endpoints,
|
||||
persistentState,
|
||||
proxy,
|
||||
config,
|
||||
encryptionKey,
|
||||
initialNetworkType
|
||||
#ifdef TGVOIP_USE_CUSTOM_CRYPTO
|
||||
,
|
||||
crypto
|
||||
#endif
|
||||
#ifdef TGVOIP_USE_CALLBACK_AUDIO_IO
|
||||
,
|
||||
audioDataCallbacks
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
TgVoip::~TgVoip() = default;
|
160
TMessagesProj/jni/libtgvoip/TgVoip.h
Normal file
160
TMessagesProj/jni/libtgvoip/TgVoip.h
Normal file
|
@ -0,0 +1,160 @@
|
|||
#ifndef __TGVOIP_H
|
||||
#define __TGVOIP_H
|
||||
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
struct TgVoipProxy {
|
||||
std::string host;
|
||||
uint16_t port;
|
||||
std::string login;
|
||||
std::string password;
|
||||
};
|
||||
|
||||
enum class TgVoipEndpointType {
|
||||
Inet,
|
||||
Lan,
|
||||
UdpRelay,
|
||||
TcpRelay
|
||||
};
|
||||
|
||||
struct TgVoipEndpoint {
|
||||
int64_t endpointId;
|
||||
std::string host;
|
||||
uint16_t port;
|
||||
TgVoipEndpointType type;
|
||||
unsigned char peerTag[16];
|
||||
};
|
||||
|
||||
enum class TgVoipNetworkType {
|
||||
Unknown,
|
||||
Gprs,
|
||||
Edge,
|
||||
ThirdGeneration,
|
||||
Hspa,
|
||||
Lte,
|
||||
WiFi,
|
||||
Ethernet,
|
||||
OtherHighSpeed,
|
||||
OtherLowSpeed,
|
||||
OtherMobile,
|
||||
Dialup
|
||||
};
|
||||
|
||||
enum class TgVoipDataSaving {
|
||||
Never,
|
||||
Mobile,
|
||||
Always
|
||||
};
|
||||
|
||||
struct TgVoipPersistentState {
|
||||
std::vector<uint8_t> value;
|
||||
};
|
||||
|
||||
#ifdef TGVOIP_USE_CUSTOM_CRYPTO
|
||||
struct TgVoipCrypto {
|
||||
void (*rand_bytes)(uint8_t* buffer, size_t length);
|
||||
void (*sha1)(uint8_t* msg, size_t length, uint8_t* output);
|
||||
void (*sha256)(uint8_t* msg, size_t length, uint8_t* output);
|
||||
void (*aes_ige_encrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv);
|
||||
void (*aes_ige_decrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv);
|
||||
void (*aes_ctr_encrypt)(uint8_t* inout, size_t length, uint8_t* key, uint8_t* iv, uint8_t* ecount, uint32_t* num);
|
||||
void (*aes_cbc_encrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv);
|
||||
void (*aes_cbc_decrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv);
|
||||
};
|
||||
#endif
|
||||
|
||||
struct TgVoipConfig {
|
||||
double initializationTimeout;
|
||||
double receiveTimeout;
|
||||
TgVoipDataSaving dataSaving;
|
||||
bool enableP2P;
|
||||
bool enableAEC;
|
||||
bool enableNS;
|
||||
bool enableAGC;
|
||||
bool enableCallUpgrade;
|
||||
std::string logPath;
|
||||
int maxApiLayer;
|
||||
};
|
||||
|
||||
struct TgVoipEncryptionKey {
|
||||
std::vector<uint8_t> value;
|
||||
bool isOutgoing;
|
||||
};
|
||||
|
||||
enum class TgVoipState {
|
||||
WaitInit,
|
||||
WaitInitAck,
|
||||
Estabilished,
|
||||
Failed,
|
||||
Reconnecting
|
||||
};
|
||||
|
||||
struct TgVoipTrafficStats {
|
||||
uint64_t bytesSentWifi;
|
||||
uint64_t bytesReceivedWifi;
|
||||
uint64_t bytesSentMobile;
|
||||
uint64_t bytesReceivedMobile;
|
||||
};
|
||||
|
||||
struct TgVoipFinalState {
|
||||
TgVoipPersistentState persistentState;
|
||||
std::string debugLog;
|
||||
TgVoipTrafficStats trafficStats;
|
||||
bool isRatingSuggested;
|
||||
};
|
||||
|
||||
struct TgVoipAudioDataCallbacks {
|
||||
std::function<void(int16_t*, size_t)> input;
|
||||
std::function<void(int16_t*, size_t)> output;
|
||||
std::function<void(int16_t*, size_t)> preprocessed;
|
||||
};
|
||||
|
||||
class TgVoip {
|
||||
protected:
|
||||
TgVoip() = default;
|
||||
|
||||
public:
|
||||
static void setLoggingFunction(std::function<void(std::string const &)> loggingFunction);
|
||||
static void setGlobalServerConfig(std::string const &serverConfig);
|
||||
static int getConnectionMaxLayer();
|
||||
static std::string getVersion();
|
||||
static TgVoip *makeInstance(
|
||||
TgVoipConfig const &config,
|
||||
TgVoipPersistentState const &persistentState,
|
||||
std::vector<TgVoipEndpoint> const &endpoints,
|
||||
std::unique_ptr<TgVoipProxy> const &proxy,
|
||||
TgVoipNetworkType initialNetworkType,
|
||||
TgVoipEncryptionKey const &encryptionKey
|
||||
#ifdef TGVOIP_USE_CUSTOM_CRYPTO
|
||||
,
|
||||
TgVoipCrypto const &crypto
|
||||
#endif
|
||||
#ifdef TGVOIP_USE_CALLBACK_AUDIO_IO
|
||||
,
|
||||
TgVoipAudioDataCallbacks const &audioDataCallbacks
|
||||
#endif
|
||||
);
|
||||
|
||||
virtual ~TgVoip();
|
||||
|
||||
virtual void setNetworkType(TgVoipNetworkType networkType) = 0;
|
||||
virtual void setMuteMicrophone(bool muteMicrophone) = 0;
|
||||
virtual void setAudioOutputGainControlEnabled(bool enabled) = 0;
|
||||
virtual void setEchoCancellationStrength(int strength) = 0;
|
||||
|
||||
virtual std::string getLastError() = 0;
|
||||
virtual std::string getDebugInfo() = 0;
|
||||
virtual int64_t getPreferredRelayId() = 0;
|
||||
virtual TgVoipTrafficStats getTrafficStats() = 0;
|
||||
virtual TgVoipPersistentState getPersistentState() = 0;
|
||||
|
||||
virtual void setOnStateUpdated(std::function<void(TgVoipState)> onStateUpdated) = 0;
|
||||
virtual void setOnSignalBarsUpdated(std::function<void(int)> onSignalBarsUpdated) = 0;
|
||||
|
||||
virtual TgVoipFinalState stop() = 0;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -29,6 +29,11 @@
|
|||
#include <sstream>
|
||||
#include <inttypes.h>
|
||||
#include <float.h>
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <opus.h>
|
||||
#else
|
||||
#include <opus.h>
|
||||
#endif
|
||||
|
||||
|
||||
inline int pad4(int x){
|
||||
|
@ -64,74 +69,6 @@ extern jclass jniUtilitiesClass;
|
|||
#include "audio/AudioIOCallback.h"
|
||||
#endif
|
||||
|
||||
#pragma mark - OpenSSL wrappers
|
||||
|
||||
#ifndef TGVOIP_USE_CUSTOM_CRYPTO
|
||||
extern "C" {
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/aes.h>
|
||||
//#include <openssl/modes.h>
|
||||
#include <openssl/rand.h>
|
||||
}
|
||||
|
||||
void tgvoip_openssl_aes_ige_encrypt(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv){
|
||||
AES_KEY akey;
|
||||
AES_set_encrypt_key(key, 32*8, &akey);
|
||||
AES_ige_encrypt(in, out, length, &akey, iv, AES_ENCRYPT);
|
||||
}
|
||||
|
||||
void tgvoip_openssl_aes_ige_decrypt(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv){
|
||||
AES_KEY akey;
|
||||
AES_set_decrypt_key(key, 32*8, &akey);
|
||||
AES_ige_encrypt(in, out, length, &akey, iv, AES_DECRYPT);
|
||||
}
|
||||
|
||||
void tgvoip_openssl_rand_bytes(uint8_t* buffer, size_t len){
|
||||
RAND_bytes(buffer, len);
|
||||
}
|
||||
|
||||
void tgvoip_openssl_sha1(uint8_t* msg, size_t len, uint8_t* output){
|
||||
SHA1(msg, len, output);
|
||||
}
|
||||
|
||||
void tgvoip_openssl_sha256(uint8_t* msg, size_t len, uint8_t* output){
|
||||
SHA256(msg, len, output);
|
||||
}
|
||||
|
||||
void tgvoip_openssl_aes_ctr_encrypt(uint8_t* inout, size_t length, uint8_t* key, uint8_t* iv, uint8_t* ecount, uint32_t* num){
|
||||
AES_KEY akey;
|
||||
AES_set_encrypt_key(key, 32*8, &akey);
|
||||
AES_ctr128_encrypt(inout, inout, length, &akey, iv, ecount, num);
|
||||
}
|
||||
|
||||
void tgvoip_openssl_aes_cbc_encrypt(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv){
|
||||
AES_KEY akey;
|
||||
AES_set_encrypt_key(key, 256, &akey);
|
||||
AES_cbc_encrypt(in, out, length, &akey, iv, AES_ENCRYPT);
|
||||
}
|
||||
|
||||
void tgvoip_openssl_aes_cbc_decrypt(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv){
|
||||
AES_KEY akey;
|
||||
AES_set_decrypt_key(key, 256, &akey);
|
||||
AES_cbc_encrypt(in, out, length, &akey, iv, AES_DECRYPT);
|
||||
}
|
||||
|
||||
CryptoFunctions VoIPController::crypto={
|
||||
tgvoip_openssl_rand_bytes,
|
||||
tgvoip_openssl_sha1,
|
||||
tgvoip_openssl_sha256,
|
||||
tgvoip_openssl_aes_ige_encrypt,
|
||||
tgvoip_openssl_aes_ige_decrypt,
|
||||
tgvoip_openssl_aes_ctr_encrypt,
|
||||
tgvoip_openssl_aes_cbc_encrypt,
|
||||
tgvoip_openssl_aes_cbc_decrypt
|
||||
|
||||
};
|
||||
#else
|
||||
CryptoFunctions VoIPController::crypto; // set it yourself upon initialization
|
||||
#endif
|
||||
|
||||
|
||||
extern FILE* tgvoipLogFile;
|
||||
|
||||
#pragma mark - Public API
|
||||
|
@ -294,6 +231,12 @@ VoIPController::~VoIPController(){
|
|||
tgvoipLogFile=NULL;
|
||||
fclose(log);
|
||||
}
|
||||
#if defined(TGVOIP_USE_CALLBACK_AUDIO_IO)
|
||||
if (preprocDecoder) {
|
||||
opus_decoder_destroy(preprocDecoder);
|
||||
preprocDecoder=nullptr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void VoIPController::Stop(){
|
||||
|
@ -773,10 +716,10 @@ string VoIPController::GetCurrentAudioOutputID(){
|
|||
|
||||
void VoIPController::SetProxy(int protocol, string address, uint16_t port, string username, string password){
|
||||
proxyProtocol=protocol;
|
||||
proxyAddress=address;
|
||||
proxyAddress=std::move(address);
|
||||
proxyPort=port;
|
||||
proxyUsername=username;
|
||||
proxyPassword=password;
|
||||
proxyUsername=std::move(username);
|
||||
proxyPassword=std::move(password);
|
||||
}
|
||||
|
||||
int VoIPController::GetSignalBarsCount(){
|
||||
|
@ -841,9 +784,11 @@ void VoIPController::SetEchoCancellationStrength(int strength){
|
|||
}
|
||||
|
||||
#if defined(TGVOIP_USE_CALLBACK_AUDIO_IO)
|
||||
void VoIPController::SetAudioDataCallbacks(std::function<void(int16_t*, size_t)> input, std::function<void(int16_t*, size_t)> output){
|
||||
void VoIPController::SetAudioDataCallbacks(std::function<void(int16_t*, size_t)> input, std::function<void(int16_t*, size_t)> output, std::function<void(int16_t*, size_t)> preproc=nullptr){
|
||||
audioInputDataCallback=input;
|
||||
audioOutputDataCallback=output;
|
||||
audioPreprocDataCallback=preproc;
|
||||
preprocDecoder=preprocDecoder ? preprocDecoder : opus_decoder_create(48000, 1, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -894,7 +839,7 @@ void VoIPController::SetConfig(const Config& cfg){
|
|||
|
||||
void VoIPController::SetPersistentState(vector<uint8_t> state){
|
||||
using namespace json11;
|
||||
|
||||
|
||||
if(state.empty())
|
||||
return;
|
||||
string jsonErr;
|
||||
|
@ -915,7 +860,7 @@ void VoIPController::SetPersistentState(vector<uint8_t> state){
|
|||
|
||||
vector<uint8_t> VoIPController::GetPersistentState(){
|
||||
using namespace json11;
|
||||
|
||||
|
||||
Json::object obj=Json::object{
|
||||
{"ver", 1},
|
||||
};
|
||||
|
@ -1116,10 +1061,11 @@ void VoIPController::HandleAudioInput(unsigned char *data, size_t len, unsigned
|
|||
}
|
||||
|
||||
unsentStreamPackets++;
|
||||
size_t pktLength = pkt.GetLength();
|
||||
PendingOutgoingPacket p{
|
||||
/*.seq=*/GenerateOutSeq(),
|
||||
/*.type=*/PKT_STREAM_DATA,
|
||||
/*.len=*/pkt.GetLength(),
|
||||
/*.len=*/pktLength,
|
||||
/*.data=*/Buffer(move(pkt)),
|
||||
/*.endpoint=*/0,
|
||||
};
|
||||
|
@ -1142,10 +1088,11 @@ void VoIPController::HandleAudioInput(unsigned char *data, size_t len, unsigned
|
|||
pkt.WriteBytes(*ecData);
|
||||
}
|
||||
|
||||
pktLength = pkt.GetLength();
|
||||
PendingOutgoingPacket p{
|
||||
GenerateOutSeq(),
|
||||
PKT_STREAM_EC,
|
||||
pkt.GetLength(),
|
||||
pktLength,
|
||||
Buffer(move(pkt)),
|
||||
0
|
||||
};
|
||||
|
@ -1153,6 +1100,13 @@ void VoIPController::HandleAudioInput(unsigned char *data, size_t len, unsigned
|
|||
}
|
||||
|
||||
audioTimestampOut+=outgoingStreams[0]->frameDuration;
|
||||
|
||||
#if defined(TGVOIP_USE_CALLBACK_AUDIO_IO)
|
||||
if (audioPreprocDataCallback && preprocDecoder) {
|
||||
int size=opus_decode(preprocDecoder, data, len, preprocBuffer, 4096, 0);
|
||||
audioPreprocDataCallback(preprocBuffer, size);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void VoIPController::InitializeAudio(){
|
||||
|
@ -1324,7 +1278,7 @@ void VoIPController::WritePacketHeader(uint32_t pseq, BufferOutputStream *s, uns
|
|||
if(!currentExtras.empty()){
|
||||
s->WriteByte(static_cast<unsigned char>(currentExtras.size()));
|
||||
for(vector<UnacknowledgedExtraData>::iterator x=currentExtras.begin(); x!=currentExtras.end(); ++x){
|
||||
LOGV("Writing extra into header: type %u, length %lu", x->type, x->data.Length());
|
||||
LOGV("Writing extra into header: type %u, length %d", x->type, int(x->data.Length()));
|
||||
assert(x->data.Length()<=254);
|
||||
s->WriteByte(static_cast<unsigned char>(x->data.Length()+1));
|
||||
s->WriteByte(x->type);
|
||||
|
@ -1406,7 +1360,7 @@ void VoIPController::WritePacketHeader(uint32_t pseq, BufferOutputStream *s, uns
|
|||
s->WriteByte(XPFLAG_HAS_EXTRA);
|
||||
s->WriteByte(static_cast<unsigned char>(currentExtras.size()));
|
||||
for(vector<UnacknowledgedExtraData>::iterator x=currentExtras.begin(); x!=currentExtras.end(); ++x){
|
||||
LOGV("Writing extra into header: type %u, length %lu", x->type, x->data.Length());
|
||||
LOGV("Writing extra into header: type %u, length %d", x->type, int(x->data.Length()));
|
||||
assert(x->data.Length()<=254);
|
||||
s->WriteByte(static_cast<unsigned char>(x->data.Length()+1));
|
||||
s->WriteByte(x->type);
|
||||
|
@ -1486,10 +1440,11 @@ void VoIPController::SendInit(){
|
|||
out.WriteInt32(id);
|
||||
}*/
|
||||
}
|
||||
size_t outLength = out.GetLength();
|
||||
SendOrEnqueuePacket(PendingOutgoingPacket{
|
||||
/*.seq=*/initSeq,
|
||||
/*.type=*/PKT_INIT,
|
||||
/*.len=*/out.GetLength(),
|
||||
/*.len=*/outLength,
|
||||
/*.data=*/Buffer(move(out)),
|
||||
/*.endpoint=*/e.id
|
||||
});
|
||||
|
@ -1518,14 +1473,14 @@ void VoIPController::InitUDPProxy(){
|
|||
ResetUdpAvailability();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
NetworkSocket* tcp=NetworkSocket::Create(PROTO_TCP);
|
||||
tcp->Connect(resolvedProxyAddress, proxyPort);
|
||||
|
||||
|
||||
vector<NetworkSocket*> writeSockets;
|
||||
vector<NetworkSocket*> readSockets;
|
||||
vector<NetworkSocket*> errorSockets;
|
||||
|
||||
|
||||
while(!tcp->IsFailed() && !tcp->IsReadyToSend()){
|
||||
writeSockets.push_back(tcp);
|
||||
if(!NetworkSocket::Select(readSockets, writeSockets, errorSockets, selectCanceller)){
|
||||
|
@ -1579,12 +1534,12 @@ void VoIPController::RunRecvThread(){
|
|||
udpPingTimeoutID=messageThread.Post(std::bind(&VoIPController::SendUdpPings, this), 0.0, 0.5);
|
||||
}
|
||||
while(runReceiver){
|
||||
|
||||
|
||||
if(proxyProtocol==PROXY_SOCKS5 && needReInitUdpProxy){
|
||||
InitUDPProxy();
|
||||
needReInitUdpProxy=false;
|
||||
}
|
||||
|
||||
|
||||
packet.data=*buffer;
|
||||
packet.length=buffer.Length();
|
||||
|
||||
|
@ -1595,7 +1550,7 @@ void VoIPController::RunRecvThread(){
|
|||
errorSockets.push_back(realUdpSocket);
|
||||
if(!realUdpSocket->IsReadyToSend())
|
||||
writeSockets.push_back(realUdpSocket);
|
||||
|
||||
|
||||
{
|
||||
MutexGuard m(endpointsMutex);
|
||||
for(pair<const int64_t, Endpoint>& _e:endpoints){
|
||||
|
@ -2132,7 +2087,7 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA
|
|||
}
|
||||
for(vector<UnacknowledgedExtraData>::iterator x=currentExtras.begin();x!=currentExtras.end();){
|
||||
if(x->firstContainingSeq!=0 && (lastRemoteAckSeq==x->firstContainingSeq || seqgt(lastRemoteAckSeq, x->firstContainingSeq))){
|
||||
LOGV("Peer acknowledged extra type %u length %lu", x->type, x->data.Length());
|
||||
LOGV("Peer acknowledged extra type %u length %d", x->type, int(x->data.Length()));
|
||||
ProcessAcknowledgedOutgoingExtra(*x);
|
||||
x=currentExtras.erase(x);
|
||||
continue;
|
||||
|
@ -2310,10 +2265,11 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA
|
|||
out.WriteByte((unsigned char) ((*s)->enabled ? 1 : 0));
|
||||
}
|
||||
LOGI("Sending init ack");
|
||||
size_t outLength = out.GetLength();
|
||||
SendOrEnqueuePacket(PendingOutgoingPacket{
|
||||
/*.seq=*/GenerateOutSeq(),
|
||||
/*.type=*/PKT_INIT_ACK,
|
||||
/*.len=*/out.GetLength(),
|
||||
/*.len=*/outLength,
|
||||
/*.data=*/Buffer(move(out)),
|
||||
/*.endpoint=*/0
|
||||
});
|
||||
|
@ -2541,10 +2497,11 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA
|
|||
}
|
||||
BufferOutputStream pkt(128);
|
||||
pkt.WriteInt32(pseq);
|
||||
size_t pktLength = pkt.GetLength();
|
||||
SendOrEnqueuePacket(PendingOutgoingPacket{
|
||||
/*.seq=*/GenerateOutSeq(),
|
||||
/*.type=*/PKT_PONG,
|
||||
/*.len=*/pkt.GetLength(),
|
||||
/*.len=*/pktLength,
|
||||
/*.data=*/Buffer(move(pkt)),
|
||||
/*.endpoint=*/srcEndpoint.id,
|
||||
});
|
||||
|
@ -2799,7 +2756,7 @@ bool VoIPController::SendOrEnqueuePacket(PendingOutgoingPacket pkt, bool enqueue
|
|||
abort();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool canSend;
|
||||
if(endpoint->type!=Endpoint::Type::TCP_RELAY){
|
||||
|
@ -3055,7 +3012,7 @@ void VoIPController::AddTCPRelays(){
|
|||
relays.push_back(tcpRelay);
|
||||
}
|
||||
for(Endpoint& e:relays){
|
||||
endpoints[e.id]=move(e);
|
||||
endpoints[e.id]=e;
|
||||
}
|
||||
didAddTcpRelays=true;
|
||||
}
|
||||
|
@ -3206,7 +3163,7 @@ void VoIPController::SendPacketReliably(unsigned char type, unsigned char *data,
|
|||
|
||||
void VoIPController::SendExtra(Buffer &data, unsigned char type){
|
||||
MutexGuard m(queuedPacketsMutex);
|
||||
LOGV("Sending extra type %u length %lu", type, data.Length());
|
||||
LOGV("Sending extra type %u length %d", type, int(data.Length()));
|
||||
for(vector<UnacknowledgedExtraData>::iterator x=currentExtras.begin();x!=currentExtras.end();++x){
|
||||
if(x->type==type){
|
||||
x->firstContainingSeq=0;
|
||||
|
@ -3479,16 +3436,17 @@ void VoIPController::SendVideoFrame(const Buffer &frame, uint32_t flags, uint32_
|
|||
pkt.WriteBytes(frame, offset, len);
|
||||
|
||||
uint32_t seq=GenerateOutSeq();
|
||||
size_t pktLength = pkt.GetLength();
|
||||
PendingOutgoingPacket p{
|
||||
/*.seq=*/seq,
|
||||
/*.type=*/PKT_STREAM_DATA,
|
||||
/*.len=*/pkt.GetLength(),
|
||||
/*.len=*/pktLength,
|
||||
/*.data=*/Buffer(move(pkt)),
|
||||
/*.endpoint=*/0,
|
||||
};
|
||||
unsentStreamPackets++;
|
||||
SendOrEnqueuePacket(move(p));
|
||||
videoCongestionControl.ProcessPacketSent(static_cast<unsigned int>(pkt.GetLength()));
|
||||
videoCongestionControl.ProcessPacketSent(static_cast<unsigned int>(pktLength));
|
||||
sentFrame.unacknowledgedPackets.push_back(seq);
|
||||
}
|
||||
MutexGuard m(sentVideoFramesMutex);
|
||||
|
@ -3750,7 +3708,7 @@ void VoIPController::UpdateCongestion(){
|
|||
wasExtraEC=true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(avgSendLossCount>0.08){
|
||||
extraEcLevel=4;
|
||||
}else if(avgSendLossCount>0.05){
|
||||
|
@ -4019,7 +3977,7 @@ Endpoint::~Endpoint(){
|
|||
|
||||
#pragma mark - AudioInputTester
|
||||
|
||||
AudioInputTester::AudioInputTester(std::string deviceID) : deviceID(deviceID){
|
||||
AudioInputTester::AudioInputTester(std::string deviceID) : deviceID(std::move(deviceID)){
|
||||
io=audio::AudioIO::Create(deviceID, "default");
|
||||
if(io->Failed()){
|
||||
LOGE("Audio IO failed");
|
||||
|
|
|
@ -402,7 +402,7 @@ namespace tgvoip{
|
|||
void SetPersistentState(std::vector<uint8_t> state);
|
||||
|
||||
#if defined(TGVOIP_USE_CALLBACK_AUDIO_IO)
|
||||
void SetAudioDataCallbacks(std::function<void(int16_t*, size_t)> input, std::function<void(int16_t*, size_t)> output);
|
||||
void SetAudioDataCallbacks(std::function<void(int16_t*, size_t)> input, std::function<void(int16_t*, size_t)> output, std::function<void(int16_t*, size_t)> preprocessed);
|
||||
#endif
|
||||
|
||||
void SetVideoCodecSpecificData(const std::vector<Buffer>& data);
|
||||
|
@ -749,6 +749,9 @@ namespace tgvoip{
|
|||
#if defined(TGVOIP_USE_CALLBACK_AUDIO_IO)
|
||||
std::function<void(int16_t*, size_t)> audioInputDataCallback;
|
||||
std::function<void(int16_t*, size_t)> audioOutputDataCallback;
|
||||
std::function<void(int16_t*, size_t)> audioPreprocDataCallback;
|
||||
::OpusDecoder* preprocDecoder=nullptr;
|
||||
int16_t preprocBuffer[4096];
|
||||
#endif
|
||||
#if defined(__APPLE__) && defined(TARGET_OS_OSX)
|
||||
bool macAudioDuckingEnabled=true;
|
||||
|
|
|
@ -58,7 +58,7 @@ static const int16_t hann[960]={
|
|||
0x7FDE, 0x7FE1, 0x7FE4, 0x7FE7, 0x7FEA, 0x7FED, 0x7FEF, 0x7FF1, 0x7FF3, 0x7FF5, 0x7FF7, 0x7FF9, 0x7FFA, 0x7FFB, 0x7FFC, 0x7FFD, 0x7FFE, 0x7FFE, 0x7FFF, 0x7FFF
|
||||
};
|
||||
|
||||
#define MIN(a, b) (a<b ? a : b)
|
||||
#define MIN(a, b) (((a)<(b)) ? (a) : (b))
|
||||
|
||||
size_t Resampler::Convert48To44(int16_t *from, int16_t *to, size_t fromLen, size_t toLen){
|
||||
size_t outLen=fromLen*147/160;
|
||||
|
|
|
@ -0,0 +1,402 @@
|
|||
#include <jni.h>
|
||||
#include <TgVoip.h>
|
||||
#include <os/android/AudioOutputOpenSLES.h>
|
||||
#include <os/android/AudioInputOpenSLES.h>
|
||||
#include <os/android/JNIUtilities.h>
|
||||
#include "org_telegram_messenger_voip_TgVoip.h"
|
||||
|
||||
using namespace tgvoip;
|
||||
|
||||
extern "C" int tgvoipOnJniLoad(JavaVM *vm, JNIEnv *env) {
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
#pragma mark - Helpers
|
||||
|
||||
class JavaObject {
|
||||
private:
|
||||
JNIEnv *env;
|
||||
jobject obj;
|
||||
jclass clazz;
|
||||
|
||||
public:
|
||||
JavaObject(JNIEnv *env, jobject obj) : JavaObject(env, obj, env->GetObjectClass(obj)) {
|
||||
}
|
||||
|
||||
JavaObject(JNIEnv *env, jobject obj, jclass clazz) {
|
||||
this->env = env;
|
||||
this->obj = obj;
|
||||
this->clazz = clazz;
|
||||
}
|
||||
|
||||
jint getIntField(const char *name) {
|
||||
return env->GetIntField(obj, env->GetFieldID(clazz, name, "I"));
|
||||
}
|
||||
|
||||
jlong getLongField(const char *name) {
|
||||
return env->GetLongField(obj, env->GetFieldID(clazz, name, "J"));
|
||||
}
|
||||
|
||||
jboolean getBooleanField(const char *name) {
|
||||
return env->GetBooleanField(obj, env->GetFieldID(clazz, name, "Z"));
|
||||
}
|
||||
|
||||
jdouble getDoubleField(const char *name) {
|
||||
return env->GetDoubleField(obj, env->GetFieldID(clazz, name, "D"));
|
||||
}
|
||||
|
||||
jbyteArray getByteArrayField(const char *name) {
|
||||
return (jbyteArray) env->GetObjectField(obj, env->GetFieldID(clazz, name, "[B"));
|
||||
}
|
||||
|
||||
jstring getStringField(const char *name) {
|
||||
return (jstring) env->GetObjectField(obj, env->GetFieldID(clazz, name, "Ljava/lang/String;"));
|
||||
}
|
||||
};
|
||||
|
||||
struct InstanceHolder {
|
||||
TgVoip *nativeInstance;
|
||||
jobject javaInstance;
|
||||
};
|
||||
|
||||
jlong getInstanceHolderId(JNIEnv *env, jobject obj) {
|
||||
return env->GetLongField(obj, env->GetFieldID(env->GetObjectClass(obj), "nativeInstanceId", "J"));
|
||||
}
|
||||
|
||||
InstanceHolder *getInstanceHolder(JNIEnv *env, jobject obj) {
|
||||
return reinterpret_cast<InstanceHolder *>(getInstanceHolderId(env, obj));
|
||||
}
|
||||
|
||||
TgVoip *getTgVoip(JNIEnv *env, jobject obj) {
|
||||
return getInstanceHolder(env, obj)->nativeInstance;
|
||||
}
|
||||
|
||||
jint throwNewJavaException(JNIEnv *env, const char *className, const char *message) {
|
||||
return env->ThrowNew(env->FindClass(className), message);
|
||||
}
|
||||
|
||||
jint throwNewJavaIllegalArgumentException(JNIEnv *env, const char *message) {
|
||||
return throwNewJavaException(env, "java/lang/IllegalStateException", message);
|
||||
}
|
||||
|
||||
jbyteArray copyVectorToJavaByteArray(JNIEnv *env, const std::vector<uint8_t> &bytes) {
|
||||
unsigned int size = bytes.size();
|
||||
jbyteArray bytesArray = env->NewByteArray(size);
|
||||
env->SetByteArrayRegion(bytesArray, 0, size, (jbyte *) bytes.data());
|
||||
return bytesArray;
|
||||
}
|
||||
|
||||
void readTgVoipPersistentState(const char *filePath, TgVoipPersistentState &tgVoipPersistentState) {
|
||||
FILE *persistentStateFile = fopen(filePath, "r");
|
||||
if (persistentStateFile) {
|
||||
fseek(persistentStateFile, 0, SEEK_END);
|
||||
auto len = static_cast<size_t>(ftell(persistentStateFile));
|
||||
fseek(persistentStateFile, 0, SEEK_SET);
|
||||
if (len < 1024 * 512 && len > 0) {
|
||||
auto *buffer = static_cast<uint8_t *>(malloc(len));
|
||||
fread(buffer, 1, len, persistentStateFile);
|
||||
tgVoipPersistentState.value = std::vector<uint8_t>(buffer, buffer + len);
|
||||
free(buffer);
|
||||
}
|
||||
fclose(persistentStateFile);
|
||||
}
|
||||
}
|
||||
|
||||
void saveTgVoipPersistentState(const char *filePath, const TgVoipPersistentState &tgVoipPersistentState) {
|
||||
FILE *persistentStateFile = fopen(filePath, "w");
|
||||
if (persistentStateFile) {
|
||||
fwrite(tgVoipPersistentState.value.data(), 1, tgVoipPersistentState.value.size(), persistentStateFile);
|
||||
fclose(persistentStateFile);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Mappers
|
||||
|
||||
TgVoipNetworkType parseTgVoipNetworkType(jint networkType) {
|
||||
switch (networkType) {
|
||||
case org_telegram_messenger_voip_TgVoip_NET_TYPE_GPRS:
|
||||
return TgVoipNetworkType::Gprs;
|
||||
case org_telegram_messenger_voip_TgVoip_NET_TYPE_EDGE:
|
||||
return TgVoipNetworkType::Edge;
|
||||
case org_telegram_messenger_voip_TgVoip_NET_TYPE_3G:
|
||||
return TgVoipNetworkType::ThirdGeneration;
|
||||
case org_telegram_messenger_voip_TgVoip_NET_TYPE_HSPA:
|
||||
return TgVoipNetworkType::Hspa;
|
||||
case org_telegram_messenger_voip_TgVoip_NET_TYPE_LTE:
|
||||
return TgVoipNetworkType::Lte;
|
||||
case org_telegram_messenger_voip_TgVoip_NET_TYPE_WIFI:
|
||||
return TgVoipNetworkType::WiFi;
|
||||
case org_telegram_messenger_voip_TgVoip_NET_TYPE_ETHERNET:
|
||||
return TgVoipNetworkType::Ethernet;
|
||||
case org_telegram_messenger_voip_TgVoip_NET_TYPE_OTHER_HIGH_SPEED:
|
||||
return TgVoipNetworkType::OtherHighSpeed;
|
||||
case org_telegram_messenger_voip_TgVoip_NET_TYPE_OTHER_LOW_SPEED:
|
||||
return TgVoipNetworkType::OtherLowSpeed;
|
||||
case org_telegram_messenger_voip_TgVoip_NET_TYPE_DIALUP:
|
||||
return TgVoipNetworkType::Dialup;
|
||||
case org_telegram_messenger_voip_TgVoip_NET_TYPE_OTHER_MOBILE:
|
||||
return TgVoipNetworkType::OtherMobile;
|
||||
default:
|
||||
return TgVoipNetworkType::Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
TgVoipDataSaving parseTgVoipDataSaving(JNIEnv *env, jint dataSaving) {
|
||||
switch (dataSaving) {
|
||||
case org_telegram_messenger_voip_TgVoip_DATA_SAVING_NEVER:
|
||||
return TgVoipDataSaving::Never;
|
||||
case org_telegram_messenger_voip_TgVoip_DATA_SAVING_MOBILE:
|
||||
return TgVoipDataSaving::Mobile;
|
||||
case org_telegram_messenger_voip_TgVoip_DATA_SAVING_ALWAYS:
|
||||
return TgVoipDataSaving::Always;
|
||||
case org_telegram_messenger_voip_TgVoip_DATA_SAVING_ROAMING:
|
||||
throwNewJavaIllegalArgumentException(env, "DATA_SAVING_ROAMING is not supported");
|
||||
return TgVoipDataSaving::Never;
|
||||
default:
|
||||
throwNewJavaIllegalArgumentException(env, "Unknown data saving constant: " + dataSaving);
|
||||
return TgVoipDataSaving::Never;
|
||||
}
|
||||
}
|
||||
|
||||
void parseTgVoipConfig(JNIEnv *env, jobject config, TgVoipConfig &tgVoipConfig) {
|
||||
JavaObject configObject(env, config);
|
||||
tgVoipConfig.initializationTimeout = configObject.getDoubleField("initializationTimeout");
|
||||
tgVoipConfig.receiveTimeout = configObject.getDoubleField("receiveTimeout");
|
||||
tgVoipConfig.dataSaving = parseTgVoipDataSaving(env, configObject.getIntField("dataSaving"));
|
||||
tgVoipConfig.enableP2P = configObject.getBooleanField("enableP2p") == JNI_TRUE;
|
||||
tgVoipConfig.enableAEC = configObject.getBooleanField("enableAec") == JNI_TRUE;
|
||||
tgVoipConfig.enableNS = configObject.getBooleanField("enableNs") == JNI_TRUE;
|
||||
tgVoipConfig.enableAGC = configObject.getBooleanField("enableAgc") == JNI_TRUE;
|
||||
tgVoipConfig.enableCallUpgrade = configObject.getBooleanField("enableCallUpgrade") == JNI_TRUE;
|
||||
tgVoipConfig.logPath = jni::JavaStringToStdString(env, configObject.getStringField("logPath"));
|
||||
tgVoipConfig.maxApiLayer = configObject.getIntField("maxApiLayer");
|
||||
}
|
||||
|
||||
TgVoipEndpointType parseTgVoipEndpointType(JNIEnv *env, jint endpointType) {
|
||||
switch (endpointType) {
|
||||
case org_telegram_messenger_voip_TgVoip_ENDPOINT_TYPE_INET:
|
||||
return TgVoipEndpointType::Inet;
|
||||
case org_telegram_messenger_voip_TgVoip_ENDPOINT_TYPE_LAN:
|
||||
return TgVoipEndpointType::Lan;
|
||||
case org_telegram_messenger_voip_TgVoip_ENDPOINT_TYPE_TCP_RELAY:
|
||||
return TgVoipEndpointType::TcpRelay;
|
||||
case org_telegram_messenger_voip_TgVoip_ENDPOINT_TYPE_UDP_RELAY:
|
||||
return TgVoipEndpointType::UdpRelay;
|
||||
default:
|
||||
throwNewJavaIllegalArgumentException(env, std::string("Unknown endpoint type: ").append(std::to_string(endpointType)).c_str());
|
||||
return TgVoipEndpointType::UdpRelay;
|
||||
}
|
||||
}
|
||||
|
||||
void parseTgVoipEndpoint(JNIEnv *env, jobject endpoint, TgVoipEndpoint &tgVoipEndpoint) {
|
||||
JavaObject endpointObject(env, endpoint);
|
||||
tgVoipEndpoint.endpointId = endpointObject.getLongField("id");
|
||||
tgVoipEndpoint.host = jni::JavaStringToStdString(env, endpointObject.getStringField("ipv4"));
|
||||
tgVoipEndpoint.port = static_cast<uint16_t>(endpointObject.getIntField("port"));
|
||||
tgVoipEndpoint.type = parseTgVoipEndpointType(env, endpointObject.getIntField("type"));
|
||||
jbyteArray peerTag = endpointObject.getByteArrayField("peerTag");
|
||||
if (peerTag && env->GetArrayLength(peerTag)) {
|
||||
jbyte *peerTagBytes = env->GetByteArrayElements(peerTag, nullptr);
|
||||
memcpy(tgVoipEndpoint.peerTag, peerTagBytes, 16);
|
||||
env->ReleaseByteArrayElements(peerTag, peerTagBytes, JNI_ABORT);
|
||||
}
|
||||
}
|
||||
|
||||
void parseTgVoipEndpoints(JNIEnv *env, jobjectArray endpoints, std::vector<TgVoipEndpoint> &tgVoipEndpoints) {
|
||||
for (int i = 0, size = env->GetArrayLength(endpoints); i < size; i++) {
|
||||
TgVoipEndpoint tgVoipEndpoint;
|
||||
parseTgVoipEndpoint(env, env->GetObjectArrayElement(endpoints, i), tgVoipEndpoint);
|
||||
tgVoipEndpoints.push_back(tgVoipEndpoint);
|
||||
}
|
||||
}
|
||||
|
||||
void parseTgVoipEncryptionKey(JNIEnv *env, jobject encryptionKey, TgVoipEncryptionKey &tgVoipEncryptionKey) {
|
||||
JavaObject encryptionKeyObject(env, encryptionKey);
|
||||
tgVoipEncryptionKey.isOutgoing = encryptionKeyObject.getBooleanField("isOutgoing") == JNI_TRUE;
|
||||
jbyteArray valueByteArray = encryptionKeyObject.getByteArrayField("value");
|
||||
auto *valueBytes = (uint8_t *) env->GetByteArrayElements(valueByteArray, nullptr);
|
||||
tgVoipEncryptionKey.value = std::vector<uint8_t>(valueBytes, valueBytes + env->GetArrayLength(valueByteArray));
|
||||
env->ReleaseByteArrayElements(valueByteArray, (jbyte *) valueBytes, JNI_ABORT);
|
||||
}
|
||||
|
||||
void parseTgVoipProxy(JNIEnv *env, jobject proxy, std::unique_ptr<TgVoipProxy> &tgVoipProxy) {
|
||||
if (!env->IsSameObject(proxy, nullptr)) {
|
||||
JavaObject proxyObject(env, proxy);
|
||||
tgVoipProxy = std::unique_ptr<TgVoipProxy>(new TgVoipProxy);
|
||||
tgVoipProxy->host = jni::JavaStringToStdString(env, proxyObject.getStringField("host"));
|
||||
tgVoipProxy->port = static_cast<uint16_t>(proxyObject.getIntField("port"));
|
||||
tgVoipProxy->login = jni::JavaStringToStdString(env, proxyObject.getStringField("login"));
|
||||
tgVoipProxy->password = jni::JavaStringToStdString(env, proxyObject.getStringField("password"));
|
||||
} else {
|
||||
tgVoipProxy = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
jint asJavaState(const TgVoipState &tgVoipState) {
|
||||
switch (tgVoipState) {
|
||||
case TgVoipState::WaitInit:
|
||||
return org_telegram_messenger_voip_TgVoip_STATE_WAIT_INIT;
|
||||
case TgVoipState::WaitInitAck:
|
||||
return org_telegram_messenger_voip_TgVoip_STATE_WAIT_INIT_ACK;
|
||||
case TgVoipState::Estabilished:
|
||||
return org_telegram_messenger_voip_TgVoip_STATE_ESTABLISHED;
|
||||
case TgVoipState::Failed:
|
||||
return org_telegram_messenger_voip_TgVoip_STATE_FAILED;
|
||||
case TgVoipState::Reconnecting:
|
||||
return org_telegram_messenger_voip_TgVoip_STATE_RECONNECTING;
|
||||
}
|
||||
}
|
||||
|
||||
jobject asJavaTrafficStats(JNIEnv *env, const TgVoipTrafficStats &trafficStats) {
|
||||
jclass clazz = env->FindClass("org/telegram/messenger/voip/TgVoip$TrafficStats");
|
||||
jmethodID initMethodId = env->GetMethodID(clazz, "<init>", "(JJJJ)V");
|
||||
return env->NewObject(clazz, initMethodId, trafficStats.bytesSentWifi, trafficStats.bytesReceivedWifi, trafficStats.bytesSentMobile, trafficStats.bytesReceivedMobile);
|
||||
}
|
||||
|
||||
jobject asJavaFinalState(JNIEnv *env, const TgVoipFinalState &tgVoipFinalState) {
|
||||
jbyteArray persistentState = copyVectorToJavaByteArray(env, tgVoipFinalState.persistentState.value);
|
||||
jstring debugLog = env->NewStringUTF(tgVoipFinalState.debugLog.c_str());
|
||||
jobject trafficStats = asJavaTrafficStats(env, tgVoipFinalState.trafficStats);
|
||||
auto isRatingSuggested = static_cast<jboolean>(tgVoipFinalState.isRatingSuggested);
|
||||
jclass finalStateClass = env->FindClass("org/telegram/messenger/voip/TgVoip$FinalState");
|
||||
jmethodID finalStateInitMethodId = env->GetMethodID(finalStateClass, "<init>", "([BLjava/lang/String;Lorg/telegram/messenger/voip/TgVoip$TrafficStats;Z)V");
|
||||
return env->NewObject(finalStateClass, finalStateInitMethodId, persistentState, debugLog, trafficStats, isRatingSuggested);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
#pragma mark - Static JNI Methods
|
||||
|
||||
JNIEXPORT jlong JNICALL Java_org_telegram_messenger_voip_NativeTgVoipDelegate_makeNativeInstance(JNIEnv *env, jobject obj, jobject instanceObj, jobject config, jstring persistentStateFilePath, jobjectArray endpoints, jobject proxy, jint networkType, jobject encryptionKey) {
|
||||
// reading persistent state
|
||||
TgVoipPersistentState tgVoipPersistentState;
|
||||
readTgVoipPersistentState(jni::JavaStringToStdString(env, persistentStateFilePath).c_str(), tgVoipPersistentState);
|
||||
|
||||
// parsing config
|
||||
TgVoipConfig tgVoipConfig;
|
||||
parseTgVoipConfig(env, config, tgVoipConfig);
|
||||
|
||||
// parsing endpoints
|
||||
std::vector<TgVoipEndpoint> tgVoipEndpoints;
|
||||
parseTgVoipEndpoints(env, endpoints, tgVoipEndpoints);
|
||||
|
||||
// parsing proxy
|
||||
std::unique_ptr<TgVoipProxy> tgVoipProxy;
|
||||
parseTgVoipProxy(env, proxy, tgVoipProxy);
|
||||
|
||||
// parse encryption key
|
||||
TgVoipEncryptionKey tgVoipEncryptionKey;
|
||||
parseTgVoipEncryptionKey(env, encryptionKey, tgVoipEncryptionKey);
|
||||
|
||||
TgVoip *tgVoip = TgVoip::makeInstance(tgVoipConfig, tgVoipPersistentState, tgVoipEndpoints, tgVoipProxy, parseTgVoipNetworkType(networkType), tgVoipEncryptionKey);
|
||||
|
||||
if (env->ExceptionCheck() == JNI_TRUE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
jobject globalRef = env->NewGlobalRef(instanceObj);
|
||||
|
||||
tgVoip->setOnStateUpdated([globalRef](TgVoipState tgVoipState) {
|
||||
jint state = asJavaState(tgVoipState);
|
||||
jni::DoWithJNI([globalRef, state](JNIEnv *env) {
|
||||
env->CallVoidMethod(globalRef, env->GetMethodID(env->GetObjectClass(globalRef), "onStateUpdated", "(I)V"), state);
|
||||
});
|
||||
});
|
||||
|
||||
tgVoip->setOnSignalBarsUpdated([globalRef](int signalBars) {
|
||||
jni::DoWithJNI([globalRef, signalBars](JNIEnv *env) {
|
||||
env->CallVoidMethod(globalRef, env->GetMethodID(env->GetObjectClass(globalRef), "onSignalBarsUpdated", "(I)V"), signalBars);
|
||||
});
|
||||
});
|
||||
|
||||
auto *instance = new InstanceHolder;
|
||||
instance->nativeInstance = tgVoip;
|
||||
instance->javaInstance = globalRef;
|
||||
return reinterpret_cast<jlong>(instance);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_telegram_messenger_voip_NativeTgVoipDelegate_setGlobalServerConfig(JNIEnv *env, jobject obj, jstring serverConfigJson) {
|
||||
TgVoip::setGlobalServerConfig(jni::JavaStringToStdString(env, serverConfigJson));
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_org_telegram_messenger_voip_NativeTgVoipDelegate_getConnectionMaxLayer(JNIEnv *env, jobject obj) {
|
||||
return TgVoip::getConnectionMaxLayer();
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_org_telegram_messenger_voip_NativeTgVoipDelegate_getVersion(JNIEnv *env, jobject obj) {
|
||||
return env->NewStringUTF(TgVoip::getVersion().c_str());
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_telegram_messenger_voip_NativeTgVoipDelegate_setBufferSize(JNIEnv *env, jobject obj, jint size) {
|
||||
tgvoip::audio::AudioOutputOpenSLES::nativeBufferSize = (unsigned int) size;
|
||||
tgvoip::audio::AudioInputOpenSLES::nativeBufferSize = (unsigned int) size;
|
||||
}
|
||||
|
||||
#pragma mark - Virtual JNI Methods
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_telegram_messenger_voip_NativeTgVoipInstance_setNetworkType(JNIEnv *env, jobject obj, jint networkType) {
|
||||
getTgVoip(env, obj)->setNetworkType(parseTgVoipNetworkType(networkType));
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_telegram_messenger_voip_NativeTgVoipInstance_setMuteMicrophone(JNIEnv *env, jobject obj, jboolean muteMicrophone) {
|
||||
getTgVoip(env, obj)->setMuteMicrophone(muteMicrophone);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_telegram_messenger_voip_NativeTgVoipInstance_setAudioOutputGainControlEnabled(JNIEnv *env, jobject obj, jboolean enabled) {
|
||||
getTgVoip(env, obj)->setAudioOutputGainControlEnabled(enabled);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_telegram_messenger_voip_NativeTgVoipInstance_setEchoCancellationStrength(JNIEnv *env, jobject obj, jint strength) {
|
||||
getTgVoip(env, obj)->setEchoCancellationStrength(strength);
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_org_telegram_messenger_voip_NativeTgVoipInstance_getLastError(JNIEnv *env, jobject obj) {
|
||||
return env->NewStringUTF(getTgVoip(env, obj)->getLastError().c_str());
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_org_telegram_messenger_voip_NativeTgVoipInstance_getDebugInfo(JNIEnv *env, jobject obj) {
|
||||
return env->NewStringUTF(getTgVoip(env, obj)->getDebugInfo().c_str());
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_org_telegram_messenger_voip_NativeTgVoipInstance_getPreferredRelayId(JNIEnv *env, jobject obj) {
|
||||
return getTgVoip(env, obj)->getPreferredRelayId();
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_org_telegram_messenger_voip_NativeTgVoipInstance_getTrafficStats(JNIEnv *env, jobject obj) {
|
||||
return asJavaTrafficStats(env, getTgVoip(env, obj)->getTrafficStats());
|
||||
}
|
||||
|
||||
JNIEXPORT jbyteArray JNICALL
|
||||
Java_org_telegram_messenger_voip_NativeTgVoipInstance_getPersistentState(JNIEnv *env, jobject obj) {
|
||||
return copyVectorToJavaByteArray(env, getTgVoip(env, obj)->getPersistentState().value);
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_org_telegram_messenger_voip_NativeTgVoipInstance_stop(JNIEnv *env, jobject obj) {
|
||||
InstanceHolder *instance = getInstanceHolder(env, obj);
|
||||
TgVoipFinalState tgVoipFinalState = instance->nativeInstance->stop();
|
||||
|
||||
// saving persistent state
|
||||
const std::string &path = jni::JavaStringToStdString(env, JavaObject(env, obj).getStringField("persistentStateFilePath"));
|
||||
saveTgVoipPersistentState(path.c_str(), tgVoipFinalState.persistentState);
|
||||
|
||||
// clean
|
||||
env->DeleteGlobalRef(instance->javaInstance);
|
||||
delete instance->nativeInstance;
|
||||
delete instance;
|
||||
|
||||
return asJavaFinalState(env, tgVoipFinalState);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
#include <jni.h>
|
||||
|
||||
#ifndef _Included_org_telegram_messenger_voip_TgVoip
|
||||
#define _Included_org_telegram_messenger_voip_TgVoip
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#undef org_telegram_messenger_voip_TgVoip_NET_TYPE_UNKNOWN
|
||||
#define org_telegram_messenger_voip_TgVoip_NET_TYPE_UNKNOWN 0L
|
||||
#undef org_telegram_messenger_voip_TgVoip_NET_TYPE_GPRS
|
||||
#define org_telegram_messenger_voip_TgVoip_NET_TYPE_GPRS 1L
|
||||
#undef org_telegram_messenger_voip_TgVoip_NET_TYPE_EDGE
|
||||
#define org_telegram_messenger_voip_TgVoip_NET_TYPE_EDGE 2L
|
||||
#undef org_telegram_messenger_voip_TgVoip_NET_TYPE_3G
|
||||
#define org_telegram_messenger_voip_TgVoip_NET_TYPE_3G 3L
|
||||
#undef org_telegram_messenger_voip_TgVoip_NET_TYPE_HSPA
|
||||
#define org_telegram_messenger_voip_TgVoip_NET_TYPE_HSPA 4L
|
||||
#undef org_telegram_messenger_voip_TgVoip_NET_TYPE_LTE
|
||||
#define org_telegram_messenger_voip_TgVoip_NET_TYPE_LTE 5L
|
||||
#undef org_telegram_messenger_voip_TgVoip_NET_TYPE_WIFI
|
||||
#define org_telegram_messenger_voip_TgVoip_NET_TYPE_WIFI 6L
|
||||
#undef org_telegram_messenger_voip_TgVoip_NET_TYPE_ETHERNET
|
||||
#define org_telegram_messenger_voip_TgVoip_NET_TYPE_ETHERNET 7L
|
||||
#undef org_telegram_messenger_voip_TgVoip_NET_TYPE_OTHER_HIGH_SPEED
|
||||
#define org_telegram_messenger_voip_TgVoip_NET_TYPE_OTHER_HIGH_SPEED 8L
|
||||
#undef org_telegram_messenger_voip_TgVoip_NET_TYPE_OTHER_LOW_SPEED
|
||||
#define org_telegram_messenger_voip_TgVoip_NET_TYPE_OTHER_LOW_SPEED 9L
|
||||
#undef org_telegram_messenger_voip_TgVoip_NET_TYPE_DIALUP
|
||||
#define org_telegram_messenger_voip_TgVoip_NET_TYPE_DIALUP 10L
|
||||
#undef org_telegram_messenger_voip_TgVoip_NET_TYPE_OTHER_MOBILE
|
||||
#define org_telegram_messenger_voip_TgVoip_NET_TYPE_OTHER_MOBILE 11L
|
||||
#undef org_telegram_messenger_voip_TgVoip_ENDPOINT_TYPE_INET
|
||||
#define org_telegram_messenger_voip_TgVoip_ENDPOINT_TYPE_INET 0L
|
||||
#undef org_telegram_messenger_voip_TgVoip_ENDPOINT_TYPE_LAN
|
||||
#define org_telegram_messenger_voip_TgVoip_ENDPOINT_TYPE_LAN 1L
|
||||
#undef org_telegram_messenger_voip_TgVoip_ENDPOINT_TYPE_UDP_RELAY
|
||||
#define org_telegram_messenger_voip_TgVoip_ENDPOINT_TYPE_UDP_RELAY 2L
|
||||
#undef org_telegram_messenger_voip_TgVoip_ENDPOINT_TYPE_TCP_RELAY
|
||||
#define org_telegram_messenger_voip_TgVoip_ENDPOINT_TYPE_TCP_RELAY 3L
|
||||
#undef org_telegram_messenger_voip_TgVoip_STATE_WAIT_INIT
|
||||
#define org_telegram_messenger_voip_TgVoip_STATE_WAIT_INIT 1L
|
||||
#undef org_telegram_messenger_voip_TgVoip_STATE_WAIT_INIT_ACK
|
||||
#define org_telegram_messenger_voip_TgVoip_STATE_WAIT_INIT_ACK 2L
|
||||
#undef org_telegram_messenger_voip_TgVoip_STATE_ESTABLISHED
|
||||
#define org_telegram_messenger_voip_TgVoip_STATE_ESTABLISHED 3L
|
||||
#undef org_telegram_messenger_voip_TgVoip_STATE_FAILED
|
||||
#define org_telegram_messenger_voip_TgVoip_STATE_FAILED 4L
|
||||
#undef org_telegram_messenger_voip_TgVoip_STATE_RECONNECTING
|
||||
#define org_telegram_messenger_voip_TgVoip_STATE_RECONNECTING 5L
|
||||
#undef org_telegram_messenger_voip_TgVoip_DATA_SAVING_NEVER
|
||||
#define org_telegram_messenger_voip_TgVoip_DATA_SAVING_NEVER 0L
|
||||
#undef org_telegram_messenger_voip_TgVoip_DATA_SAVING_MOBILE
|
||||
#define org_telegram_messenger_voip_TgVoip_DATA_SAVING_MOBILE 1L
|
||||
#undef org_telegram_messenger_voip_TgVoip_DATA_SAVING_ALWAYS
|
||||
#define org_telegram_messenger_voip_TgVoip_DATA_SAVING_ALWAYS 2L
|
||||
#undef org_telegram_messenger_voip_TgVoip_DATA_SAVING_ROAMING
|
||||
#define org_telegram_messenger_voip_TgVoip_DATA_SAVING_ROAMING 3L
|
||||
#undef org_telegram_messenger_voip_TgVoip_PEER_CAP_GROUP_CALLS
|
||||
#define org_telegram_messenger_voip_TgVoip_PEER_CAP_GROUP_CALLS 1L
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -21,6 +21,7 @@
|
|||
#include "../../os/android/JNIUtilities.h"
|
||||
#include "../../PrivateDefines.h"
|
||||
#include "../../logging.h"
|
||||
#include "../../../c_utils.h"
|
||||
|
||||
#ifdef TGVOIP_HAS_CONFIG
|
||||
#include <tgvoip_config.h>
|
||||
|
@ -560,7 +561,20 @@ namespace tgvoip {
|
|||
}
|
||||
}
|
||||
|
||||
extern "C" void tgvoipRegisterNatives(JNIEnv* env){
|
||||
extern "C" int tgvoipOnJniLoad(JavaVM *vm, JNIEnv *env);
|
||||
|
||||
extern "C" jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
JNIEnv *env = 0;
|
||||
srand(time(NULL));
|
||||
|
||||
if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tgvoipOnJniLoad(vm, env) != JNI_TRUE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
jclass controller=env->FindClass(TGVOIP_PACKAGE_PATH "/VoIPController");
|
||||
jclass groupController=env->FindClass(TGVOIP_PACKAGE_PATH "/VoIPGroupController");
|
||||
if(env->ExceptionCheck()){
|
||||
|
@ -730,4 +744,6 @@ extern "C" void tgvoipRegisterNatives(JNIEnv* env){
|
|||
};
|
||||
env->RegisterNatives(vlog, vlogMethods, sizeof(vlogMethods)/sizeof(JNINativeMethod));
|
||||
}
|
||||
}
|
||||
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
|
@ -16,10 +16,15 @@ extern JavaVM* sharedJVM;
|
|||
namespace tgvoip{
|
||||
namespace jni{
|
||||
|
||||
inline void DoWithJNI(std::function<void(JNIEnv*)> f){
|
||||
JNIEnv *env=NULL;
|
||||
bool didAttach=false;
|
||||
inline JNIEnv *GetEnv() {
|
||||
JNIEnv *env = nullptr;
|
||||
sharedJVM->GetEnv((void **) &env, JNI_VERSION_1_6);
|
||||
return env;
|
||||
}
|
||||
|
||||
inline void DoWithJNI(std::function<void(JNIEnv*)> f){
|
||||
JNIEnv *env=GetEnv();
|
||||
bool didAttach=false;
|
||||
if(!env){
|
||||
sharedJVM->AttachCurrentThread(&env, NULL);
|
||||
didAttach=true;
|
||||
|
@ -59,7 +64,6 @@ namespace tgvoip{
|
|||
env->ReleaseByteArrayElements(arr, elements, 0);
|
||||
return arr;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,9 @@ class AudioOutputAudioUnit;
|
|||
std::string currentInputDevice;
|
||||
std::string currentOutputDevice;
|
||||
bool duckingEnabled=true;
|
||||
#ifndef TGVOIP_NO_OSX_PRIVATE_API
|
||||
bool actualDuckingEnabled=true;
|
||||
#endif // TGVOIP_NO_OSX_PRIVATE_API
|
||||
AudioDeviceID currentOutputDeviceID;
|
||||
#endif
|
||||
AudioComponentInstance unit;
|
||||
|
|
|
@ -193,7 +193,7 @@ AudioPulse::AudioPulse(std::string inputDevice, std::string outputDevice){
|
|||
isLocked=false;
|
||||
|
||||
output=new AudioOutputPulse(context, mainloop, outputDevice);
|
||||
input=new AudioInputPulse(context, mainloop, outputDevice);
|
||||
input=new AudioInputPulse(context, mainloop, inputDevice);
|
||||
}
|
||||
|
||||
AudioPulse::~AudioPulse(){
|
||||
|
|
26
TMessagesProj/jni/libtgvoip2/.gitignore
vendored
Normal file
26
TMessagesProj/jni/libtgvoip2/.gitignore
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
.DS_Store
|
||||
bin
|
||||
.idea
|
||||
build
|
||||
*/Debug/*
|
||||
*/Release/*
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
[Pp]review/
|
||||
[Pp]roduction/
|
||||
x64/
|
||||
x86/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
DerivedData/
|
||||
|
||||
# Visual Studio 2015 cache/options directory
|
||||
.vs/
|
||||
|
||||
xcuserdata/
|
||||
autom4te.cache/
|
560
TMessagesProj/jni/libtgvoip2/Android.mk
Normal file
560
TMessagesProj/jni/libtgvoip2/Android.mk
Normal file
|
@ -0,0 +1,560 @@
|
|||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
LOCAL_MODULE := tgvoip${TGVOIP_NATIVE_VERSION}
|
||||
LOCAL_CPPFLAGS := -Wall -std=c++11 -DANDROID -finline-functions -ffast-math -Os -fno-strict-aliasing -O3 -frtti -D__STDC_LIMIT_MACROS -Wno-unknown-pragmas
|
||||
LOCAL_CPPFLAGS += -DBSD=1 -funroll-loops
|
||||
LOCAL_CFLAGS := -O3 -DUSE_KISS_FFT -fexceptions -DWEBRTC_APM_DEBUG_DUMP=0 -DWEBRTC_POSIX -DWEBRTC_ANDROID -D__STDC_LIMIT_MACROS -DWEBRTC_NS_FLOAT
|
||||
LOCAL_CFLAGS += -DNULL=0 -DSOCKLEN_T=socklen_t -DLOCALE_NOT_USED -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64
|
||||
LOCAL_CFLAGS += -Drestrict='' -D__EMX__ -DOPUS_BUILD -DFIXED_POINT -DUSE_ALLOCA -DHAVE_LRINT -DHAVE_LRINTF -fno-math-errno
|
||||
LOCAL_LDLIBS := -llog -lOpenSLES
|
||||
LOCAL_STATIC_LIBRARIES := crypto
|
||||
|
||||
MY_DIR := libtgvoip2
|
||||
|
||||
LOCAL_C_INCLUDES := \
|
||||
$(LOCAL_PATH)/../opus/include \
|
||||
$(LOCAL_PATH)/../opus/silk \
|
||||
$(LOCAL_PATH)/../opus/silk/fixed \
|
||||
$(LOCAL_PATH)/../opus/celt \
|
||||
$(LOCAL_PATH)/../opus/ \
|
||||
$(LOCAL_PATH)/../opus/opusfile \
|
||||
$(LOCAL_PATH)/../boringssl/include/ \
|
||||
$(LOCAL_PATH)/webrtc_dsp/
|
||||
|
||||
ifeq ($(TARGET_ARCH_ABI),$(filter $(TARGET_ARCH_ABI),armeabi-v7a arm64-v8a))
|
||||
CC_NEON := cc.neon
|
||||
LOCAL_CFLAGS += -DWEBRTC_HAS_NEON
|
||||
else
|
||||
CC_NEON := cc
|
||||
endif
|
||||
|
||||
LOCAL_CFLAGS += $(TGVOIP_ADDITIONAL_CFLAGS)
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
./logging.cpp \
|
||||
./TgVoip.cpp \
|
||||
./VoIPController.cpp \
|
||||
./VoIPGroupController.cpp \
|
||||
./Buffers.cpp \
|
||||
./BlockingQueue.cpp \
|
||||
./audio/AudioInput.cpp \
|
||||
./os/android/AudioInputOpenSLES.cpp \
|
||||
./MediaStreamItf.cpp \
|
||||
./audio/AudioOutput.cpp \
|
||||
./OpusEncoder.cpp \
|
||||
./os/android/AudioOutputOpenSLES.cpp \
|
||||
./JitterBuffer.cpp \
|
||||
./OpusDecoder.cpp \
|
||||
./os/android/OpenSLEngineWrapper.cpp \
|
||||
./os/android/AudioInputAndroid.cpp \
|
||||
./os/android/AudioOutputAndroid.cpp \
|
||||
./EchoCanceller.cpp \
|
||||
./CongestionControl.cpp \
|
||||
./VoIPServerConfig.cpp \
|
||||
./audio/Resampler.cpp \
|
||||
./NetworkSocket.cpp \
|
||||
./os/posix/NetworkSocketPosix.cpp \
|
||||
./PacketReassembler.cpp \
|
||||
./MessageThread.cpp \
|
||||
./json11.cpp \
|
||||
./audio/AudioIO.cpp \
|
||||
./video/VideoRenderer.cpp \
|
||||
./video/VideoSource.cpp \
|
||||
./video/ScreamCongestionController.cpp \
|
||||
./os/android/VideoSourceAndroid.cpp \
|
||||
./os/android/VideoRendererAndroid.cpp \
|
||||
./client/android/org_telegram_messenger_voip_TgVoip.cpp \
|
||||
./client/android/tg_voip_jni.cpp
|
||||
|
||||
# WebRTC signal processing
|
||||
|
||||
LOCAL_SRC_FILES += \
|
||||
./webrtc_dsp/system_wrappers/source/field_trial.cc \
|
||||
./webrtc_dsp/system_wrappers/source/metrics.cc \
|
||||
./webrtc_dsp/system_wrappers/source/cpu_features.cc \
|
||||
./webrtc_dsp/absl/strings/internal/memutil.cc \
|
||||
./webrtc_dsp/absl/strings/string_view.cc \
|
||||
./webrtc_dsp/absl/strings/ascii.cc \
|
||||
./webrtc_dsp/absl/types/bad_optional_access.cc \
|
||||
./webrtc_dsp/absl/types/optional.cc \
|
||||
./webrtc_dsp/absl/base/internal/raw_logging.cc \
|
||||
./webrtc_dsp/absl/base/internal/throw_delegate.cc \
|
||||
./webrtc_dsp/rtc_base/race_checker.cc \
|
||||
./webrtc_dsp/rtc_base/strings/string_builder.cc \
|
||||
./webrtc_dsp/rtc_base/memory/aligned_malloc.cc \
|
||||
./webrtc_dsp/rtc_base/timeutils.cc \
|
||||
./webrtc_dsp/rtc_base/platform_file.cc \
|
||||
./webrtc_dsp/rtc_base/string_to_number.cc \
|
||||
./webrtc_dsp/rtc_base/thread_checker_impl.cc \
|
||||
./webrtc_dsp/rtc_base/stringencode.cc \
|
||||
./webrtc_dsp/rtc_base/stringutils.cc \
|
||||
./webrtc_dsp/rtc_base/checks.cc \
|
||||
./webrtc_dsp/rtc_base/platform_thread.cc \
|
||||
./webrtc_dsp/rtc_base/criticalsection.cc \
|
||||
./webrtc_dsp/rtc_base/platform_thread_types.cc \
|
||||
./webrtc_dsp/rtc_base/event.cc \
|
||||
./webrtc_dsp/rtc_base/event_tracer.cc \
|
||||
./webrtc_dsp/rtc_base/logging_webrtc.cc \
|
||||
./webrtc_dsp/third_party/rnnoise/src/rnn_vad_weights.cc \
|
||||
./webrtc_dsp/third_party/rnnoise/src/kiss_fft.cc \
|
||||
./webrtc_dsp/api/audio/audio_frame.cc \
|
||||
./webrtc_dsp/api/audio/echo_canceller3_config.cc \
|
||||
./webrtc_dsp/api/audio/echo_canceller3_factory.cc \
|
||||
./webrtc_dsp/modules/third_party/fft/fft.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/pitch_estimator.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/arith_routines_logist.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/filterbanks.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/transform.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/pitch_filter.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/filter_functions.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/decode.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/lattice.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/intialize.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/lpc_tables.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/encode.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/lpc_analysis.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/arith_routines_hist.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/entropy_coding.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/isac_vad.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/arith_routines.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/crc.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/decode_bwe.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/isac.c \
|
||||
./webrtc_dsp/modules/audio_processing/rms_level.cc \
|
||||
./webrtc_dsp/modules/audio_processing/echo_detector/normalized_covariance_estimator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/echo_detector/moving_max.cc \
|
||||
./webrtc_dsp/modules/audio_processing/echo_detector/circular_buffer.cc \
|
||||
./webrtc_dsp/modules/audio_processing/echo_detector/mean_variance_estimator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/splitting_filter.cc \
|
||||
./webrtc_dsp/modules/audio_processing/gain_control_impl.cc \
|
||||
./webrtc_dsp/modules/audio_processing/ns/nsx_core.c \
|
||||
./webrtc_dsp/modules/audio_processing/ns/noise_suppression_x.c \
|
||||
./webrtc_dsp/modules/audio_processing/ns/nsx_core_c.c \
|
||||
./webrtc_dsp/modules/audio_processing/ns/ns_core.c \
|
||||
./webrtc_dsp/modules/audio_processing/ns/noise_suppression.c \
|
||||
./webrtc_dsp/modules/audio_processing/audio_buffer.cc \
|
||||
./webrtc_dsp/modules/audio_processing/typing_detection.cc \
|
||||
./webrtc_dsp/modules/audio_processing/include/audio_processing_statistics.cc \
|
||||
./webrtc_dsp/modules/audio_processing/include/audio_generator_factory.cc \
|
||||
./webrtc_dsp/modules/audio_processing/include/aec_dump.cc \
|
||||
./webrtc_dsp/modules/audio_processing/include/audio_processing.cc \
|
||||
./webrtc_dsp/modules/audio_processing/include/config.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/interpolated_gain_curve.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/agc2_common.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/gain_applier.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/adaptive_agc.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/adaptive_digital_gain_applier.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/limiter.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/saturation_protector.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/rnn_vad/spectral_features_internal.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/rnn_vad/rnn.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/rnn_vad/pitch_search_internal.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/rnn_vad/spectral_features.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/rnn_vad/pitch_search.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/rnn_vad/features_extraction.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/rnn_vad/fft_util.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/rnn_vad/lp_residual.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/adaptive_mode_level_estimator_agc.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/vector_float_frame.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/noise_level_estimator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/agc2_testing_common.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/fixed_digital_level_estimator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/fixed_gain_controller.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/vad_with_level.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/limiter_db_gain_curve.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/down_sampler.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/signal_classifier.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/noise_spectrum_estimator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/compute_interpolated_gain_curve.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/biquad_filter.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/adaptive_mode_level_estimator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/transient/moving_moments.cc \
|
||||
./webrtc_dsp/modules/audio_processing/transient/wpd_tree.cc \
|
||||
./webrtc_dsp/modules/audio_processing/transient/wpd_node.cc \
|
||||
./webrtc_dsp/modules/audio_processing/transient/transient_suppressor.cc \
|
||||
./webrtc_dsp/modules/audio_processing/transient/transient_detector.cc \
|
||||
./webrtc_dsp/modules/audio_processing/low_cut_filter.cc \
|
||||
./webrtc_dsp/modules/audio_processing/level_estimator_impl.cc \
|
||||
./webrtc_dsp/modules/audio_processing/three_band_filter_bank.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec/echo_cancellation.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec/aec_resampler.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec/aec_core.cc \
|
||||
./webrtc_dsp/modules/audio_processing/voice_detection_impl.cc \
|
||||
./webrtc_dsp/modules/audio_processing/echo_cancellation_impl.cc \
|
||||
./webrtc_dsp/modules/audio_processing/gain_control_for_experimental_agc.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc/agc.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc/loudness_histogram.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc/agc_manager_direct.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc/legacy/analog_agc.c \
|
||||
./webrtc_dsp/modules/audio_processing/agc/legacy/digital_agc.c \
|
||||
./webrtc_dsp/modules/audio_processing/agc/utility.cc \
|
||||
./webrtc_dsp/modules/audio_processing/audio_processing_impl.cc \
|
||||
./webrtc_dsp/modules/audio_processing/audio_generator/file_audio_generator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/gain_controller2.cc \
|
||||
./webrtc_dsp/modules/audio_processing/residual_echo_detector.cc \
|
||||
./webrtc_dsp/modules/audio_processing/noise_suppression_impl.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aecm/aecm_core.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aecm/aecm_core_c.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aecm/echo_control_mobile.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/render_reverb_model.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/reverb_model_fallback.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/echo_remover_metrics.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/matched_filter_lag_aggregator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/render_delay_buffer2.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/echo_path_variability.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/frame_blocker.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/subtractor.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/aec3_fft.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/fullband_erle_estimator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/suppression_filter.$(CC_NEON) \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/block_processor.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/subband_erle_estimator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/render_delay_controller_metrics.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/render_delay_buffer.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/vector_buffer.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/erl_estimator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/aec_state.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/adaptive_fir_filter.$(CC_NEON) \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/render_delay_controller.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/skew_estimator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/echo_path_delay_estimator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/block_framer.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/erle_estimator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/reverb_model.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/cascaded_biquad_filter.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/render_buffer.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/subtractor_output.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/stationarity_estimator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/render_signal_analyzer.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/subtractor_output_analyzer.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/suppression_gain.$(CC_NEON) \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/echo_audibility.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/block_processor_metrics.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/moving_average.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/reverb_model_estimator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/aec3_common.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/residual_echo_estimator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/matched_filter.$(CC_NEON) \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/reverb_decay_estimator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/render_delay_controller2.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/suppression_gain_limiter.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/main_filter_update_gain.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/echo_remover.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/downsampled_render_buffer.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/matrix_buffer.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/block_processor2.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/echo_canceller3.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/block_delay_buffer.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/fft_buffer.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/comfort_noise_generator.$(CC_NEON) \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/shadow_filter_update_gain.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/filter_analyzer.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/reverb_frequency_response.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/decimator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/echo_control_mobile_impl.cc \
|
||||
./webrtc_dsp/modules/audio_processing/logging/apm_data_dumper.cc \
|
||||
./webrtc_dsp/modules/audio_processing/vad/voice_activity_detector.cc \
|
||||
./webrtc_dsp/modules/audio_processing/vad/standalone_vad.cc \
|
||||
./webrtc_dsp/modules/audio_processing/vad/pitch_internal.cc \
|
||||
./webrtc_dsp/modules/audio_processing/vad/vad_circular_buffer.cc \
|
||||
./webrtc_dsp/modules/audio_processing/vad/vad_audio_proc.cc \
|
||||
./webrtc_dsp/modules/audio_processing/vad/pole_zero_filter.cc \
|
||||
./webrtc_dsp/modules/audio_processing/vad/pitch_based_vad.cc \
|
||||
./webrtc_dsp/modules/audio_processing/vad/gmm.cc \
|
||||
./webrtc_dsp/modules/audio_processing/utility/ooura_fft.cc \
|
||||
./webrtc_dsp/modules/audio_processing/utility/delay_estimator_wrapper.cc \
|
||||
./webrtc_dsp/modules/audio_processing/utility/delay_estimator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/utility/block_mean_calculator.cc \
|
||||
./webrtc_dsp/common_audio/window_generator.cc \
|
||||
./webrtc_dsp/common_audio/channel_buffer.cc \
|
||||
./webrtc_dsp/common_audio/fir_filter_factory.cc \
|
||||
./webrtc_dsp/common_audio/wav_header.cc \
|
||||
./webrtc_dsp/common_audio/real_fourier_ooura.cc \
|
||||
./webrtc_dsp/common_audio/audio_util.cc \
|
||||
./webrtc_dsp/common_audio/resampler/push_sinc_resampler.cc \
|
||||
./webrtc_dsp/common_audio/resampler/resampler.cc \
|
||||
./webrtc_dsp/common_audio/resampler/push_resampler.cc \
|
||||
./webrtc_dsp/common_audio/resampler/sinc_resampler.cc \
|
||||
./webrtc_dsp/common_audio/resampler/sinusoidal_linear_chirp_source.cc \
|
||||
./webrtc_dsp/common_audio/wav_file.cc \
|
||||
./webrtc_dsp/common_audio/third_party/fft4g/fft4g.c \
|
||||
./webrtc_dsp/common_audio/audio_converter.cc \
|
||||
./webrtc_dsp/common_audio/real_fourier.cc \
|
||||
./webrtc_dsp/common_audio/sparse_fir_filter.cc \
|
||||
./webrtc_dsp/common_audio/smoothing_filter.cc \
|
||||
./webrtc_dsp/common_audio/fir_filter_c.cc \
|
||||
./webrtc_dsp/common_audio/ring_buffer.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/complex_fft.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/filter_ma_fast_q12.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/levinson_durbin.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/dot_product_with_scale.cc \
|
||||
./webrtc_dsp/common_audio/signal_processing/auto_corr_to_refl_coef.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/resample_by_2_internal.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/energy.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/sqrt_of_one_minus_x_squared.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/downsample_fast.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/splitting_filter1.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/spl_init.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/lpc_to_refl_coef.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/cross_correlation.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/division_operations.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/auto_correlation.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/get_scaling_square.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/resample.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/min_max_operations.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/refl_coef_to_lpc.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/filter_ar.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/vector_scaling_operations.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/resample_fractional.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/real_fft.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/ilbc_specific_functions.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/randomization_functions.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/copy_set_operations.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/resample_by_2.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/get_hanning_window.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/resample_48khz.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/spl_inl.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/spl_sqrt.c \
|
||||
./webrtc_dsp/common_audio/vad/vad_sp.c \
|
||||
./webrtc_dsp/common_audio/vad/vad.cc \
|
||||
./webrtc_dsp/common_audio/vad/webrtc_vad.c \
|
||||
./webrtc_dsp/common_audio/vad/vad_filterbank.c \
|
||||
./webrtc_dsp/common_audio/vad/vad_core.c \
|
||||
./webrtc_dsp/common_audio/vad/vad_gmm.c
|
||||
|
||||
ifeq ($(TARGET_ARCH_ABI),$(filter $(TARGET_ARCH_ABI),armeabi-v7a arm64-v8a))
|
||||
LOCAL_SRC_FILES += \
|
||||
./webrtc_dsp/modules/audio_processing/ns/nsx_core_neon.c.neon \
|
||||
./webrtc_dsp/modules/audio_processing/aec/aec_core_neon.cc.neon \
|
||||
./webrtc_dsp/modules/audio_processing/aecm/aecm_core_neon.cc.neon \
|
||||
./webrtc_dsp/modules/audio_processing/utility/ooura_fft_neon.cc.neon \
|
||||
./webrtc_dsp/common_audio/fir_filter_neon.cc.neon \
|
||||
./webrtc_dsp/common_audio/resampler/sinc_resampler_neon.cc.neon \
|
||||
./webrtc_dsp/common_audio/signal_processing/downsample_fast_neon.c.neon \
|
||||
./webrtc_dsp/common_audio/signal_processing/min_max_operations_neon.c.neon \
|
||||
./webrtc_dsp/common_audio/signal_processing/cross_correlation_neon.c.neon
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
|
||||
LOCAL_SRC_FILES += \
|
||||
./webrtc_dsp/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor_arm.S.neon \
|
||||
./webrtc_dsp/common_audio/signal_processing/complex_bit_reverse_arm.S.neon \
|
||||
./webrtc_dsp/common_audio/signal_processing/filter_ar_fast_q12_armv7.S.neon
|
||||
else
|
||||
LOCAL_SRC_FILES += \
|
||||
./webrtc_dsp/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/complex_bit_reverse.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/filter_ar_fast_q12.c
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET_ARCH_ABI),$(filter $(TARGET_ARCH_ABI),x86 x86_64))
|
||||
LOCAL_SRC_FILES += \
|
||||
./webrtc_dsp/modules/audio_processing/aec/aec_core_sse2.cc \
|
||||
./webrtc_dsp/modules/audio_processing/utility/ooura_fft_sse2.cc \
|
||||
./webrtc_dsp/common_audio/fir_filter_sse.cc \
|
||||
./webrtc_dsp/common_audio/resampler/sinc_resampler_sse.cc
|
||||
endif
|
||||
|
||||
# Opus
|
||||
|
||||
LOCAL_SRC_FILES += \
|
||||
./../opus/src/opus.c \
|
||||
./../opus/src/opus_decoder.c \
|
||||
./../opus/src/opus_encoder.c \
|
||||
./../opus/src/opus_multistream.c \
|
||||
./../opus/src/opus_multistream_encoder.c \
|
||||
./../opus/src/opus_multistream_decoder.c \
|
||||
./../opus/src/repacketizer.c \
|
||||
./../opus/src/analysis.c \
|
||||
./../opus/src/mlp.c \
|
||||
./../opus/src/mlp_data.c \
|
||||
./../opus/src/opus_projection_encoder.c \
|
||||
./../opus/src/opus_projection_decoder.c \
|
||||
./../opus/src/mapping_matrix.c
|
||||
|
||||
ifeq ($(TARGET_ARCH_ABI),$(filter $(TARGET_ARCH_ABI),armeabi-v7a arm64-v8a))
|
||||
LOCAL_ARM_MODE := arm
|
||||
LOCAL_CPPFLAGS += -DLIBYUV_NEON
|
||||
LOCAL_CFLAGS += -DLIBYUV_NEON
|
||||
LOCAL_CFLAGS += -DOPUS_HAVE_RTCD -DOPUS_ARM_ASM
|
||||
LOCAL_SRC_FILES += \
|
||||
./../opus/celt/arm/celt_neon_intr.c.neon \
|
||||
./../opus/celt/arm/pitch_neon_intr.c.neon \
|
||||
./../opus/silk/arm/NSQ_neon.c.neon \
|
||||
./../opus/silk/arm/arm_silk_map.c \
|
||||
./../opus/silk/arm/LPC_inv_pred_gain_neon_intr.c.neon \
|
||||
./../opus/silk/arm/NSQ_del_dec_neon_intr.c.neon \
|
||||
./../opus/silk/arm/biquad_alt_neon_intr.c.neon \
|
||||
./../opus/silk/fixed/arm/warped_autocorrelation_FIX_neon_intr.c.neon
|
||||
|
||||
# LOCAL_SRC_FILES += ./../opus/celt/arm/celt_pitch_xcorr_arm-gnu.S
|
||||
|
||||
else
|
||||
ifeq ($(TARGET_ARCH_ABI),x86)
|
||||
LOCAL_CFLAGS += -Dx86fix
|
||||
LOCAL_CPPFLAGS += -Dx86fix
|
||||
LOCAL_ARM_MODE := arm
|
||||
# LOCAL_SRC_FILES += \
|
||||
# ./libyuv/source/row_x86.asm
|
||||
|
||||
# LOCAL_SRC_FILES += \
|
||||
# ./../opus/celt/x86/celt_lpc_sse.c \
|
||||
# ./../opus/celt/x86/pitch_sse.c \
|
||||
# ./../opus/celt/x86/pitch_sse2.c \
|
||||
# ./../opus/celt/x86/pitch_sse4_1.c \
|
||||
# ./../opus/celt/x86/vq_sse2.c \
|
||||
# ./../opus/celt/x86/x86_celt_map.c \
|
||||
# ./../opus/celt/x86/x86cpu.c \
|
||||
# ./../opus/silk/fixed/x86/burg_modified_FIX_sse.c \
|
||||
# ./../opus/silk/fixed/x86/vector_ops_FIX_sse.c \
|
||||
# ./../opus/silk/x86/NSQ_del_dec_sse.c \
|
||||
# ./../opus/silk/x86/NSQ_sse.c \
|
||||
# ./../opus/silk/x86/VAD_sse.c \
|
||||
# ./../opus/silk/x86/VQ_WMat_sse.c \
|
||||
# ./../opus/silk/x86/x86_silk_map.c
|
||||
endif
|
||||
endif
|
||||
|
||||
LOCAL_SRC_FILES += \
|
||||
./../opus/silk/CNG.c \
|
||||
./../opus/silk/code_signs.c \
|
||||
./../opus/silk/init_decoder.c \
|
||||
./../opus/silk/decode_core.c \
|
||||
./../opus/silk/decode_frame.c \
|
||||
./../opus/silk/decode_parameters.c \
|
||||
./../opus/silk/decode_indices.c \
|
||||
./../opus/silk/decode_pulses.c \
|
||||
./../opus/silk/decoder_set_fs.c \
|
||||
./../opus/silk/dec_API.c \
|
||||
./../opus/silk/enc_API.c \
|
||||
./../opus/silk/encode_indices.c \
|
||||
./../opus/silk/encode_pulses.c \
|
||||
./../opus/silk/gain_quant.c \
|
||||
./../opus/silk/interpolate.c \
|
||||
./../opus/silk/LP_variable_cutoff.c \
|
||||
./../opus/silk/NLSF_decode.c \
|
||||
./../opus/silk/NSQ.c \
|
||||
./../opus/silk/NSQ_del_dec.c \
|
||||
./../opus/silk/PLC.c \
|
||||
./../opus/silk/shell_coder.c \
|
||||
./../opus/silk/tables_gain.c \
|
||||
./../opus/silk/tables_LTP.c \
|
||||
./../opus/silk/tables_NLSF_CB_NB_MB.c \
|
||||
./../opus/silk/tables_NLSF_CB_WB.c \
|
||||
./../opus/silk/tables_other.c \
|
||||
./../opus/silk/tables_pitch_lag.c \
|
||||
./../opus/silk/tables_pulses_per_block.c \
|
||||
./../opus/silk/VAD.c \
|
||||
./../opus/silk/control_audio_bandwidth.c \
|
||||
./../opus/silk/quant_LTP_gains.c \
|
||||
./../opus/silk/VQ_WMat_EC.c \
|
||||
./../opus/silk/HP_variable_cutoff.c \
|
||||
./../opus/silk/NLSF_encode.c \
|
||||
./../opus/silk/NLSF_VQ.c \
|
||||
./../opus/silk/NLSF_unpack.c \
|
||||
./../opus/silk/NLSF_del_dec_quant.c \
|
||||
./../opus/silk/process_NLSFs.c \
|
||||
./../opus/silk/stereo_LR_to_MS.c \
|
||||
./../opus/silk/stereo_MS_to_LR.c \
|
||||
./../opus/silk/check_control_input.c \
|
||||
./../opus/silk/control_SNR.c \
|
||||
./../opus/silk/init_encoder.c \
|
||||
./../opus/silk/control_codec.c \
|
||||
./../opus/silk/A2NLSF.c \
|
||||
./../opus/silk/ana_filt_bank_1.c \
|
||||
./../opus/silk/biquad_alt.c \
|
||||
./../opus/silk/bwexpander_32.c \
|
||||
./../opus/silk/bwexpander.c \
|
||||
./../opus/silk/debug.c \
|
||||
./../opus/silk/decode_pitch.c \
|
||||
./../opus/silk/inner_prod_aligned.c \
|
||||
./../opus/silk/lin2log.c \
|
||||
./../opus/silk/log2lin.c \
|
||||
./../opus/silk/LPC_analysis_filter.c \
|
||||
./../opus/silk/LPC_inv_pred_gain.c \
|
||||
./../opus/silk/table_LSF_cos.c \
|
||||
./../opus/silk/NLSF2A.c \
|
||||
./../opus/silk/NLSF_stabilize.c \
|
||||
./../opus/silk/NLSF_VQ_weights_laroia.c \
|
||||
./../opus/silk/pitch_est_tables.c \
|
||||
./../opus/silk/resampler.c \
|
||||
./../opus/silk/resampler_down2_3.c \
|
||||
./../opus/silk/resampler_down2.c \
|
||||
./../opus/silk/resampler_private_AR2.c \
|
||||
./../opus/silk/resampler_private_down_FIR.c \
|
||||
./../opus/silk/resampler_private_IIR_FIR.c \
|
||||
./../opus/silk/resampler_private_up2_HQ.c \
|
||||
./../opus/silk/resampler_rom.c \
|
||||
./../opus/silk/sigm_Q15.c \
|
||||
./../opus/silk/sort.c \
|
||||
./../opus/silk/sum_sqr_shift.c \
|
||||
./../opus/silk/stereo_decode_pred.c \
|
||||
./../opus/silk/stereo_encode_pred.c \
|
||||
./../opus/silk/stereo_find_predictor.c \
|
||||
./../opus/silk/stereo_quant_pred.c \
|
||||
./../opus/silk/LPC_fit.c
|
||||
|
||||
LOCAL_SRC_FILES += \
|
||||
./../opus/silk/fixed/LTP_analysis_filter_FIX.c \
|
||||
./../opus/silk/fixed/LTP_scale_ctrl_FIX.c \
|
||||
./../opus/silk/fixed/corrMatrix_FIX.c \
|
||||
./../opus/silk/fixed/encode_frame_FIX.c \
|
||||
./../opus/silk/fixed/find_LPC_FIX.c \
|
||||
./../opus/silk/fixed/find_LTP_FIX.c \
|
||||
./../opus/silk/fixed/find_pitch_lags_FIX.c \
|
||||
./../opus/silk/fixed/find_pred_coefs_FIX.c \
|
||||
./../opus/silk/fixed/noise_shape_analysis_FIX.c \
|
||||
./../opus/silk/fixed/process_gains_FIX.c \
|
||||
./../opus/silk/fixed/regularize_correlations_FIX.c \
|
||||
./../opus/silk/fixed/residual_energy16_FIX.c \
|
||||
./../opus/silk/fixed/residual_energy_FIX.c \
|
||||
./../opus/silk/fixed/warped_autocorrelation_FIX.c \
|
||||
./../opus/silk/fixed/apply_sine_window_FIX.c \
|
||||
./../opus/silk/fixed/autocorr_FIX.c \
|
||||
./../opus/silk/fixed/burg_modified_FIX.c \
|
||||
./../opus/silk/fixed/k2a_FIX.c \
|
||||
./../opus/silk/fixed/k2a_Q16_FIX.c \
|
||||
./../opus/silk/fixed/pitch_analysis_core_FIX.c \
|
||||
./../opus/silk/fixed/vector_ops_FIX.c \
|
||||
./../opus/silk/fixed/schur64_FIX.c \
|
||||
./../opus/silk/fixed/schur_FIX.c
|
||||
|
||||
LOCAL_SRC_FILES += \
|
||||
./../opus/celt/bands.c \
|
||||
./../opus/celt/celt.c \
|
||||
./../opus/celt/celt_encoder.c \
|
||||
./../opus/celt/celt_decoder.c \
|
||||
./../opus/celt/cwrs.c \
|
||||
./../opus/celt/entcode.c \
|
||||
./../opus/celt/entdec.c \
|
||||
./../opus/celt/entenc.c \
|
||||
./../opus/celt/kiss_fft.c \
|
||||
./../opus/celt/laplace.c \
|
||||
./../opus/celt/mathops.c \
|
||||
./../opus/celt/mdct.c \
|
||||
./../opus/celt/modes.c \
|
||||
./../opus/celt/pitch.c \
|
||||
./../opus/celt/celt_lpc.c \
|
||||
./../opus/celt/quant_bands.c \
|
||||
./../opus/celt/rate.c \
|
||||
./../opus/celt/vq.c \
|
||||
./../opus/celt/arm/armcpu.c \
|
||||
./../opus/celt/arm/arm_celt_map.c
|
||||
|
||||
LOCAL_SRC_FILES += \
|
||||
./../opus/ogg/bitwise.c \
|
||||
./../opus/ogg/framing.c \
|
||||
./../opus/opusfile/info.c \
|
||||
./../opus/opusfile/internal.c \
|
||||
./../opus/opusfile/opusfile.c \
|
||||
./../opus/opusfile/stream.c
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
10
TMessagesProj/jni/libtgvoip2/BlockingQueue.cpp
Normal file
10
TMessagesProj/jni/libtgvoip2/BlockingQueue.cpp
Normal file
|
@ -0,0 +1,10 @@
|
|||
//
|
||||
// libtgvoip is free and unencumbered public domain software.
|
||||
// For more information, see http://unlicense.org or the UNLICENSE file
|
||||
// you should have received with this source code distribution.
|
||||
//
|
||||
|
||||
#include "BlockingQueue.h"
|
||||
|
||||
using namespace tgvoip;
|
||||
|
92
TMessagesProj/jni/libtgvoip2/BlockingQueue.h
Normal file
92
TMessagesProj/jni/libtgvoip2/BlockingQueue.h
Normal file
|
@ -0,0 +1,92 @@
|
|||
//
|
||||
// libtgvoip is free and unencumbered public domain software.
|
||||
// For more information, see http://unlicense.org or the UNLICENSE file
|
||||
// you should have received with this source code distribution.
|
||||
//
|
||||
|
||||
#ifndef LIBTGVOIP_BLOCKINGQUEUE_H
|
||||
#define LIBTGVOIP_BLOCKINGQUEUE_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <list>
|
||||
#include "threading.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace tgvoip{
|
||||
|
||||
using namespace std;
|
||||
|
||||
template<typename T>
|
||||
class BlockingQueue{
|
||||
public:
|
||||
TGVOIP_DISALLOW_COPY_AND_ASSIGN(BlockingQueue);
|
||||
BlockingQueue(size_t capacity) : semaphore(capacity, 0){
|
||||
this->capacity=capacity;
|
||||
overflowCallback=NULL;
|
||||
};
|
||||
|
||||
~BlockingQueue(){
|
||||
semaphore.Release();
|
||||
}
|
||||
|
||||
void Put(T thing){
|
||||
MutexGuard sync(mutex);
|
||||
queue.push_back(std::move(thing));
|
||||
bool didOverflow=false;
|
||||
while(queue.size()>capacity){
|
||||
didOverflow=true;
|
||||
if(overflowCallback){
|
||||
overflowCallback(std::move(queue.front()));
|
||||
queue.pop_front();
|
||||
}else{
|
||||
abort();
|
||||
}
|
||||
}
|
||||
if(!didOverflow)
|
||||
semaphore.Release();
|
||||
}
|
||||
|
||||
T GetBlocking(){
|
||||
semaphore.Acquire();
|
||||
MutexGuard sync(mutex);
|
||||
return GetInternal();
|
||||
}
|
||||
|
||||
T Get(){
|
||||
MutexGuard sync(mutex);
|
||||
if(queue.size()>0)
|
||||
semaphore.Acquire();
|
||||
return GetInternal();
|
||||
}
|
||||
|
||||
size_t Size(){
|
||||
return queue.size();
|
||||
}
|
||||
|
||||
void PrepareDealloc(){
|
||||
|
||||
}
|
||||
|
||||
void SetOverflowCallback(void (*overflowCallback)(T)){
|
||||
this->overflowCallback=overflowCallback;
|
||||
}
|
||||
|
||||
private:
|
||||
T GetInternal(){
|
||||
//if(queue.size()==0)
|
||||
// return NULL;
|
||||
T r=std::move(queue.front());
|
||||
queue.pop_front();
|
||||
return r;
|
||||
}
|
||||
|
||||
std::list<T> queue;
|
||||
size_t capacity;
|
||||
//tgvoip_lock_t lock;
|
||||
Semaphore semaphore;
|
||||
Mutex mutex;
|
||||
void (*overflowCallback)(T);
|
||||
};
|
||||
}
|
||||
|
||||
#endif //LIBTGVOIP_BLOCKINGQUEUE_H
|
237
TMessagesProj/jni/libtgvoip2/Buffers.cpp
Normal file
237
TMessagesProj/jni/libtgvoip2/Buffers.cpp
Normal file
|
@ -0,0 +1,237 @@
|
|||
//
|
||||
// libtgvoip is free and unencumbered public domain software.
|
||||
// For more information, see http://unlicense.org or the UNLICENSE file
|
||||
// you should have received with this source code distribution.
|
||||
//
|
||||
|
||||
#include "Buffers.h"
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
#include <stdlib.h>
|
||||
#include "logging.h"
|
||||
|
||||
using namespace tgvoip;
|
||||
|
||||
#pragma mark - BufferInputStream
|
||||
|
||||
BufferInputStream::BufferInputStream(const unsigned char* data, size_t length){
|
||||
this->buffer=data;
|
||||
this->length=length;
|
||||
offset=0;
|
||||
}
|
||||
|
||||
BufferInputStream::BufferInputStream(const Buffer &buffer){
|
||||
this->buffer=*buffer;
|
||||
this->length=buffer.Length();
|
||||
offset=0;
|
||||
}
|
||||
|
||||
BufferInputStream::~BufferInputStream(){
|
||||
|
||||
}
|
||||
|
||||
|
||||
void BufferInputStream::Seek(size_t offset){
|
||||
if(offset>length){
|
||||
throw std::out_of_range("Not enough bytes in buffer");
|
||||
}
|
||||
this->offset=offset;
|
||||
}
|
||||
|
||||
size_t BufferInputStream::GetLength(){
|
||||
return length;
|
||||
}
|
||||
|
||||
size_t BufferInputStream::GetOffset(){
|
||||
return offset;
|
||||
}
|
||||
|
||||
size_t BufferInputStream::Remaining(){
|
||||
return length-offset;
|
||||
}
|
||||
|
||||
unsigned char BufferInputStream::ReadByte(){
|
||||
EnsureEnoughRemaining(1);
|
||||
return (unsigned char)buffer[offset++];
|
||||
}
|
||||
|
||||
int32_t BufferInputStream::ReadInt32(){
|
||||
EnsureEnoughRemaining(4);
|
||||
int32_t res=((int32_t)buffer[offset] & 0xFF) |
|
||||
(((int32_t)buffer[offset+1] & 0xFF) << 8) |
|
||||
(((int32_t)buffer[offset+2] & 0xFF) << 16) |
|
||||
(((int32_t)buffer[offset+3] & 0xFF) << 24);
|
||||
offset+=4;
|
||||
return res;
|
||||
}
|
||||
|
||||
int64_t BufferInputStream::ReadInt64(){
|
||||
EnsureEnoughRemaining(8);
|
||||
int64_t res=((int64_t)buffer[offset] & 0xFF) |
|
||||
(((int64_t)buffer[offset+1] & 0xFF) << 8) |
|
||||
(((int64_t)buffer[offset+2] & 0xFF) << 16) |
|
||||
(((int64_t)buffer[offset+3] & 0xFF) << 24) |
|
||||
(((int64_t)buffer[offset+4] & 0xFF) << 32) |
|
||||
(((int64_t)buffer[offset+5] & 0xFF) << 40) |
|
||||
(((int64_t)buffer[offset+6] & 0xFF) << 48) |
|
||||
(((int64_t)buffer[offset+7] & 0xFF) << 56);
|
||||
offset+=8;
|
||||
return res;
|
||||
}
|
||||
|
||||
int16_t BufferInputStream::ReadInt16(){
|
||||
EnsureEnoughRemaining(2);
|
||||
int16_t res=(uint16_t)buffer[offset] | ((uint16_t)buffer[offset+1] << 8);
|
||||
offset+=2;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
int32_t BufferInputStream::ReadTlLength(){
|
||||
unsigned char l=ReadByte();
|
||||
if(l<254)
|
||||
return l;
|
||||
assert(length-offset>=3);
|
||||
EnsureEnoughRemaining(3);
|
||||
int32_t res=((int32_t)buffer[offset] & 0xFF) |
|
||||
(((int32_t)buffer[offset+1] & 0xFF) << 8) |
|
||||
(((int32_t)buffer[offset+2] & 0xFF) << 16);
|
||||
offset+=3;
|
||||
return res;
|
||||
}
|
||||
|
||||
void BufferInputStream::ReadBytes(unsigned char *to, size_t count){
|
||||
EnsureEnoughRemaining(count);
|
||||
memcpy(to, buffer+offset, count);
|
||||
offset+=count;
|
||||
}
|
||||
|
||||
void BufferInputStream::ReadBytes(Buffer &to){
|
||||
ReadBytes(*to, to.Length());
|
||||
}
|
||||
|
||||
BufferInputStream BufferInputStream::GetPartBuffer(size_t length, bool advance){
|
||||
EnsureEnoughRemaining(length);
|
||||
BufferInputStream s=BufferInputStream(buffer+offset, length);
|
||||
if(advance)
|
||||
offset+=length;
|
||||
return s;
|
||||
}
|
||||
|
||||
void BufferInputStream::EnsureEnoughRemaining(size_t need){
|
||||
if(length-offset<need){
|
||||
throw std::out_of_range("Not enough bytes in buffer");
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - BufferOutputStream
|
||||
|
||||
BufferOutputStream::BufferOutputStream(size_t size){
|
||||
buffer=(unsigned char*) malloc(size);
|
||||
if(!buffer)
|
||||
throw std::bad_alloc();
|
||||
offset=0;
|
||||
this->size=size;
|
||||
bufferProvided=false;
|
||||
}
|
||||
|
||||
BufferOutputStream::BufferOutputStream(unsigned char *buffer, size_t size){
|
||||
this->buffer=buffer;
|
||||
this->size=size;
|
||||
offset=0;
|
||||
bufferProvided=true;
|
||||
}
|
||||
|
||||
BufferOutputStream::~BufferOutputStream(){
|
||||
if(!bufferProvided && buffer)
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
void BufferOutputStream::WriteByte(unsigned char byte){
|
||||
this->ExpandBufferIfNeeded(1);
|
||||
buffer[offset++]=byte;
|
||||
}
|
||||
|
||||
void BufferOutputStream::WriteInt32(int32_t i){
|
||||
this->ExpandBufferIfNeeded(4);
|
||||
buffer[offset+3]=(unsigned char)((i >> 24) & 0xFF);
|
||||
buffer[offset+2]=(unsigned char)((i >> 16) & 0xFF);
|
||||
buffer[offset+1]=(unsigned char)((i >> 8) & 0xFF);
|
||||
buffer[offset]=(unsigned char)(i & 0xFF);
|
||||
offset+=4;
|
||||
}
|
||||
|
||||
void BufferOutputStream::WriteInt64(int64_t i){
|
||||
this->ExpandBufferIfNeeded(8);
|
||||
buffer[offset+7]=(unsigned char)((i >> 56) & 0xFF);
|
||||
buffer[offset+6]=(unsigned char)((i >> 48) & 0xFF);
|
||||
buffer[offset+5]=(unsigned char)((i >> 40) & 0xFF);
|
||||
buffer[offset+4]=(unsigned char)((i >> 32) & 0xFF);
|
||||
buffer[offset+3]=(unsigned char)((i >> 24) & 0xFF);
|
||||
buffer[offset+2]=(unsigned char)((i >> 16) & 0xFF);
|
||||
buffer[offset+1]=(unsigned char)((i >> 8) & 0xFF);
|
||||
buffer[offset]=(unsigned char)(i & 0xFF);
|
||||
offset+=8;
|
||||
}
|
||||
|
||||
void BufferOutputStream::WriteInt16(int16_t i){
|
||||
this->ExpandBufferIfNeeded(2);
|
||||
buffer[offset+1]=(unsigned char)((i >> 8) & 0xFF);
|
||||
buffer[offset]=(unsigned char)(i & 0xFF);
|
||||
offset+=2;
|
||||
}
|
||||
|
||||
void BufferOutputStream::WriteBytes(const unsigned char *bytes, size_t count){
|
||||
this->ExpandBufferIfNeeded(count);
|
||||
memcpy(buffer+offset, bytes, count);
|
||||
offset+=count;
|
||||
}
|
||||
|
||||
void BufferOutputStream::WriteBytes(const Buffer &buffer){
|
||||
WriteBytes(*buffer, buffer.Length());
|
||||
}
|
||||
|
||||
void BufferOutputStream::WriteBytes(const Buffer &buffer, size_t offset, size_t count){
|
||||
if(offset+count>buffer.Length())
|
||||
throw std::out_of_range("offset out of buffer bounds");
|
||||
WriteBytes(*buffer+offset, count);
|
||||
}
|
||||
|
||||
unsigned char *BufferOutputStream::GetBuffer(){
|
||||
return buffer;
|
||||
}
|
||||
|
||||
size_t BufferOutputStream::GetLength(){
|
||||
return offset;
|
||||
}
|
||||
|
||||
void BufferOutputStream::ExpandBufferIfNeeded(size_t need) {
|
||||
if (offset + need > size) {
|
||||
if (bufferProvided) {
|
||||
throw std::out_of_range("buffer overflow");
|
||||
}
|
||||
unsigned char* new_buffer;
|
||||
need = std::max(need, size_t{1024});
|
||||
new_buffer = reinterpret_cast<unsigned char*>(std::realloc(buffer, size + need));
|
||||
if (new_buffer == NULL) {
|
||||
std::free(buffer);
|
||||
buffer = NULL;
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
buffer = new_buffer;
|
||||
size += need;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BufferOutputStream::Reset(){
|
||||
offset=0;
|
||||
}
|
||||
|
||||
void BufferOutputStream::Rewind(size_t numBytes){
|
||||
if(numBytes>offset)
|
||||
throw std::out_of_range("buffer underflow");
|
||||
offset-=numBytes;
|
||||
}
|
357
TMessagesProj/jni/libtgvoip2/Buffers.h
Normal file
357
TMessagesProj/jni/libtgvoip2/Buffers.h
Normal file
|
@ -0,0 +1,357 @@
|
|||
//
|
||||
// libtgvoip is free and unencumbered public domain software.
|
||||
// For more information, see http://unlicense.org or the UNLICENSE file
|
||||
// you should have received with this source code distribution.
|
||||
//
|
||||
|
||||
#ifndef LIBTGVOIP_BUFFERINPUTSTREAM_H
|
||||
#define LIBTGVOIP_BUFFERINPUTSTREAM_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdexcept>
|
||||
#include <array>
|
||||
#include <limits>
|
||||
#include <bitset>
|
||||
#include <stddef.h>
|
||||
#include "threading.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace tgvoip{
|
||||
class Buffer;
|
||||
|
||||
class BufferInputStream{
|
||||
|
||||
public:
|
||||
BufferInputStream(const unsigned char* data, size_t length);
|
||||
BufferInputStream(const Buffer& buffer);
|
||||
~BufferInputStream();
|
||||
void Seek(size_t offset);
|
||||
size_t GetLength();
|
||||
size_t GetOffset();
|
||||
size_t Remaining();
|
||||
unsigned char ReadByte();
|
||||
int64_t ReadInt64();
|
||||
int32_t ReadInt32();
|
||||
int16_t ReadInt16();
|
||||
int32_t ReadTlLength();
|
||||
void ReadBytes(unsigned char* to, size_t count);
|
||||
void ReadBytes(Buffer& to);
|
||||
BufferInputStream GetPartBuffer(size_t length, bool advance);
|
||||
|
||||
private:
|
||||
void EnsureEnoughRemaining(size_t need);
|
||||
const unsigned char* buffer;
|
||||
size_t length;
|
||||
size_t offset;
|
||||
};
|
||||
|
||||
class BufferOutputStream{
|
||||
friend class Buffer;
|
||||
public:
|
||||
TGVOIP_DISALLOW_COPY_AND_ASSIGN(BufferOutputStream);
|
||||
BufferOutputStream(size_t size);
|
||||
BufferOutputStream(unsigned char* buffer, size_t size);
|
||||
~BufferOutputStream();
|
||||
void WriteByte(unsigned char byte);
|
||||
void WriteInt64(int64_t i);
|
||||
void WriteInt32(int32_t i);
|
||||
void WriteInt16(int16_t i);
|
||||
void WriteBytes(const unsigned char* bytes, size_t count);
|
||||
void WriteBytes(const Buffer& buffer);
|
||||
void WriteBytes(const Buffer& buffer, size_t offset, size_t count);
|
||||
unsigned char* GetBuffer();
|
||||
size_t GetLength();
|
||||
void Reset();
|
||||
void Rewind(size_t numBytes);
|
||||
|
||||
BufferOutputStream& operator=(BufferOutputStream&& other){
|
||||
if(this!=&other){
|
||||
if(!bufferProvided && buffer)
|
||||
free(buffer);
|
||||
buffer=other.buffer;
|
||||
offset=other.offset;
|
||||
size=other.size;
|
||||
bufferProvided=other.bufferProvided;
|
||||
other.buffer=NULL;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
void ExpandBufferIfNeeded(size_t need);
|
||||
unsigned char* buffer=NULL;
|
||||
size_t size;
|
||||
size_t offset;
|
||||
bool bufferProvided;
|
||||
};
|
||||
|
||||
class Buffer{
|
||||
public:
|
||||
Buffer(size_t capacity){
|
||||
if(capacity>0){
|
||||
data=(unsigned char *) malloc(capacity);
|
||||
if(!data)
|
||||
throw std::bad_alloc();
|
||||
}else{
|
||||
data=NULL;
|
||||
}
|
||||
length=capacity;
|
||||
};
|
||||
TGVOIP_DISALLOW_COPY_AND_ASSIGN(Buffer); // use Buffer::CopyOf to copy contents explicitly
|
||||
Buffer(Buffer&& other) noexcept {
|
||||
data=other.data;
|
||||
length=other.length;
|
||||
freeFn=other.freeFn;
|
||||
reallocFn=other.reallocFn;
|
||||
other.data=NULL;
|
||||
};
|
||||
Buffer(BufferOutputStream&& stream){
|
||||
data=stream.buffer;
|
||||
length=stream.offset;
|
||||
stream.buffer=NULL;
|
||||
}
|
||||
Buffer(){
|
||||
data=NULL;
|
||||
length=0;
|
||||
}
|
||||
~Buffer(){
|
||||
if(data){
|
||||
if(freeFn)
|
||||
freeFn(data);
|
||||
else
|
||||
free(data);
|
||||
}
|
||||
data=NULL;
|
||||
length=0;
|
||||
};
|
||||
Buffer& operator=(Buffer&& other){
|
||||
if(this!=&other){
|
||||
if(data){
|
||||
if(freeFn)
|
||||
freeFn(data);
|
||||
else
|
||||
free(data);
|
||||
}
|
||||
data=other.data;
|
||||
length=other.length;
|
||||
freeFn=other.freeFn;
|
||||
reallocFn=other.reallocFn;
|
||||
other.data=NULL;
|
||||
other.length=0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
unsigned char& operator[](size_t i){
|
||||
if(i>=length)
|
||||
throw std::out_of_range("");
|
||||
return data[i];
|
||||
}
|
||||
const unsigned char& operator[](size_t i) const{
|
||||
if(i>=length)
|
||||
throw std::out_of_range("");
|
||||
return data[i];
|
||||
}
|
||||
unsigned char* operator*(){
|
||||
return data;
|
||||
}
|
||||
const unsigned char* operator*() const{
|
||||
return data;
|
||||
}
|
||||
void CopyFrom(const Buffer& other, size_t count, size_t srcOffset=0, size_t dstOffset=0){
|
||||
if(!other.data)
|
||||
throw std::invalid_argument("CopyFrom can't copy from NULL");
|
||||
if(other.length<srcOffset+count || length<dstOffset+count)
|
||||
throw std::out_of_range("Out of offset+count bounds of either buffer");
|
||||
memcpy(data+dstOffset, other.data+srcOffset, count);
|
||||
}
|
||||
void CopyFrom(const void* ptr, size_t dstOffset, size_t count){
|
||||
if(length<dstOffset+count)
|
||||
throw std::out_of_range("Offset+count is out of bounds");
|
||||
memcpy(data+dstOffset, ptr, count);
|
||||
}
|
||||
void Resize(size_t newSize){
|
||||
if(reallocFn)
|
||||
data=(unsigned char *) reallocFn(data, newSize);
|
||||
else
|
||||
data=(unsigned char *) realloc(data, newSize);
|
||||
if(!data)
|
||||
throw std::bad_alloc();
|
||||
length=newSize;
|
||||
}
|
||||
size_t Length() const{
|
||||
return length;
|
||||
}
|
||||
bool IsEmpty() const{
|
||||
return length==0 || !data;
|
||||
}
|
||||
static Buffer CopyOf(const Buffer& other){
|
||||
if(other.IsEmpty())
|
||||
return Buffer();
|
||||
Buffer buf(other.length);
|
||||
buf.CopyFrom(other, other.length);
|
||||
return buf;
|
||||
}
|
||||
static Buffer CopyOf(const Buffer& other, size_t offset, size_t length){
|
||||
if(offset+length>other.Length())
|
||||
throw std::out_of_range("offset+length out of bounds");
|
||||
Buffer buf(length);
|
||||
buf.CopyFrom(other, length, offset);
|
||||
return buf;
|
||||
}
|
||||
static Buffer Wrap(unsigned char* data, size_t size, std::function<void(void*)> freeFn, std::function<void*(void*, size_t)> reallocFn){
|
||||
Buffer b=Buffer();
|
||||
b.data=data;
|
||||
b.length=size;
|
||||
b.freeFn=freeFn;
|
||||
b.reallocFn=reallocFn;
|
||||
return b;
|
||||
}
|
||||
private:
|
||||
unsigned char* data;
|
||||
size_t length;
|
||||
std::function<void(void*)> freeFn;
|
||||
std::function<void*(void*, size_t)> reallocFn;
|
||||
};
|
||||
|
||||
template <typename T, size_t size, typename AVG_T=T> class HistoricBuffer{
|
||||
public:
|
||||
HistoricBuffer(){
|
||||
std::fill(data.begin(), data.end(), (T)0);
|
||||
}
|
||||
|
||||
AVG_T Average() const {
|
||||
AVG_T avg=(AVG_T)0;
|
||||
for(T i:data){
|
||||
avg+=i;
|
||||
}
|
||||
return avg/(AVG_T)size;
|
||||
}
|
||||
|
||||
AVG_T Average(size_t firstN) const {
|
||||
AVG_T avg=(AVG_T)0;
|
||||
for(size_t i=0;i<firstN;i++){
|
||||
avg+=(*this)[i];
|
||||
}
|
||||
return avg/(AVG_T)firstN;
|
||||
}
|
||||
|
||||
AVG_T NonZeroAverage() const {
|
||||
AVG_T avg=(AVG_T)0;
|
||||
int nonZeroCount=0;
|
||||
for(T i:data){
|
||||
if(i!=0){
|
||||
nonZeroCount++;
|
||||
avg+=i;
|
||||
}
|
||||
}
|
||||
if(nonZeroCount==0)
|
||||
return (AVG_T)0;
|
||||
return avg/(AVG_T)nonZeroCount;
|
||||
}
|
||||
|
||||
void Add(T el){
|
||||
data[offset]=el;
|
||||
offset=(offset+1)%size;
|
||||
}
|
||||
|
||||
T Min() const {
|
||||
T min=std::numeric_limits<T>::max();
|
||||
for(T i:data){
|
||||
if(i<min)
|
||||
min=i;
|
||||
}
|
||||
return min;
|
||||
}
|
||||
|
||||
T Max() const {
|
||||
T max=std::numeric_limits<T>::min();
|
||||
for(T i:data){
|
||||
if(i>max)
|
||||
max=i;
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
void Reset(){
|
||||
std::fill(data.begin(), data.end(), (T)0);
|
||||
offset=0;
|
||||
}
|
||||
|
||||
T operator[](size_t i) const {
|
||||
assert(i<size);
|
||||
// [0] should return the most recent entry, [1] the one before it, and so on
|
||||
ptrdiff_t _i=offset-i-1;
|
||||
if(_i<0)
|
||||
_i=size+_i;
|
||||
return data[_i];
|
||||
}
|
||||
|
||||
T& operator[](size_t i){
|
||||
assert(i<size);
|
||||
// [0] should return the most recent entry, [1] the one before it, and so on
|
||||
ptrdiff_t _i=offset-i-1;
|
||||
if(_i<0)
|
||||
_i=size+_i;
|
||||
return data[_i];
|
||||
}
|
||||
|
||||
size_t Size() const {
|
||||
return size;
|
||||
}
|
||||
private:
|
||||
std::array<T, size> data;
|
||||
ptrdiff_t offset=0;
|
||||
};
|
||||
|
||||
template <size_t bufSize, size_t bufCount> class BufferPool{
|
||||
public:
|
||||
TGVOIP_DISALLOW_COPY_AND_ASSIGN(BufferPool);
|
||||
BufferPool(){
|
||||
bufferStart=(unsigned char*)malloc(bufSize*bufCount);
|
||||
if(!bufferStart)
|
||||
throw std::bad_alloc();
|
||||
};
|
||||
~BufferPool(){
|
||||
assert(usedBuffers.none());
|
||||
free(bufferStart);
|
||||
};
|
||||
Buffer Get(){
|
||||
auto freeFn=[this](void* _buf){
|
||||
assert(_buf!=NULL);
|
||||
unsigned char* buf=(unsigned char*)_buf;
|
||||
size_t offset=buf-bufferStart;
|
||||
assert(offset%bufSize==0);
|
||||
size_t index=offset/bufSize;
|
||||
assert(index<bufCount);
|
||||
|
||||
MutexGuard m(mutex);
|
||||
assert(usedBuffers.test(index));
|
||||
usedBuffers[index]=0;
|
||||
};
|
||||
auto resizeFn=[](void* buf, size_t newSize)->void*{
|
||||
if(newSize>bufSize)
|
||||
throw std::invalid_argument("newSize>bufferSize");
|
||||
return buf;
|
||||
};
|
||||
MutexGuard m(mutex);
|
||||
for(size_t i=0;i<bufCount;i++){
|
||||
if(!usedBuffers[i]){
|
||||
usedBuffers[i]=1;
|
||||
return Buffer::Wrap(bufferStart+(bufSize*i), bufSize, freeFn, resizeFn);
|
||||
}
|
||||
}
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
private:
|
||||
std::bitset<bufCount> usedBuffers;
|
||||
unsigned char* bufferStart;
|
||||
Mutex mutex;
|
||||
};
|
||||
}
|
||||
|
||||
#endif //LIBTGVOIP_BUFFERINPUTSTREAM_H
|
148
TMessagesProj/jni/libtgvoip2/CongestionControl.cpp
Normal file
148
TMessagesProj/jni/libtgvoip2/CongestionControl.cpp
Normal file
|
@ -0,0 +1,148 @@
|
|||
//
|
||||
// libtgvoip is free and unencumbered public domain software.
|
||||
// For more information, see http://unlicense.org or the UNLICENSE file
|
||||
// you should have received with this source code distribution.
|
||||
//
|
||||
|
||||
#include "CongestionControl.h"
|
||||
#include "VoIPController.h"
|
||||
#include "logging.h"
|
||||
#include "VoIPServerConfig.h"
|
||||
#include "PrivateDefines.h"
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
|
||||
using namespace tgvoip;
|
||||
|
||||
CongestionControl::CongestionControl(){
|
||||
memset(inflightPackets, 0, sizeof(inflightPackets));
|
||||
tmpRtt=0;
|
||||
tmpRttCount=0;
|
||||
lastSentSeq=0;
|
||||
lastActionTime=0;
|
||||
lastActionRtt=0;
|
||||
stateTransitionTime=0;
|
||||
inflightDataSize=0;
|
||||
lossCount=0;
|
||||
cwnd=(size_t) ServerConfig::GetSharedInstance()->GetInt("audio_congestion_window", 1024);
|
||||
}
|
||||
|
||||
CongestionControl::~CongestionControl(){
|
||||
}
|
||||
|
||||
size_t CongestionControl::GetAcknowledgedDataSize(){
|
||||
return 0;
|
||||
}
|
||||
|
||||
double CongestionControl::GetAverageRTT(){
|
||||
return rttHistory.NonZeroAverage();
|
||||
}
|
||||
|
||||
size_t CongestionControl::GetInflightDataSize(){
|
||||
return inflightHistory.Average();
|
||||
}
|
||||
|
||||
|
||||
size_t CongestionControl::GetCongestionWindow(){
|
||||
return cwnd;
|
||||
}
|
||||
|
||||
double CongestionControl::GetMinimumRTT(){
|
||||
return rttHistory.Min();
|
||||
}
|
||||
|
||||
void CongestionControl::PacketAcknowledged(uint32_t seq){
|
||||
for(int i=0;i<100;i++){
|
||||
if(inflightPackets[i].seq==seq && inflightPackets[i].sendTime>0){
|
||||
tmpRtt+=(VoIPController::GetCurrentTime()-inflightPackets[i].sendTime);
|
||||
tmpRttCount++;
|
||||
inflightPackets[i].sendTime=0;
|
||||
inflightDataSize-=inflightPackets[i].size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CongestionControl::PacketSent(uint32_t seq, size_t size){
|
||||
if(!seqgt(seq, lastSentSeq) || seq==lastSentSeq){
|
||||
LOGW("Duplicate outgoing seq %u", seq);
|
||||
return;
|
||||
}
|
||||
lastSentSeq=seq;
|
||||
double smallestSendTime=INFINITY;
|
||||
tgvoip_congestionctl_packet_t* slot=NULL;
|
||||
int i;
|
||||
for(i=0;i<100;i++){
|
||||
if(inflightPackets[i].sendTime==0){
|
||||
slot=&inflightPackets[i];
|
||||
break;
|
||||
}
|
||||
if(smallestSendTime>inflightPackets[i].sendTime){
|
||||
slot=&inflightPackets[i];
|
||||
smallestSendTime=slot->sendTime;
|
||||
}
|
||||
}
|
||||
assert(slot!=NULL);
|
||||
if(slot->sendTime>0){
|
||||
inflightDataSize-=slot->size;
|
||||
lossCount++;
|
||||
LOGD("Packet with seq %u was not acknowledged", slot->seq);
|
||||
}
|
||||
slot->seq=seq;
|
||||
slot->size=size;
|
||||
slot->sendTime=VoIPController::GetCurrentTime();
|
||||
inflightDataSize+=size;
|
||||
}
|
||||
|
||||
void CongestionControl::PacketLost(uint32_t seq){
|
||||
for(int i=0;i<100;i++){
|
||||
if(inflightPackets[i].seq==seq && inflightPackets[i].sendTime>0){
|
||||
inflightPackets[i].sendTime=0;
|
||||
inflightDataSize-=inflightPackets[i].size;
|
||||
lossCount++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CongestionControl::Tick(){
|
||||
tickCount++;
|
||||
if(tmpRttCount>0){
|
||||
rttHistory.Add(tmpRtt/tmpRttCount);
|
||||
tmpRtt=0;
|
||||
tmpRttCount=0;
|
||||
}
|
||||
int i;
|
||||
for(i=0;i<100;i++){
|
||||
if(inflightPackets[i].sendTime!=0 && VoIPController::GetCurrentTime()-inflightPackets[i].sendTime>2){
|
||||
inflightPackets[i].sendTime=0;
|
||||
inflightDataSize-=inflightPackets[i].size;
|
||||
lossCount++;
|
||||
LOGD("Packet with seq %u was not acknowledged", inflightPackets[i].seq);
|
||||
}
|
||||
}
|
||||
inflightHistory.Add(inflightDataSize);
|
||||
}
|
||||
|
||||
|
||||
int CongestionControl::GetBandwidthControlAction(){
|
||||
if(VoIPController::GetCurrentTime()-lastActionTime<1)
|
||||
return TGVOIP_CONCTL_ACT_NONE;
|
||||
size_t inflightAvg=GetInflightDataSize();
|
||||
size_t max=cwnd+cwnd/10;
|
||||
size_t min=cwnd-cwnd/10;
|
||||
if(inflightAvg<min){
|
||||
lastActionTime=VoIPController::GetCurrentTime();
|
||||
return TGVOIP_CONCTL_ACT_INCREASE;
|
||||
}
|
||||
if(inflightAvg>max){
|
||||
lastActionTime=VoIPController::GetCurrentTime();
|
||||
return TGVOIP_CONCTL_ACT_DECREASE;
|
||||
}
|
||||
return TGVOIP_CONCTL_ACT_NONE;
|
||||
}
|
||||
|
||||
|
||||
uint32_t CongestionControl::GetSendLossCount(){
|
||||
return lossCount;
|
||||
}
|
63
TMessagesProj/jni/libtgvoip2/CongestionControl.h
Normal file
63
TMessagesProj/jni/libtgvoip2/CongestionControl.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
//
|
||||
// libtgvoip is free and unencumbered public domain software.
|
||||
// For more information, see http://unlicense.org or the UNLICENSE file
|
||||
// you should have received with this source code distribution.
|
||||
//
|
||||
|
||||
#ifndef LIBTGVOIP_CONGESTIONCONTROL_H
|
||||
#define LIBTGVOIP_CONGESTIONCONTROL_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "threading.h"
|
||||
#include "Buffers.h"
|
||||
|
||||
#define TGVOIP_CONCTL_ACT_INCREASE 1
|
||||
#define TGVOIP_CONCTL_ACT_DECREASE 2
|
||||
#define TGVOIP_CONCTL_ACT_NONE 0
|
||||
|
||||
namespace tgvoip{
|
||||
|
||||
struct tgvoip_congestionctl_packet_t{
|
||||
uint32_t seq;
|
||||
double sendTime;
|
||||
size_t size;
|
||||
};
|
||||
typedef struct tgvoip_congestionctl_packet_t tgvoip_congestionctl_packet_t;
|
||||
|
||||
class CongestionControl{
|
||||
public:
|
||||
CongestionControl();
|
||||
~CongestionControl();
|
||||
|
||||
void PacketSent(uint32_t seq, size_t size);
|
||||
void PacketLost(uint32_t seq);
|
||||
void PacketAcknowledged(uint32_t seq);
|
||||
|
||||
double GetAverageRTT();
|
||||
double GetMinimumRTT();
|
||||
size_t GetInflightDataSize();
|
||||
size_t GetCongestionWindow();
|
||||
size_t GetAcknowledgedDataSize();
|
||||
void Tick();
|
||||
int GetBandwidthControlAction();
|
||||
uint32_t GetSendLossCount();
|
||||
|
||||
private:
|
||||
HistoricBuffer<double, 100> rttHistory;
|
||||
HistoricBuffer<size_t, 30> inflightHistory;
|
||||
tgvoip_congestionctl_packet_t inflightPackets[100];
|
||||
uint32_t lossCount;
|
||||
double tmpRtt;
|
||||
double lastActionTime;
|
||||
double lastActionRtt;
|
||||
double stateTransitionTime;
|
||||
int tmpRttCount;
|
||||
uint32_t lastSentSeq;
|
||||
uint32_t tickCount;
|
||||
size_t inflightDataSize;
|
||||
size_t cwnd;
|
||||
};
|
||||
}
|
||||
|
||||
#endif //LIBTGVOIP_CONGESTIONCONTROL_H
|
248
TMessagesProj/jni/libtgvoip2/EchoCanceller.cpp
Normal file
248
TMessagesProj/jni/libtgvoip2/EchoCanceller.cpp
Normal file
|
@ -0,0 +1,248 @@
|
|||
//
|
||||
// libtgvoip is free and unencumbered public domain software.
|
||||
// For more information, see http://unlicense.org or the UNLICENSE file
|
||||
// you should have received with this source code distribution.
|
||||
//
|
||||
|
||||
#ifndef TGVOIP_NO_DSP
|
||||
#include "webrtc_dsp/modules/audio_processing/include/audio_processing.h"
|
||||
#include "webrtc_dsp/api/audio/audio_frame.h"
|
||||
#endif
|
||||
|
||||
#include "EchoCanceller.h"
|
||||
#include "audio/AudioOutput.h"
|
||||
#include "audio/AudioInput.h"
|
||||
#include "logging.h"
|
||||
#include "VoIPServerConfig.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
using namespace tgvoip;
|
||||
|
||||
EchoCanceller::EchoCanceller(bool enableAEC, bool enableNS, bool enableAGC){
|
||||
#ifndef TGVOIP_NO_DSP
|
||||
this->enableAEC=enableAEC;
|
||||
this->enableAGC=enableAGC;
|
||||
this->enableNS=enableNS;
|
||||
isOn=true;
|
||||
|
||||
webrtc::Config extraConfig;
|
||||
#ifdef TGVOIP_USE_DESKTOP_DSP
|
||||
extraConfig.Set(new webrtc::DelayAgnostic(true));
|
||||
#endif
|
||||
|
||||
apm=webrtc::AudioProcessingBuilder().Create(extraConfig);
|
||||
|
||||
webrtc::AudioProcessing::Config config;
|
||||
config.echo_canceller.enabled = enableAEC;
|
||||
#ifndef TGVOIP_USE_DESKTOP_DSP
|
||||
config.echo_canceller.mobile_mode = true;
|
||||
#else
|
||||
config.echo_canceller.mobile_mode = false;
|
||||
#endif
|
||||
config.high_pass_filter.enabled = enableAEC;
|
||||
config.gain_controller2.enabled = enableAGC;
|
||||
apm->ApplyConfig(config);
|
||||
|
||||
webrtc::NoiseSuppression::Level nsLevel;
|
||||
#ifdef __APPLE__
|
||||
switch(ServerConfig::GetSharedInstance()->GetInt("webrtc_ns_level_vpio", 0)){
|
||||
#else
|
||||
switch(ServerConfig::GetSharedInstance()->GetInt("webrtc_ns_level", 2)){
|
||||
#endif
|
||||
case 0:
|
||||
nsLevel=webrtc::NoiseSuppression::Level::kLow;
|
||||
break;
|
||||
case 1:
|
||||
nsLevel=webrtc::NoiseSuppression::Level::kModerate;
|
||||
break;
|
||||
case 3:
|
||||
nsLevel=webrtc::NoiseSuppression::Level::kVeryHigh;
|
||||
break;
|
||||
case 2:
|
||||
default:
|
||||
nsLevel=webrtc::NoiseSuppression::Level::kHigh;
|
||||
break;
|
||||
}
|
||||
apm->noise_suppression()->set_level(nsLevel);
|
||||
apm->noise_suppression()->Enable(enableNS);
|
||||
if(enableAGC){
|
||||
apm->gain_control()->set_mode(webrtc::GainControl::Mode::kAdaptiveDigital);
|
||||
apm->gain_control()->set_target_level_dbfs(ServerConfig::GetSharedInstance()->GetInt("webrtc_agc_target_level", 9));
|
||||
apm->gain_control()->enable_limiter(ServerConfig::GetSharedInstance()->GetBoolean("webrtc_agc_enable_limiter", true));
|
||||
apm->gain_control()->set_compression_gain_db(ServerConfig::GetSharedInstance()->GetInt("webrtc_agc_compression_gain", 20));
|
||||
}
|
||||
apm->voice_detection()->set_likelihood(webrtc::VoiceDetection::Likelihood::kVeryLowLikelihood);
|
||||
|
||||
audioFrame=new webrtc::AudioFrame();
|
||||
audioFrame->samples_per_channel_=480;
|
||||
audioFrame->sample_rate_hz_=48000;
|
||||
audioFrame->num_channels_=1;
|
||||
|
||||
farendQueue=new BlockingQueue<Buffer>(11);
|
||||
running=true;
|
||||
bufferFarendThread=new Thread(std::bind(&EchoCanceller::RunBufferFarendThread, this));
|
||||
bufferFarendThread->SetName("VoipECBufferFarEnd");
|
||||
bufferFarendThread->Start();
|
||||
|
||||
#else
|
||||
this->enableAEC=this->enableAGC=enableAGC=this->enableNS=enableNS=false;
|
||||
isOn=true;
|
||||
#endif
|
||||
}
|
||||
|
||||
EchoCanceller::~EchoCanceller(){
|
||||
#ifndef TGVOIP_NO_DSP
|
||||
farendQueue->Put(Buffer());
|
||||
bufferFarendThread->Join();
|
||||
delete bufferFarendThread;
|
||||
delete farendQueue;
|
||||
delete audioFrame;
|
||||
delete apm;
|
||||
#endif
|
||||
}
|
||||
|
||||
void EchoCanceller::Start(){
|
||||
|
||||
}
|
||||
|
||||
void EchoCanceller::Stop(){
|
||||
|
||||
}
|
||||
|
||||
|
||||
void EchoCanceller::SpeakerOutCallback(unsigned char* data, size_t len){
|
||||
if(len!=960*2 || !enableAEC || !isOn)
|
||||
return;
|
||||
#ifndef TGVOIP_NO_DSP
|
||||
try{
|
||||
Buffer buf=farendBufferPool.Get();
|
||||
buf.CopyFrom(data, 0, 960*2);
|
||||
farendQueue->Put(std::move(buf));
|
||||
}catch(std::bad_alloc& x){
|
||||
LOGW("Echo canceller can't keep up with real time");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef TGVOIP_NO_DSP
|
||||
void EchoCanceller::RunBufferFarendThread(){
|
||||
webrtc::AudioFrame frame;
|
||||
frame.num_channels_=1;
|
||||
frame.sample_rate_hz_=48000;
|
||||
frame.samples_per_channel_=480;
|
||||
while(running){
|
||||
Buffer buf=farendQueue->GetBlocking();
|
||||
if(buf.IsEmpty()){
|
||||
LOGI("Echo canceller buffer farend thread exiting");
|
||||
return;
|
||||
}
|
||||
int16_t* samplesIn=(int16_t*)*buf;
|
||||
memcpy(frame.mutable_data(), samplesIn, 480*2);
|
||||
apm->ProcessReverseStream(&frame);
|
||||
memcpy(frame.mutable_data(), samplesIn+480, 480*2);
|
||||
apm->ProcessReverseStream(&frame);
|
||||
didBufferFarend=true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void EchoCanceller::Enable(bool enabled){
|
||||
isOn=enabled;
|
||||
}
|
||||
|
||||
void EchoCanceller::ProcessInput(int16_t* inOut, size_t numSamples, bool& hasVoice){
|
||||
#ifndef TGVOIP_NO_DSP
|
||||
if(!isOn || (!enableAEC && !enableAGC && !enableNS)){
|
||||
return;
|
||||
}
|
||||
int delay=audio::AudioInput::GetEstimatedDelay()+audio::AudioOutput::GetEstimatedDelay();
|
||||
assert(numSamples==960);
|
||||
|
||||
memcpy(audioFrame->mutable_data(), inOut, 480*2);
|
||||
if(enableAEC)
|
||||
apm->set_stream_delay_ms(delay);
|
||||
apm->ProcessStream(audioFrame);
|
||||
if(enableVAD)
|
||||
hasVoice=apm->voice_detection()->stream_has_voice();
|
||||
memcpy(inOut, audioFrame->data(), 480*2);
|
||||
memcpy(audioFrame->mutable_data(), inOut+480, 480*2);
|
||||
if(enableAEC)
|
||||
apm->set_stream_delay_ms(delay);
|
||||
apm->ProcessStream(audioFrame);
|
||||
if(enableVAD){
|
||||
hasVoice=hasVoice || apm->voice_detection()->stream_has_voice();
|
||||
}
|
||||
memcpy(inOut+480, audioFrame->data(), 480*2);
|
||||
#endif
|
||||
}
|
||||
|
||||
void EchoCanceller::SetAECStrength(int strength){
|
||||
#ifndef TGVOIP_NO_DSP
|
||||
/*if(aec){
|
||||
#ifndef TGVOIP_USE_DESKTOP_DSP
|
||||
AecmConfig cfg;
|
||||
cfg.cngMode=AecmFalse;
|
||||
cfg.echoMode=(int16_t) strength;
|
||||
WebRtcAecm_set_config(aec, cfg);
|
||||
#endif
|
||||
}*/
|
||||
#endif
|
||||
}
|
||||
|
||||
void EchoCanceller::SetVoiceDetectionEnabled(bool enabled){
|
||||
enableVAD=enabled;
|
||||
#ifndef TGVOIP_NO_DSP
|
||||
apm->voice_detection()->Enable(enabled);
|
||||
#endif
|
||||
}
|
||||
|
||||
using namespace tgvoip::effects;
|
||||
|
||||
AudioEffect::~AudioEffect(){
|
||||
|
||||
}
|
||||
|
||||
void AudioEffect::SetPassThrough(bool passThrough){
|
||||
this->passThrough=passThrough;
|
||||
}
|
||||
|
||||
Volume::Volume(){
|
||||
|
||||
}
|
||||
|
||||
Volume::~Volume(){
|
||||
|
||||
}
|
||||
|
||||
void Volume::Process(int16_t* inOut, size_t numSamples){
|
||||
if(level==1.0f || passThrough){
|
||||
return;
|
||||
}
|
||||
for(size_t i=0;i<numSamples;i++){
|
||||
float sample=(float)inOut[i]*multiplier;
|
||||
if(sample>32767.0f)
|
||||
inOut[i]=INT16_MAX;
|
||||
else if(sample<-32768.0f)
|
||||
inOut[i]=INT16_MIN;
|
||||
else
|
||||
inOut[i]=(int16_t)sample;
|
||||
}
|
||||
}
|
||||
|
||||
void Volume::SetLevel(float level){
|
||||
this->level=level;
|
||||
float db;
|
||||
if(level<1.0f)
|
||||
db=-50.0f*(1.0f-level);
|
||||
else if(level>1.0f && level<=2.0f)
|
||||
db=10.0f*(level-1.0f);
|
||||
else
|
||||
db=0.0f;
|
||||
multiplier=expf(db/20.0f * logf(10.0f));
|
||||
}
|
||||
|
||||
float Volume::GetLevel(){
|
||||
return level;
|
||||
}
|
83
TMessagesProj/jni/libtgvoip2/EchoCanceller.h
Normal file
83
TMessagesProj/jni/libtgvoip2/EchoCanceller.h
Normal file
|
@ -0,0 +1,83 @@
|
|||
//
|
||||
// libtgvoip is free and unencumbered public domain software.
|
||||
// For more information, see http://unlicense.org or the UNLICENSE file
|
||||
// you should have received with this source code distribution.
|
||||
//
|
||||
|
||||
#ifndef LIBTGVOIP_ECHOCANCELLER_H
|
||||
#define LIBTGVOIP_ECHOCANCELLER_H
|
||||
|
||||
#include "threading.h"
|
||||
#include "Buffers.h"
|
||||
#include "BlockingQueue.h"
|
||||
#include "MediaStreamItf.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace webrtc{
|
||||
class AudioProcessing;
|
||||
class AudioFrame;
|
||||
}
|
||||
|
||||
namespace tgvoip{
|
||||
class EchoCanceller{
|
||||
|
||||
public:
|
||||
TGVOIP_DISALLOW_COPY_AND_ASSIGN(EchoCanceller);
|
||||
EchoCanceller(bool enableAEC, bool enableNS, bool enableAGC);
|
||||
virtual ~EchoCanceller();
|
||||
virtual void Start();
|
||||
virtual void Stop();
|
||||
void SpeakerOutCallback(unsigned char* data, size_t len);
|
||||
void Enable(bool enabled);
|
||||
void ProcessInput(int16_t* inOut, size_t numSamples, bool& hasVoice);
|
||||
void SetAECStrength(int strength);
|
||||
void SetVoiceDetectionEnabled(bool enabled);
|
||||
|
||||
private:
|
||||
bool enableAEC;
|
||||
bool enableAGC;
|
||||
bool enableNS;
|
||||
bool enableVAD=false;
|
||||
bool isOn;
|
||||
#ifndef TGVOIP_NO_DSP
|
||||
webrtc::AudioProcessing* apm=NULL;
|
||||
webrtc::AudioFrame* audioFrame=NULL;
|
||||
void RunBufferFarendThread();
|
||||
bool didBufferFarend;
|
||||
Thread* bufferFarendThread;
|
||||
BlockingQueue<Buffer>* farendQueue;
|
||||
BufferPool<960*2, 10> farendBufferPool;
|
||||
bool running;
|
||||
#endif
|
||||
};
|
||||
|
||||
namespace effects{
|
||||
|
||||
class AudioEffect{
|
||||
public:
|
||||
virtual ~AudioEffect()=0;
|
||||
virtual void Process(int16_t* inOut, size_t numSamples)=0;
|
||||
virtual void SetPassThrough(bool passThrough);
|
||||
protected:
|
||||
bool passThrough=false;
|
||||
};
|
||||
|
||||
class Volume : public AudioEffect{
|
||||
public:
|
||||
Volume();
|
||||
virtual ~Volume();
|
||||
virtual void Process(int16_t* inOut, size_t numSamples);
|
||||
/**
|
||||
* Level is (0.0, 2.0]
|
||||
*/
|
||||
void SetLevel(float level);
|
||||
float GetLevel();
|
||||
private:
|
||||
float level=1.0f;
|
||||
float multiplier=1.0f;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif //LIBTGVOIP_ECHOCANCELLER_H
|
24
TMessagesProj/jni/libtgvoip2/Info.plist
Normal file
24
TMessagesProj/jni/libtgvoip2/Info.plist
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
455
TMessagesProj/jni/libtgvoip2/JitterBuffer.cpp
Normal file
455
TMessagesProj/jni/libtgvoip2/JitterBuffer.cpp
Normal file
|
@ -0,0 +1,455 @@
|
|||
//
|
||||
// libtgvoip is free and unencumbered public domain software.
|
||||
// For more information, see http://unlicense.org or the UNLICENSE file
|
||||
// you should have received with this source code distribution.
|
||||
//
|
||||
|
||||
#include "VoIPController.h"
|
||||
#include "JitterBuffer.h"
|
||||
#include "logging.h"
|
||||
#include "VoIPServerConfig.h"
|
||||
#include <math.h>
|
||||
|
||||
using namespace tgvoip;
|
||||
|
||||
JitterBuffer::JitterBuffer(MediaStreamItf *out, uint32_t step){
|
||||
if(out)
|
||||
out->SetCallback(JitterBuffer::CallbackOut, this);
|
||||
this->step=step;
|
||||
memset(slots, 0, sizeof(jitter_packet_t)*JITTER_SLOT_COUNT);
|
||||
if(step<30){
|
||||
minMinDelay=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_min_delay_20", 6);
|
||||
maxMinDelay=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_max_delay_20", 25);
|
||||
maxUsedSlots=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_max_slots_20", 50);
|
||||
}else if(step<50){
|
||||
minMinDelay=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_min_delay_40", 4);
|
||||
maxMinDelay=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_max_delay_40", 15);
|
||||
maxUsedSlots=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_max_slots_40", 30);
|
||||
}else{
|
||||
minMinDelay=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_min_delay_60", 2);
|
||||
maxMinDelay=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_max_delay_60", 10);
|
||||
maxUsedSlots=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_max_slots_60", 20);
|
||||
}
|
||||
lossesToReset=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_losses_to_reset", 20);
|
||||
resyncThreshold=ServerConfig::GetSharedInstance()->GetDouble("jitter_resync_threshold", 1.0);
|
||||
#ifdef TGVOIP_DUMP_JITTER_STATS
|
||||
#ifdef TGVOIP_JITTER_DUMP_FILE
|
||||
dump=fopen(TGVOIP_JITTER_DUMP_FILE, "w");
|
||||
#elif defined(__ANDROID__)
|
||||
dump=fopen("/sdcard/tgvoip_jitter_dump.txt", "w");
|
||||
#else
|
||||
dump=fopen("tgvoip_jitter_dump.txt", "w");
|
||||
#endif
|
||||
tgvoip_log_file_write_header(dump);
|
||||
fprintf(dump, "PTS\tRTS\tNumInBuf\tAJitter\tADelay\tTDelay\n");
|
||||
#endif
|
||||
Reset();
|
||||
}
|
||||
|
||||
JitterBuffer::~JitterBuffer(){
|
||||
Reset();
|
||||
}
|
||||
|
||||
void JitterBuffer::SetMinPacketCount(uint32_t count){
|
||||
LOGI("jitter: set min packet count %u", count);
|
||||
minDelay=count;
|
||||
minMinDelay=count;
|
||||
//Reset();
|
||||
}
|
||||
|
||||
int JitterBuffer::GetMinPacketCount(){
|
||||
return (int)minDelay;
|
||||
}
|
||||
|
||||
size_t JitterBuffer::CallbackIn(unsigned char *data, size_t len, void *param){
|
||||
//((JitterBuffer*)param)->HandleInput(data, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t JitterBuffer::CallbackOut(unsigned char *data, size_t len, void *param){
|
||||
return 0; //((JitterBuffer*)param)->HandleOutput(data, len, 0, NULL);
|
||||
}
|
||||
|
||||
void JitterBuffer::HandleInput(unsigned char *data, size_t len, uint32_t timestamp, bool isEC){
|
||||
MutexGuard m(mutex);
|
||||
jitter_packet_t pkt;
|
||||
pkt.size=len;
|
||||
pkt.buffer=Buffer::Wrap(data, len, [](void*){}, [](void* a, size_t)->void*{return a;});
|
||||
pkt.timestamp=timestamp;
|
||||
pkt.isEC=isEC;
|
||||
PutInternal(&pkt, !isEC);
|
||||
//LOGV("in, ts=%d, ec=%d", timestamp, isEC);
|
||||
|
||||
}
|
||||
|
||||
void JitterBuffer::Reset(){
|
||||
wasReset=true;
|
||||
needBuffering=true;
|
||||
lastPutTimestamp=0;
|
||||
int i;
|
||||
for(i=0;i<JITTER_SLOT_COUNT;i++){
|
||||
if(!slots[i].buffer.IsEmpty()){
|
||||
slots[i].buffer=Buffer();
|
||||
}
|
||||
}
|
||||
delayHistory.Reset();
|
||||
lateHistory.Reset();
|
||||
adjustingDelay=false;
|
||||
lostSinceReset=0;
|
||||
gotSinceReset=0;
|
||||
expectNextAtTime=0;
|
||||
deviationHistory.Reset();
|
||||
outstandingDelayChange=0;
|
||||
dontChangeDelay=0;
|
||||
}
|
||||
|
||||
|
||||
size_t JitterBuffer::HandleOutput(unsigned char *buffer, size_t len, int offsetInSteps, bool advance, int& playbackScaledDuration, bool& isEC){
|
||||
jitter_packet_t pkt;
|
||||
pkt.buffer=Buffer::Wrap(buffer, len, [](void*){}, [](void* a, size_t)->void*{return a;});
|
||||
pkt.size=len;
|
||||
MutexGuard m(mutex);
|
||||
if(first){
|
||||
first=false;
|
||||
unsigned int delay=GetCurrentDelay();
|
||||
if(GetCurrentDelay()>5){
|
||||
LOGW("jitter: delay too big upon start (%u), dropping packets", delay);
|
||||
while(delay>GetMinPacketCount()){
|
||||
for(int i=0;i<JITTER_SLOT_COUNT;i++){
|
||||
if(slots[i].timestamp==nextTimestamp){
|
||||
if(!slots[i].buffer.IsEmpty()){
|
||||
slots[i].buffer=Buffer();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
Advance();
|
||||
delay--;
|
||||
}
|
||||
}
|
||||
}
|
||||
int result=GetInternal(&pkt, offsetInSteps, advance);
|
||||
if(outstandingDelayChange!=0){
|
||||
if(outstandingDelayChange<0){
|
||||
playbackScaledDuration=40;
|
||||
outstandingDelayChange+=20;
|
||||
}else{
|
||||
playbackScaledDuration=80;
|
||||
outstandingDelayChange-=20;
|
||||
}
|
||||
//LOGV("outstanding delay change: %d", outstandingDelayChange);
|
||||
}else if(advance && GetCurrentDelay()==0){
|
||||
//LOGV("stretching packet because the next one is late");
|
||||
playbackScaledDuration=80;
|
||||
}else{
|
||||
playbackScaledDuration=60;
|
||||
}
|
||||
if(result==JR_OK){
|
||||
isEC=pkt.isEC;
|
||||
return pkt.size;
|
||||
}else{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int JitterBuffer::GetInternal(jitter_packet_t* pkt, int offset, bool advance){
|
||||
/*if(needBuffering && lastPutTimestamp<nextTimestamp){
|
||||
LOGV("jitter: don't have timestamp %lld, buffering", (long long int)nextTimestamp);
|
||||
Advance();
|
||||
return JR_BUFFERING;
|
||||
}*/
|
||||
|
||||
//needBuffering=false;
|
||||
|
||||
int64_t timestampToGet=nextTimestamp+offset*(int32_t)step;
|
||||
|
||||
int i;
|
||||
for(i=0;i<JITTER_SLOT_COUNT;i++){
|
||||
if(!slots[i].buffer.IsEmpty() && slots[i].timestamp==timestampToGet){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(i<JITTER_SLOT_COUNT){
|
||||
if(pkt && pkt->size<slots[i].size){
|
||||
LOGE("jitter: packet won't fit into provided buffer of %d (need %d)", int(slots[i].size), int(pkt->size));
|
||||
}else{
|
||||
if(pkt) {
|
||||
pkt->size = slots[i].size;
|
||||
pkt->timestamp = slots[i].timestamp;
|
||||
pkt->buffer.CopyFrom(slots[i].buffer, slots[i].size);
|
||||
pkt->isEC=slots[i].isEC;
|
||||
}
|
||||
}
|
||||
slots[i].buffer=Buffer();
|
||||
if(offset==0)
|
||||
Advance();
|
||||
lostCount=0;
|
||||
needBuffering=false;
|
||||
return JR_OK;
|
||||
}
|
||||
|
||||
LOGV("jitter: found no packet for timestamp %lld (last put = %d, lost = %d)", (long long int)timestampToGet, lastPutTimestamp, lostCount);
|
||||
|
||||
if(advance)
|
||||
Advance();
|
||||
|
||||
if(!needBuffering){
|
||||
lostCount++;
|
||||
if(offset==0){
|
||||
lostPackets++;
|
||||
lostSinceReset++;
|
||||
}
|
||||
if(lostCount>=lossesToReset || (gotSinceReset>minDelay*25 && lostSinceReset>gotSinceReset/2)){
|
||||
LOGW("jitter: lost %d packets in a row, resetting", lostCount);
|
||||
//minDelay++;
|
||||
dontIncMinDelay=16;
|
||||
dontDecMinDelay+=128;
|
||||
if(GetCurrentDelay()<minDelay)
|
||||
nextTimestamp-=(int64_t)(minDelay-GetCurrentDelay());
|
||||
lostCount=0;
|
||||
Reset();
|
||||
}
|
||||
|
||||
return JR_MISSING;
|
||||
}
|
||||
return JR_BUFFERING;
|
||||
}
|
||||
|
||||
void JitterBuffer::PutInternal(jitter_packet_t* pkt, bool overwriteExisting){
|
||||
if(pkt->size>JITTER_SLOT_SIZE){
|
||||
LOGE("The packet is too big to fit into the jitter buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
int i;
|
||||
for(i=0;i<JITTER_SLOT_COUNT;i++){
|
||||
if(!slots[i].buffer.IsEmpty() && slots[i].timestamp==pkt->timestamp){
|
||||
//LOGV("Found existing packet for timestamp %u, overwrite %d", pkt->timestamp, overwriteExisting);
|
||||
if(overwriteExisting){
|
||||
slots[i].buffer.CopyFrom(pkt->buffer, pkt->size);
|
||||
slots[i].size=pkt->size;
|
||||
slots[i].isEC=pkt->isEC;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
gotSinceReset++;
|
||||
if(wasReset){
|
||||
wasReset=false;
|
||||
outstandingDelayChange=0;
|
||||
nextTimestamp=(int64_t)(((int64_t)pkt->timestamp)-step*minDelay);
|
||||
first=true;
|
||||
LOGI("jitter: resyncing, next timestamp = %lld (step=%d, minDelay=%f)", (long long int)nextTimestamp, step, double(minDelay));
|
||||
}
|
||||
|
||||
for(i=0;i<JITTER_SLOT_COUNT;i++){
|
||||
if(!slots[i].buffer.IsEmpty()){
|
||||
if(slots[i].timestamp<nextTimestamp-1){
|
||||
slots[i].buffer=Buffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*double prevTime=0;
|
||||
uint32_t closestTime=0;
|
||||
for(i=0;i<JITTER_SLOT_COUNT;i++){
|
||||
if(slots[i].buffer!=NULL && pkt->timestamp-slots[i].timestamp<pkt->timestamp-closestTime){
|
||||
closestTime=slots[i].timestamp;
|
||||
prevTime=slots[i].recvTime;
|
||||
}
|
||||
}*/
|
||||
double time=VoIPController::GetCurrentTime();
|
||||
if(expectNextAtTime!=0){
|
||||
double dev=expectNextAtTime-time;
|
||||
//LOGV("packet dev %f", dev);
|
||||
deviationHistory.Add(dev);
|
||||
expectNextAtTime+=step/1000.0;
|
||||
}else{
|
||||
expectNextAtTime=time+step/1000.0;
|
||||
}
|
||||
|
||||
if(pkt->timestamp<nextTimestamp){
|
||||
//LOGW("jitter: would drop packet with timestamp %d because it is late but not hopelessly", pkt->timestamp);
|
||||
latePacketCount++;
|
||||
lostPackets--;
|
||||
}else if(pkt->timestamp<nextTimestamp-1){
|
||||
//LOGW("jitter: dropping packet with timestamp %d because it is too late", pkt->timestamp);
|
||||
latePacketCount++;
|
||||
return;
|
||||
}
|
||||
|
||||
if(pkt->timestamp>lastPutTimestamp)
|
||||
lastPutTimestamp=pkt->timestamp;
|
||||
|
||||
for(i=0;i<JITTER_SLOT_COUNT;i++){
|
||||
if(slots[i].buffer.IsEmpty())
|
||||
break;
|
||||
}
|
||||
if(i==JITTER_SLOT_COUNT || GetCurrentDelay()>=maxUsedSlots){
|
||||
int toRemove=JITTER_SLOT_COUNT;
|
||||
uint32_t bestTimestamp=0xFFFFFFFF;
|
||||
for(i=0;i<JITTER_SLOT_COUNT;i++){
|
||||
if(!slots[i].buffer.IsEmpty() && slots[i].timestamp<bestTimestamp){
|
||||
toRemove=i;
|
||||
bestTimestamp=slots[i].timestamp;
|
||||
}
|
||||
}
|
||||
Advance();
|
||||
slots[toRemove].buffer=Buffer();
|
||||
i=toRemove;
|
||||
}
|
||||
slots[i].timestamp=pkt->timestamp;
|
||||
slots[i].size=pkt->size;
|
||||
slots[i].buffer=bufferPool.Get();
|
||||
slots[i].recvTimeDiff=time-prevRecvTime;
|
||||
slots[i].isEC=pkt->isEC;
|
||||
slots[i].buffer.CopyFrom(pkt->buffer, pkt->size);
|
||||
#ifdef TGVOIP_DUMP_JITTER_STATS
|
||||
fprintf(dump, "%u\t%.03f\t%d\t%.03f\t%.03f\t%.03f\n", pkt->timestamp, time, GetCurrentDelay(), lastMeasuredJitter, lastMeasuredDelay, minDelay);
|
||||
#endif
|
||||
prevRecvTime=time;
|
||||
}
|
||||
|
||||
|
||||
void JitterBuffer::Advance(){
|
||||
nextTimestamp+=step;
|
||||
}
|
||||
|
||||
|
||||
unsigned int JitterBuffer::GetCurrentDelay(){
|
||||
unsigned int delay=0;
|
||||
int i;
|
||||
for(i=0;i<JITTER_SLOT_COUNT;i++){
|
||||
if(!slots[i].buffer.IsEmpty())
|
||||
delay++;
|
||||
}
|
||||
return delay;
|
||||
}
|
||||
|
||||
void JitterBuffer::Tick(){
|
||||
MutexGuard m(mutex);
|
||||
int i;
|
||||
|
||||
lateHistory.Add(latePacketCount);
|
||||
latePacketCount=0;
|
||||
bool absolutelyNoLatePackets=lateHistory.Max()==0;
|
||||
|
||||
double avgLate16=lateHistory.Average(16);
|
||||
//LOGV("jitter: avg late=%.1f, %.1f, %.1f", avgLate16, avgLate32, avgLate64);
|
||||
if(avgLate16>=resyncThreshold){
|
||||
LOGV("resyncing: avgLate16=%f, resyncThreshold=%f", avgLate16, resyncThreshold);
|
||||
wasReset=true;
|
||||
}
|
||||
|
||||
if(absolutelyNoLatePackets){
|
||||
if(dontDecMinDelay>0)
|
||||
dontDecMinDelay--;
|
||||
}
|
||||
|
||||
delayHistory.Add(GetCurrentDelay());
|
||||
avgDelay=delayHistory.Average(32);
|
||||
|
||||
double stddev=0;
|
||||
double avgdev=deviationHistory.Average();
|
||||
for(i=0;i<64;i++){
|
||||
double d=(deviationHistory[i]-avgdev);
|
||||
stddev+=(d*d);
|
||||
}
|
||||
stddev=sqrt(stddev/64);
|
||||
uint32_t stddevDelay=(uint32_t)ceil(stddev*2*1000/step);
|
||||
if(stddevDelay<minMinDelay)
|
||||
stddevDelay=minMinDelay;
|
||||
if(stddevDelay>maxMinDelay)
|
||||
stddevDelay=maxMinDelay;
|
||||
if(stddevDelay!=minDelay){
|
||||
int32_t diff=(int32_t)(stddevDelay-minDelay);
|
||||
if(diff>0){
|
||||
dontDecMinDelay=100;
|
||||
}
|
||||
if(diff<-1)
|
||||
diff=-1;
|
||||
if(diff>1)
|
||||
diff=1;
|
||||
if((diff>0 && dontIncMinDelay==0) || (diff<0 && dontDecMinDelay==0)){
|
||||
//nextTimestamp+=diff*(int32_t)step;
|
||||
minDelay.store(minDelay + diff);
|
||||
outstandingDelayChange+=diff*60;
|
||||
dontChangeDelay+=32;
|
||||
//LOGD("new delay from stddev %f", minDelay);
|
||||
if(diff<0){
|
||||
dontDecMinDelay+=25;
|
||||
}
|
||||
if(diff>0){
|
||||
dontIncMinDelay=25;
|
||||
}
|
||||
}
|
||||
}
|
||||
lastMeasuredJitter=stddev;
|
||||
lastMeasuredDelay=stddevDelay;
|
||||
//LOGV("stddev=%.3f, avg=%.3f, ndelay=%d, dontDec=%u", stddev, avgdev, stddevDelay, dontDecMinDelay);
|
||||
if(dontChangeDelay==0){
|
||||
if(avgDelay>minDelay+0.5){
|
||||
outstandingDelayChange-=avgDelay>minDelay+2 ? 60 : 20;
|
||||
dontChangeDelay+=10;
|
||||
}else if(avgDelay<minDelay-0.3){
|
||||
outstandingDelayChange+=20;
|
||||
dontChangeDelay+=10;
|
||||
}
|
||||
}
|
||||
if(dontChangeDelay>0)
|
||||
dontChangeDelay--;
|
||||
|
||||
//LOGV("jitter: avg delay=%d, delay=%d, late16=%.1f, dontDecMinDelay=%d", avgDelay, delayHistory[0], avgLate16, dontDecMinDelay);
|
||||
/*if(!adjustingDelay) {
|
||||
if (((minDelay==1 ? (avgDelay>=3) : (avgDelay>=minDelay/2)) && delayHistory[0]>minDelay && avgLate16<=0.1 && absolutelyNoLatePackets && dontDecMinDelay<32 && min>minDelay)) {
|
||||
LOGI("jitter: need adjust");
|
||||
adjustingDelay=true;
|
||||
}
|
||||
}else{
|
||||
if(!absolutelyNoLatePackets){
|
||||
LOGI("jitter: done adjusting because we're losing packets");
|
||||
adjustingDelay=false;
|
||||
}else if(tickCount%5==0){
|
||||
LOGD("jitter: removing a packet to reduce delay");
|
||||
GetInternal(NULL, 0);
|
||||
expectNextAtTime=0;
|
||||
if(GetCurrentDelay()<=minDelay || min<=minDelay){
|
||||
adjustingDelay = false;
|
||||
LOGI("jitter: done adjusting");
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
tickCount++;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void JitterBuffer::GetAverageLateCount(double *out){
|
||||
double avgLate64=lateHistory.Average(), avgLate32=lateHistory.Average(32), avgLate16=lateHistory.Average(16);
|
||||
out[0]=avgLate16;
|
||||
out[1]=avgLate32;
|
||||
out[2]=avgLate64;
|
||||
}
|
||||
|
||||
|
||||
int JitterBuffer::GetAndResetLostPacketCount(){
|
||||
MutexGuard m(mutex);
|
||||
int r=lostPackets;
|
||||
lostPackets=0;
|
||||
return r;
|
||||
}
|
||||
|
||||
double JitterBuffer::GetLastMeasuredJitter(){
|
||||
return lastMeasuredJitter;
|
||||
}
|
||||
|
||||
double JitterBuffer::GetLastMeasuredDelay(){
|
||||
return lastMeasuredDelay;
|
||||
}
|
||||
|
||||
double JitterBuffer::GetAverageDelay(){
|
||||
return avgDelay;
|
||||
}
|
98
TMessagesProj/jni/libtgvoip2/JitterBuffer.h
Normal file
98
TMessagesProj/jni/libtgvoip2/JitterBuffer.h
Normal file
|
@ -0,0 +1,98 @@
|
|||
//
|
||||
// libtgvoip is free and unencumbered public domain software.
|
||||
// For more information, see http://unlicense.org or the UNLICENSE file
|
||||
// you should have received with this source code distribution.
|
||||
//
|
||||
|
||||
#ifndef LIBTGVOIP_JITTERBUFFER_H
|
||||
#define LIBTGVOIP_JITTERBUFFER_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <vector>
|
||||
#include <atomic>
|
||||
#include <stdio.h>
|
||||
#include "MediaStreamItf.h"
|
||||
#include "BlockingQueue.h"
|
||||
#include "Buffers.h"
|
||||
#include "threading.h"
|
||||
|
||||
#define JITTER_SLOT_COUNT 64
|
||||
#define JITTER_SLOT_SIZE 1024
|
||||
#define JR_OK 1
|
||||
#define JR_MISSING 2
|
||||
#define JR_BUFFERING 3
|
||||
|
||||
|
||||
namespace tgvoip{
|
||||
class JitterBuffer{
|
||||
public:
|
||||
JitterBuffer(MediaStreamItf* out, uint32_t step);
|
||||
~JitterBuffer();
|
||||
void SetMinPacketCount(uint32_t count);
|
||||
int GetMinPacketCount();
|
||||
unsigned int GetCurrentDelay();
|
||||
double GetAverageDelay();
|
||||
void Reset();
|
||||
void HandleInput(unsigned char* data, size_t len, uint32_t timestamp, bool isEC);
|
||||
size_t HandleOutput(unsigned char* buffer, size_t len, int offsetInSteps, bool advance, int& playbackScaledDuration, bool& isEC);
|
||||
void Tick();
|
||||
void GetAverageLateCount(double* out);
|
||||
int GetAndResetLostPacketCount();
|
||||
double GetLastMeasuredJitter();
|
||||
double GetLastMeasuredDelay();
|
||||
|
||||
private:
|
||||
struct jitter_packet_t{
|
||||
Buffer buffer=Buffer();
|
||||
size_t size;
|
||||
uint32_t timestamp;
|
||||
bool isEC;
|
||||
double recvTimeDiff;
|
||||
};
|
||||
static size_t CallbackIn(unsigned char* data, size_t len, void* param);
|
||||
static size_t CallbackOut(unsigned char* data, size_t len, void* param);
|
||||
void PutInternal(jitter_packet_t* pkt, bool overwriteExisting);
|
||||
int GetInternal(jitter_packet_t* pkt, int offset, bool advance);
|
||||
void Advance();
|
||||
|
||||
BufferPool<JITTER_SLOT_SIZE, JITTER_SLOT_COUNT> bufferPool;
|
||||
Mutex mutex;
|
||||
jitter_packet_t slots[JITTER_SLOT_COUNT];
|
||||
int64_t nextTimestamp=0;
|
||||
uint32_t step;
|
||||
std::atomic<double> minDelay{6};
|
||||
uint32_t minMinDelay;
|
||||
uint32_t maxMinDelay;
|
||||
uint32_t maxUsedSlots;
|
||||
uint32_t lastPutTimestamp;
|
||||
uint32_t lossesToReset;
|
||||
double resyncThreshold;
|
||||
unsigned int lostCount=0;
|
||||
unsigned int lostSinceReset=0;
|
||||
unsigned int gotSinceReset=0;
|
||||
bool wasReset=true;
|
||||
bool needBuffering=true;
|
||||
HistoricBuffer<int, 64, double> delayHistory;
|
||||
HistoricBuffer<int, 64, double> lateHistory;
|
||||
bool adjustingDelay=false;
|
||||
unsigned int tickCount=0;
|
||||
unsigned int latePacketCount=0;
|
||||
unsigned int dontIncMinDelay=0;
|
||||
unsigned int dontDecMinDelay=0;
|
||||
int lostPackets=0;
|
||||
double prevRecvTime=0;
|
||||
double expectNextAtTime=0;
|
||||
HistoricBuffer<double, 64> deviationHistory;
|
||||
double lastMeasuredJitter=0;
|
||||
double lastMeasuredDelay=0;
|
||||
int outstandingDelayChange=0;
|
||||
unsigned int dontChangeDelay=0;
|
||||
double avgDelay=0;
|
||||
bool first=true;
|
||||
#ifdef TGVOIP_DUMP_JITTER_STATS
|
||||
FILE* dump;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
#endif //LIBTGVOIP_JITTERBUFFER_H
|
769
TMessagesProj/jni/libtgvoip2/Makefile.am
Normal file
769
TMessagesProj/jni/libtgvoip2/Makefile.am
Normal file
|
@ -0,0 +1,769 @@
|
|||
AUTOMAKE_OPTIONS = foreign
|
||||
|
||||
CFLAGS = -Wall -DHAVE_CONFIG_H -Wno-unknown-pragmas
|
||||
|
||||
lib_LTLIBRARIES = libtgvoip.la
|
||||
|
||||
SRC = TgVoip.cpp \
|
||||
VoIPController.cpp \
|
||||
Buffers.cpp \
|
||||
CongestionControl.cpp \
|
||||
EchoCanceller.cpp \
|
||||
JitterBuffer.cpp \
|
||||
logging.cpp \
|
||||
MediaStreamItf.cpp \
|
||||
MessageThread.cpp \
|
||||
NetworkSocket.cpp \
|
||||
OpusDecoder.cpp \
|
||||
OpusEncoder.cpp \
|
||||
PacketReassembler.cpp \
|
||||
VoIPGroupController.cpp \
|
||||
VoIPServerConfig.cpp \
|
||||
audio/AudioIO.cpp \
|
||||
audio/AudioInput.cpp \
|
||||
audio/AudioOutput.cpp \
|
||||
audio/Resampler.cpp \
|
||||
os/posix/NetworkSocketPosix.cpp \
|
||||
video/VideoSource.cpp \
|
||||
video/VideoRenderer.cpp \
|
||||
video/VideoPacketSender.cpp \
|
||||
video/VideoFEC.cpp \
|
||||
video/ScreamCongestionController.cpp \
|
||||
json11.cpp
|
||||
|
||||
TGVOIP_HDRS = \
|
||||
TgVoip.h \
|
||||
VoIPController.h \
|
||||
Buffers.h \
|
||||
BlockingQueue.h \
|
||||
PrivateDefines.h \
|
||||
CongestionControl.h \
|
||||
EchoCanceller.h \
|
||||
JitterBuffer.h \
|
||||
logging.h \
|
||||
threading.h \
|
||||
MediaStreamItf.h \
|
||||
MessageThread.h \
|
||||
NetworkSocket.h \
|
||||
OpusDecoder.h \
|
||||
OpusEncoder.h \
|
||||
PacketReassembler.h \
|
||||
VoIPServerConfig.h \
|
||||
audio/AudioIO.h \
|
||||
audio/AudioInput.h \
|
||||
audio/AudioOutput.h \
|
||||
audio/Resampler.h \
|
||||
os/posix/NetworkSocketPosix.h \
|
||||
video/VideoSource.h \
|
||||
video/VideoPacketSender.h \
|
||||
video/VideoFEC.h \
|
||||
video/VideoRenderer.h \
|
||||
video/ScreamCongestionController.h \
|
||||
json11.hpp \
|
||||
utils.h
|
||||
|
||||
if TARGET_OS_OSX
|
||||
|
||||
SRC += \
|
||||
os/darwin/AudioInputAudioUnit.cpp \
|
||||
os/darwin/AudioOutputAudioUnit.cpp \
|
||||
os/darwin/AudioUnitIO.cpp \
|
||||
os/darwin/AudioInputAudioUnitOSX.cpp \
|
||||
os/darwin/AudioOutputAudioUnitOSX.cpp \
|
||||
os/darwin/DarwinSpecific.mm \
|
||||
os/darwin/SampleBufferDisplayLayerRenderer.mm \
|
||||
os/darwin/TGVVideoRenderer.mm \
|
||||
os/darwin/TGVVideoSource.mm \
|
||||
os/darwin/VideoToolboxEncoderSource.mm
|
||||
|
||||
TGVOIP_HDRS += \
|
||||
os/darwin/AudioInputAudioUnit.h \
|
||||
os/darwin/AudioOutputAudioUnit.h \
|
||||
os/darwin/AudioUnitIO.h \
|
||||
os/darwin/AudioInputAudioUnitOSX.h \
|
||||
os/darwin/AudioOutputAudioUnitOSX.h \
|
||||
os/darwin/DarwinSpecific.h \
|
||||
os/darwin/SampleBufferDisplayLayerRenderer.h \
|
||||
os/darwin/TGVVideoRenderer.h \
|
||||
os/darwin/TGVVideoSource.h \
|
||||
os/darwin/VideoToolboxEncoderSource.h
|
||||
|
||||
LDFLAGS += -framework Foundation -framework CoreFoundation -framework CoreAudio -framework AudioToolbox -framework VideoToolbox -framework CoreMedia -framework CoreVideo
|
||||
|
||||
else
|
||||
# Linux-specific
|
||||
|
||||
if WITH_ALSA
|
||||
SRC += \
|
||||
os/linux/AudioInputALSA.cpp \
|
||||
os/linux/AudioOutputALSA.cpp
|
||||
TGVOIP_HDRS += \
|
||||
os/linux/AudioInputALSA.h \
|
||||
os/linux/AudioOutputALSA.h
|
||||
endif
|
||||
|
||||
if WITH_PULSE
|
||||
SRC += \
|
||||
os/linux/AudioOutputPulse.cpp \
|
||||
os/linux/AudioInputPulse.cpp \
|
||||
os/linux/AudioPulse.cpp
|
||||
TGVOIP_HDRS += \
|
||||
os/linux/AudioOutputPulse.h \
|
||||
os/linux/AudioInputPulse.h \
|
||||
os/linux/AudioPulse.h \
|
||||
os/linux/PulseFunctions.h
|
||||
endif
|
||||
endif
|
||||
|
||||
if ENABLE_DSP
|
||||
CFLAGS += -DWEBRTC_POSIX -DWEBRTC_APM_DEBUG_DUMP=0 -DWEBRTC_NS_FLOAT -I$(top_srcdir)/webrtc_dsp
|
||||
CCASFLAGS += -I$(top_srcdir)/webrtc_dsp
|
||||
|
||||
SRC += \
|
||||
./webrtc_dsp/system_wrappers/source/field_trial.cc \
|
||||
./webrtc_dsp/system_wrappers/source/metrics.cc \
|
||||
./webrtc_dsp/system_wrappers/source/cpu_features.cc \
|
||||
./webrtc_dsp/absl/strings/internal/memutil.cc \
|
||||
./webrtc_dsp/absl/strings/string_view.cc \
|
||||
./webrtc_dsp/absl/strings/ascii.cc \
|
||||
./webrtc_dsp/absl/types/bad_optional_access.cc \
|
||||
./webrtc_dsp/absl/types/optional.cc \
|
||||
./webrtc_dsp/absl/base/internal/raw_logging.cc \
|
||||
./webrtc_dsp/absl/base/internal/throw_delegate.cc \
|
||||
./webrtc_dsp/rtc_base/race_checker.cc \
|
||||
./webrtc_dsp/rtc_base/strings/string_builder.cc \
|
||||
./webrtc_dsp/rtc_base/memory/aligned_malloc.cc \
|
||||
./webrtc_dsp/rtc_base/timeutils.cc \
|
||||
./webrtc_dsp/rtc_base/platform_file.cc \
|
||||
./webrtc_dsp/rtc_base/string_to_number.cc \
|
||||
./webrtc_dsp/rtc_base/thread_checker_impl.cc \
|
||||
./webrtc_dsp/rtc_base/stringencode.cc \
|
||||
./webrtc_dsp/rtc_base/stringutils.cc \
|
||||
./webrtc_dsp/rtc_base/checks.cc \
|
||||
./webrtc_dsp/rtc_base/platform_thread.cc \
|
||||
./webrtc_dsp/rtc_base/logging_webrtc.cc \
|
||||
./webrtc_dsp/rtc_base/criticalsection.cc \
|
||||
./webrtc_dsp/rtc_base/platform_thread_types.cc \
|
||||
./webrtc_dsp/rtc_base/event.cc \
|
||||
./webrtc_dsp/rtc_base/event_tracer.cc \
|
||||
./webrtc_dsp/third_party/rnnoise/src/rnn_vad_weights.cc \
|
||||
./webrtc_dsp/third_party/rnnoise/src/kiss_fft.cc \
|
||||
./webrtc_dsp/api/audio/audio_frame.cc \
|
||||
./webrtc_dsp/api/audio/echo_canceller3_config.cc \
|
||||
./webrtc_dsp/api/audio/echo_canceller3_factory.cc \
|
||||
./webrtc_dsp/modules/third_party/fft/fft.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/pitch_estimator.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/arith_routines_logist.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/filterbanks.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/transform.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/pitch_filter.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/filter_functions.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/decode.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/lattice.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/intialize.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/lpc_tables.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/encode.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/lpc_analysis.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/arith_routines_hist.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/entropy_coding.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/isac_vad.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/arith_routines.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/crc.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/decode_bwe.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.c \
|
||||
./webrtc_dsp/modules/audio_coding/codecs/isac/main/source/isac.c \
|
||||
./webrtc_dsp/modules/audio_processing/rms_level.cc \
|
||||
./webrtc_dsp/modules/audio_processing/echo_detector/normalized_covariance_estimator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/echo_detector/moving_max.cc \
|
||||
./webrtc_dsp/modules/audio_processing/echo_detector/circular_buffer.cc \
|
||||
./webrtc_dsp/modules/audio_processing/echo_detector/mean_variance_estimator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/splitting_filter.cc \
|
||||
./webrtc_dsp/modules/audio_processing/gain_control_impl.cc \
|
||||
./webrtc_dsp/modules/audio_processing/ns/nsx_core.c \
|
||||
./webrtc_dsp/modules/audio_processing/ns/noise_suppression_x.c \
|
||||
./webrtc_dsp/modules/audio_processing/ns/nsx_core_c.c \
|
||||
./webrtc_dsp/modules/audio_processing/ns/ns_core.c \
|
||||
./webrtc_dsp/modules/audio_processing/ns/noise_suppression.c \
|
||||
./webrtc_dsp/modules/audio_processing/audio_buffer.cc \
|
||||
./webrtc_dsp/modules/audio_processing/typing_detection.cc \
|
||||
./webrtc_dsp/modules/audio_processing/include/audio_processing_statistics.cc \
|
||||
./webrtc_dsp/modules/audio_processing/include/audio_generator_factory.cc \
|
||||
./webrtc_dsp/modules/audio_processing/include/aec_dump.cc \
|
||||
./webrtc_dsp/modules/audio_processing/include/audio_processing.cc \
|
||||
./webrtc_dsp/modules/audio_processing/include/config.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/interpolated_gain_curve.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/agc2_common.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/gain_applier.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/adaptive_agc.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/adaptive_digital_gain_applier.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/limiter.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/saturation_protector.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/rnn_vad/spectral_features_internal.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/rnn_vad/rnn.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/rnn_vad/pitch_search_internal.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/rnn_vad/spectral_features.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/rnn_vad/pitch_search.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/rnn_vad/features_extraction.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/rnn_vad/fft_util.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/rnn_vad/lp_residual.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/adaptive_mode_level_estimator_agc.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/vector_float_frame.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/noise_level_estimator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/agc2_testing_common.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/fixed_digital_level_estimator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/fixed_gain_controller.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/vad_with_level.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/limiter_db_gain_curve.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/down_sampler.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/signal_classifier.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/noise_spectrum_estimator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/compute_interpolated_gain_curve.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/biquad_filter.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc2/adaptive_mode_level_estimator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/transient/moving_moments.cc \
|
||||
./webrtc_dsp/modules/audio_processing/transient/wpd_tree.cc \
|
||||
./webrtc_dsp/modules/audio_processing/transient/wpd_node.cc \
|
||||
./webrtc_dsp/modules/audio_processing/transient/transient_suppressor.cc \
|
||||
./webrtc_dsp/modules/audio_processing/transient/transient_detector.cc \
|
||||
./webrtc_dsp/modules/audio_processing/low_cut_filter.cc \
|
||||
./webrtc_dsp/modules/audio_processing/level_estimator_impl.cc \
|
||||
./webrtc_dsp/modules/audio_processing/three_band_filter_bank.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec/echo_cancellation.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec/aec_resampler.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec/aec_core.cc \
|
||||
./webrtc_dsp/modules/audio_processing/voice_detection_impl.cc \
|
||||
./webrtc_dsp/modules/audio_processing/echo_cancellation_impl.cc \
|
||||
./webrtc_dsp/modules/audio_processing/gain_control_for_experimental_agc.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc/agc.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc/loudness_histogram.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc/agc_manager_direct.cc \
|
||||
./webrtc_dsp/modules/audio_processing/agc/legacy/analog_agc.c \
|
||||
./webrtc_dsp/modules/audio_processing/agc/legacy/digital_agc.c \
|
||||
./webrtc_dsp/modules/audio_processing/agc/utility.cc \
|
||||
./webrtc_dsp/modules/audio_processing/audio_processing_impl.cc \
|
||||
./webrtc_dsp/modules/audio_processing/audio_generator/file_audio_generator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/gain_controller2.cc \
|
||||
./webrtc_dsp/modules/audio_processing/residual_echo_detector.cc \
|
||||
./webrtc_dsp/modules/audio_processing/noise_suppression_impl.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aecm/aecm_core.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aecm/aecm_core_c.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aecm/echo_control_mobile.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/render_reverb_model.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/reverb_model_fallback.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/echo_remover_metrics.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/matched_filter_lag_aggregator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/render_delay_buffer2.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/echo_path_variability.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/frame_blocker.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/subtractor.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/aec3_fft.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/fullband_erle_estimator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/suppression_filter.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/block_processor.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/subband_erle_estimator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/render_delay_controller_metrics.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/render_delay_buffer.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/vector_buffer.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/erl_estimator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/aec_state.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/adaptive_fir_filter.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/render_delay_controller.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/skew_estimator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/echo_path_delay_estimator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/block_framer.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/erle_estimator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/reverb_model.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/cascaded_biquad_filter.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/render_buffer.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/subtractor_output.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/stationarity_estimator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/render_signal_analyzer.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/subtractor_output_analyzer.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/suppression_gain.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/echo_audibility.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/block_processor_metrics.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/moving_average.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/reverb_model_estimator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/aec3_common.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/residual_echo_estimator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/matched_filter.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/reverb_decay_estimator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/render_delay_controller2.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/suppression_gain_limiter.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/main_filter_update_gain.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/echo_remover.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/downsampled_render_buffer.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/matrix_buffer.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/block_processor2.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/echo_canceller3.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/block_delay_buffer.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/fft_buffer.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/comfort_noise_generator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/shadow_filter_update_gain.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/filter_analyzer.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/reverb_frequency_response.cc \
|
||||
./webrtc_dsp/modules/audio_processing/aec3/decimator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/echo_control_mobile_impl.cc \
|
||||
./webrtc_dsp/modules/audio_processing/logging/apm_data_dumper.cc \
|
||||
./webrtc_dsp/modules/audio_processing/vad/voice_activity_detector.cc \
|
||||
./webrtc_dsp/modules/audio_processing/vad/standalone_vad.cc \
|
||||
./webrtc_dsp/modules/audio_processing/vad/pitch_internal.cc \
|
||||
./webrtc_dsp/modules/audio_processing/vad/vad_circular_buffer.cc \
|
||||
./webrtc_dsp/modules/audio_processing/vad/vad_audio_proc.cc \
|
||||
./webrtc_dsp/modules/audio_processing/vad/pole_zero_filter.cc \
|
||||
./webrtc_dsp/modules/audio_processing/vad/pitch_based_vad.cc \
|
||||
./webrtc_dsp/modules/audio_processing/vad/gmm.cc \
|
||||
./webrtc_dsp/modules/audio_processing/utility/ooura_fft.cc \
|
||||
./webrtc_dsp/modules/audio_processing/utility/delay_estimator_wrapper.cc \
|
||||
./webrtc_dsp/modules/audio_processing/utility/delay_estimator.cc \
|
||||
./webrtc_dsp/modules/audio_processing/utility/block_mean_calculator.cc \
|
||||
./webrtc_dsp/common_audio/window_generator.cc \
|
||||
./webrtc_dsp/common_audio/channel_buffer.cc \
|
||||
./webrtc_dsp/common_audio/fir_filter_factory.cc \
|
||||
./webrtc_dsp/common_audio/wav_header.cc \
|
||||
./webrtc_dsp/common_audio/real_fourier_ooura.cc \
|
||||
./webrtc_dsp/common_audio/audio_util.cc \
|
||||
./webrtc_dsp/common_audio/fir_filter_sse.cc \
|
||||
./webrtc_dsp/common_audio/resampler/push_sinc_resampler.cc \
|
||||
./webrtc_dsp/common_audio/resampler/resampler.cc \
|
||||
./webrtc_dsp/common_audio/resampler/sinc_resampler_sse.cc \
|
||||
./webrtc_dsp/common_audio/resampler/push_resampler.cc \
|
||||
./webrtc_dsp/common_audio/resampler/sinc_resampler.cc \
|
||||
./webrtc_dsp/common_audio/resampler/sinusoidal_linear_chirp_source.cc \
|
||||
./webrtc_dsp/common_audio/wav_file.cc \
|
||||
./webrtc_dsp/common_audio/third_party/fft4g/fft4g.c \
|
||||
./webrtc_dsp/common_audio/audio_converter.cc \
|
||||
./webrtc_dsp/common_audio/real_fourier.cc \
|
||||
./webrtc_dsp/common_audio/sparse_fir_filter.cc \
|
||||
./webrtc_dsp/common_audio/smoothing_filter.cc \
|
||||
./webrtc_dsp/common_audio/fir_filter_c.cc \
|
||||
./webrtc_dsp/common_audio/ring_buffer.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/complex_fft.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/filter_ma_fast_q12.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/splitting_filter1.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/levinson_durbin.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/dot_product_with_scale.cc \
|
||||
./webrtc_dsp/common_audio/signal_processing/auto_corr_to_refl_coef.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/resample_by_2_internal.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/energy.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/sqrt_of_one_minus_x_squared.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/downsample_fast.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/filter_ar_fast_q12.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/spl_init.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/lpc_to_refl_coef.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/cross_correlation.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/division_operations.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/auto_correlation.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/get_scaling_square.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/resample.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/min_max_operations.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/refl_coef_to_lpc.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/filter_ar.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/vector_scaling_operations.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/resample_fractional.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/real_fft.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/ilbc_specific_functions.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/randomization_functions.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/copy_set_operations.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/resample_by_2.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/get_hanning_window.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/resample_48khz.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/spl_inl.c \
|
||||
./webrtc_dsp/common_audio/signal_processing/spl_sqrt.c \
|
||||
./webrtc_dsp/common_audio/vad/vad_sp.c \
|
||||
./webrtc_dsp/common_audio/vad/vad.cc \
|
||||
./webrtc_dsp/common_audio/vad/webrtc_vad.c \
|
||||
./webrtc_dsp/common_audio/vad/vad_filterbank.c \
|
||||
./webrtc_dsp/common_audio/vad/vad_core.c \
|
||||
./webrtc_dsp/common_audio/vad/vad_gmm.c
|
||||
|
||||
if TARGET_OS_OSX
|
||||
CFLAGS += -DWEBRTC_MAC
|
||||
SRC += \
|
||||
webrtc_dsp/rtc_base/logging_mac.mm \
|
||||
webrtc_dsp/rtc_base/logging_mac.h
|
||||
else
|
||||
CFLAGS += -DWEBRTC_LINUX
|
||||
endif
|
||||
|
||||
if TARGET_CPU_X86
|
||||
SRC += \
|
||||
webrtc_dsp/modules/audio_processing/aec/aec_core_sse2.cc \
|
||||
webrtc_dsp/modules/audio_processing/utility/ooura_fft_sse2.cc
|
||||
endif
|
||||
|
||||
if ENABLE_AUDIO_CALLBACK
|
||||
CFLAGS += -DTGVOIP_USE_CALLBACK_AUDIO_IO
|
||||
SRC += \
|
||||
audio/AudioIOCallback.cpp
|
||||
TGVOIP_HDRS += \
|
||||
audio/AudioIOCallback.h
|
||||
endif
|
||||
|
||||
if TARGET_CPU_ARM
|
||||
SRC += \
|
||||
webrtc_dsp/common_audio/signal_processing/complex_bit_reverse_arm.S \
|
||||
webrtc_dsp/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor_arm.S
|
||||
if TARGET_CPU_ARMV7
|
||||
CFLAGS += -mfpu=neon -mfloat-abi=hard
|
||||
CCASFLAGS += -mfpu=neon -mfloat-abi=hard
|
||||
SRC += \
|
||||
webrtc_dsp/common_audio/signal_processing/cross_correlation_neon.c \
|
||||
webrtc_dsp/common_audio/signal_processing/downsample_fast_neon.c \
|
||||
webrtc_dsp/common_audio/signal_processing/min_max_operations_neon.c \
|
||||
webrtc_dsp/modules/audio_processing/aec/aec_core_neon.cc \
|
||||
webrtc_dsp/modules/audio_processing/aecm/aecm_core_neon.cc \
|
||||
webrtc_dsp/modules/audio_processing/ns/nsx_core_neon.c \
|
||||
webrtc_dsp/modules/audio_processing/utility/ooura_fft_neon.cc
|
||||
# webrtc_dsp/common_audio/signal_processing/filter_ar_fast_q12_armv7.S
|
||||
endif
|
||||
else
|
||||
SRC += \
|
||||
webrtc_dsp/common_audio/signal_processing/complex_bit_reverse.c \
|
||||
webrtc_dsp/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.c
|
||||
endif
|
||||
|
||||
# headers
|
||||
SRC += \
|
||||
webrtc_dsp/system_wrappers/include/field_trial.h \
|
||||
webrtc_dsp/system_wrappers/include/cpu_features_wrapper.h \
|
||||
webrtc_dsp/system_wrappers/include/asm_defines.h \
|
||||
webrtc_dsp/system_wrappers/include/metrics.h \
|
||||
webrtc_dsp/system_wrappers/include/compile_assert_c.h \
|
||||
webrtc_dsp/typedefs.h \
|
||||
webrtc_dsp/absl/strings/internal/memutil.h \
|
||||
webrtc_dsp/absl/strings/ascii.h \
|
||||
webrtc_dsp/absl/strings/string_view.h \
|
||||
webrtc_dsp/absl/types/optional.h \
|
||||
webrtc_dsp/absl/types/bad_optional_access.h \
|
||||
webrtc_dsp/absl/memory/memory.h \
|
||||
webrtc_dsp/absl/meta/type_traits.h \
|
||||
webrtc_dsp/absl/algorithm/algorithm.h \
|
||||
webrtc_dsp/absl/container/inlined_vector.h \
|
||||
webrtc_dsp/absl/base/policy_checks.h \
|
||||
webrtc_dsp/absl/base/port.h \
|
||||
webrtc_dsp/absl/base/config.h \
|
||||
webrtc_dsp/absl/base/internal/invoke.h \
|
||||
webrtc_dsp/absl/base/internal/inline_variable.h \
|
||||
webrtc_dsp/absl/base/internal/atomic_hook.h \
|
||||
webrtc_dsp/absl/base/internal/identity.h \
|
||||
webrtc_dsp/absl/base/internal/raw_logging.h \
|
||||
webrtc_dsp/absl/base/internal/throw_delegate.h \
|
||||
webrtc_dsp/absl/base/attributes.h \
|
||||
webrtc_dsp/absl/base/macros.h \
|
||||
webrtc_dsp/absl/base/optimization.h \
|
||||
webrtc_dsp/absl/base/log_severity.h \
|
||||
webrtc_dsp/absl/utility/utility.h \
|
||||
webrtc_dsp/rtc_base/string_to_number.h \
|
||||
webrtc_dsp/rtc_base/constructormagic.h \
|
||||
webrtc_dsp/rtc_base/strings/string_builder.h \
|
||||
webrtc_dsp/rtc_base/event_tracer.h \
|
||||
webrtc_dsp/rtc_base/stringencode.h \
|
||||
webrtc_dsp/rtc_base/memory/aligned_malloc.h \
|
||||
webrtc_dsp/rtc_base/event.h \
|
||||
webrtc_dsp/rtc_base/ignore_wundef.h \
|
||||
webrtc_dsp/rtc_base/stringutils.h \
|
||||
webrtc_dsp/rtc_base/arraysize.h \
|
||||
webrtc_dsp/rtc_base/swap_queue.h \
|
||||
webrtc_dsp/rtc_base/trace_event.h \
|
||||
webrtc_dsp/rtc_base/checks.h \
|
||||
webrtc_dsp/rtc_base/deprecation.h \
|
||||
webrtc_dsp/rtc_base/sanitizer.h \
|
||||
webrtc_dsp/rtc_base/scoped_ref_ptr.h \
|
||||
webrtc_dsp/rtc_base/logging.h \
|
||||
webrtc_dsp/rtc_base/timeutils.h \
|
||||
webrtc_dsp/rtc_base/atomicops.h \
|
||||
webrtc_dsp/rtc_base/numerics/safe_minmax.h \
|
||||
webrtc_dsp/rtc_base/numerics/safe_conversions.h \
|
||||
webrtc_dsp/rtc_base/numerics/safe_conversions_impl.h \
|
||||
webrtc_dsp/rtc_base/numerics/safe_compare.h \
|
||||
webrtc_dsp/rtc_base/system/unused.h \
|
||||
webrtc_dsp/rtc_base/system/inline.h \
|
||||
webrtc_dsp/rtc_base/system/ignore_warnings.h \
|
||||
webrtc_dsp/rtc_base/system/asm_defines.h \
|
||||
webrtc_dsp/rtc_base/system/rtc_export.h \
|
||||
webrtc_dsp/rtc_base/system/arch.h \
|
||||
webrtc_dsp/rtc_base/platform_thread.h \
|
||||
webrtc_dsp/rtc_base/platform_thread_types.h \
|
||||
webrtc_dsp/rtc_base/protobuf_utils.h \
|
||||
webrtc_dsp/rtc_base/thread_annotations.h \
|
||||
webrtc_dsp/rtc_base/gtest_prod_util.h \
|
||||
webrtc_dsp/rtc_base/function_view.h \
|
||||
webrtc_dsp/rtc_base/criticalsection.h \
|
||||
webrtc_dsp/rtc_base/refcount.h \
|
||||
webrtc_dsp/rtc_base/thread_checker_impl.h \
|
||||
webrtc_dsp/rtc_base/compile_assert_c.h \
|
||||
webrtc_dsp/rtc_base/type_traits.h \
|
||||
webrtc_dsp/rtc_base/platform_file.h \
|
||||
webrtc_dsp/rtc_base/refcounter.h \
|
||||
webrtc_dsp/rtc_base/thread_checker.h \
|
||||
webrtc_dsp/rtc_base/race_checker.h \
|
||||
webrtc_dsp/rtc_base/refcountedobject.h \
|
||||
webrtc_dsp/third_party/rnnoise/src/rnn_activations.h \
|
||||
webrtc_dsp/third_party/rnnoise/src/kiss_fft.h \
|
||||
webrtc_dsp/third_party/rnnoise/src/rnn_vad_weights.h \
|
||||
webrtc_dsp/api/audio/echo_canceller3_config.h \
|
||||
webrtc_dsp/api/audio/echo_control.h \
|
||||
webrtc_dsp/api/audio/audio_frame.h \
|
||||
webrtc_dsp/api/audio/echo_canceller3_factory.h \
|
||||
webrtc_dsp/api/array_view.h \
|
||||
webrtc_dsp/modules/third_party/fft/fft.h \
|
||||
webrtc_dsp/modules/audio_coding/codecs/isac/bandwidth_info.h \
|
||||
webrtc_dsp/modules/audio_coding/codecs/isac/main/include/isac.h \
|
||||
webrtc_dsp/modules/audio_coding/codecs/isac/main/source/os_specific_inline.h \
|
||||
webrtc_dsp/modules/audio_coding/codecs/isac/main/source/entropy_coding.h \
|
||||
webrtc_dsp/modules/audio_coding/codecs/isac/main/source/isac_vad.h \
|
||||
webrtc_dsp/modules/audio_coding/codecs/isac/main/source/settings.h \
|
||||
webrtc_dsp/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.h \
|
||||
webrtc_dsp/modules/audio_coding/codecs/isac/main/source/arith_routines.h \
|
||||
webrtc_dsp/modules/audio_coding/codecs/isac/main/source/crc.h \
|
||||
webrtc_dsp/modules/audio_coding/codecs/isac/main/source/isac_float_type.h \
|
||||
webrtc_dsp/modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.h \
|
||||
webrtc_dsp/modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.h \
|
||||
webrtc_dsp/modules/audio_coding/codecs/isac/main/source/codec.h \
|
||||
webrtc_dsp/modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.h \
|
||||
webrtc_dsp/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h \
|
||||
webrtc_dsp/modules/audio_coding/codecs/isac/main/source/pitch_estimator.h \
|
||||
webrtc_dsp/modules/audio_coding/codecs/isac/main/source/structs.h \
|
||||
webrtc_dsp/modules/audio_coding/codecs/isac/main/source/filter_functions.h \
|
||||
webrtc_dsp/modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.h \
|
||||
webrtc_dsp/modules/audio_coding/codecs/isac/main/source/pitch_filter.h \
|
||||
webrtc_dsp/modules/audio_coding/codecs/isac/main/source/lpc_analysis.h \
|
||||
webrtc_dsp/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h \
|
||||
webrtc_dsp/modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.h \
|
||||
webrtc_dsp/modules/audio_coding/codecs/isac/main/source/lpc_tables.h \
|
||||
webrtc_dsp/modules/audio_processing/echo_detector/moving_max.h \
|
||||
webrtc_dsp/modules/audio_processing/echo_detector/circular_buffer.h \
|
||||
webrtc_dsp/modules/audio_processing/echo_detector/normalized_covariance_estimator.h \
|
||||
webrtc_dsp/modules/audio_processing/echo_detector/mean_variance_estimator.h \
|
||||
webrtc_dsp/modules/audio_processing/gain_control_for_experimental_agc.h \
|
||||
webrtc_dsp/modules/audio_processing/rms_level.h \
|
||||
webrtc_dsp/modules/audio_processing/ns/ns_core.h \
|
||||
webrtc_dsp/modules/audio_processing/ns/defines.h \
|
||||
webrtc_dsp/modules/audio_processing/ns/noise_suppression.h \
|
||||
webrtc_dsp/modules/audio_processing/ns/nsx_core.h \
|
||||
webrtc_dsp/modules/audio_processing/ns/windows_private.h \
|
||||
webrtc_dsp/modules/audio_processing/ns/noise_suppression_x.h \
|
||||
webrtc_dsp/modules/audio_processing/ns/nsx_defines.h \
|
||||
webrtc_dsp/modules/audio_processing/residual_echo_detector.h \
|
||||
webrtc_dsp/modules/audio_processing/audio_processing_impl.h \
|
||||
webrtc_dsp/modules/audio_processing/render_queue_item_verifier.h \
|
||||
webrtc_dsp/modules/audio_processing/include/audio_generator.h \
|
||||
webrtc_dsp/modules/audio_processing/include/config.h \
|
||||
webrtc_dsp/modules/audio_processing/include/audio_frame_view.h \
|
||||
webrtc_dsp/modules/audio_processing/include/mock_audio_processing.h \
|
||||
webrtc_dsp/modules/audio_processing/include/gain_control.h \
|
||||
webrtc_dsp/modules/audio_processing/include/audio_generator_factory.h \
|
||||
webrtc_dsp/modules/audio_processing/include/aec_dump.h \
|
||||
webrtc_dsp/modules/audio_processing/include/audio_processing_statistics.h \
|
||||
webrtc_dsp/modules/audio_processing/include/audio_processing.h \
|
||||
webrtc_dsp/modules/audio_processing/agc2/interpolated_gain_curve.h \
|
||||
webrtc_dsp/modules/audio_processing/agc2/biquad_filter.h \
|
||||
webrtc_dsp/modules/audio_processing/agc2/agc2_testing_common.h \
|
||||
webrtc_dsp/modules/audio_processing/agc2/adaptive_mode_level_estimator.h \
|
||||
webrtc_dsp/modules/audio_processing/agc2/signal_classifier.h \
|
||||
webrtc_dsp/modules/audio_processing/agc2/vector_float_frame.h \
|
||||
webrtc_dsp/modules/audio_processing/agc2/rnn_vad/sequence_buffer.h \
|
||||
webrtc_dsp/modules/audio_processing/agc2/rnn_vad/rnn.h \
|
||||
webrtc_dsp/modules/audio_processing/agc2/rnn_vad/test_utils.h \
|
||||
webrtc_dsp/modules/audio_processing/agc2/rnn_vad/pitch_info.h \
|
||||
webrtc_dsp/modules/audio_processing/agc2/rnn_vad/lp_residual.h \
|
||||
webrtc_dsp/modules/audio_processing/agc2/rnn_vad/ring_buffer.h \
|
||||
webrtc_dsp/modules/audio_processing/agc2/rnn_vad/symmetric_matrix_buffer.h \
|
||||
webrtc_dsp/modules/audio_processing/agc2/rnn_vad/spectral_features.h \
|
||||
webrtc_dsp/modules/audio_processing/agc2/rnn_vad/features_extraction.h \
|
||||
webrtc_dsp/modules/audio_processing/agc2/rnn_vad/common.h \
|
||||
webrtc_dsp/modules/audio_processing/agc2/rnn_vad/spectral_features_internal.h \
|
||||
webrtc_dsp/modules/audio_processing/agc2/rnn_vad/fft_util.h \
|
||||
webrtc_dsp/modules/audio_processing/agc2/rnn_vad/pitch_search_internal.h \
|
||||
webrtc_dsp/modules/audio_processing/agc2/rnn_vad/pitch_search.h \
|
||||
webrtc_dsp/modules/audio_processing/agc2/fixed_gain_controller.h \
|
||||
webrtc_dsp/modules/audio_processing/agc2/down_sampler.h \
|
||||
webrtc_dsp/modules/audio_processing/agc2/saturation_protector.h \
|
||||
webrtc_dsp/modules/audio_processing/agc2/agc2_common.h \
|
||||
webrtc_dsp/modules/audio_processing/agc2/adaptive_mode_level_estimator_agc.h \
|
||||
webrtc_dsp/modules/audio_processing/agc2/adaptive_digital_gain_applier.h \
|
||||
webrtc_dsp/modules/audio_processing/agc2/vad_with_level.h \
|
||||
webrtc_dsp/modules/audio_processing/agc2/limiter_db_gain_curve.h \
|
||||
webrtc_dsp/modules/audio_processing/agc2/fixed_digital_level_estimator.h \
|
||||
webrtc_dsp/modules/audio_processing/agc2/adaptive_agc.h \
|
||||
webrtc_dsp/modules/audio_processing/agc2/gain_applier.h \
|
||||
webrtc_dsp/modules/audio_processing/agc2/noise_level_estimator.h \
|
||||
webrtc_dsp/modules/audio_processing/agc2/compute_interpolated_gain_curve.h \
|
||||
webrtc_dsp/modules/audio_processing/agc2/noise_spectrum_estimator.h \
|
||||
webrtc_dsp/modules/audio_processing/agc2/limiter.h \
|
||||
webrtc_dsp/modules/audio_processing/transient/transient_detector.h \
|
||||
webrtc_dsp/modules/audio_processing/transient/transient_suppressor.h \
|
||||
webrtc_dsp/modules/audio_processing/transient/daubechies_8_wavelet_coeffs.h \
|
||||
webrtc_dsp/modules/audio_processing/transient/common.h \
|
||||
webrtc_dsp/modules/audio_processing/transient/wpd_node.h \
|
||||
webrtc_dsp/modules/audio_processing/transient/moving_moments.h \
|
||||
webrtc_dsp/modules/audio_processing/transient/wpd_tree.h \
|
||||
webrtc_dsp/modules/audio_processing/transient/dyadic_decimator.h \
|
||||
webrtc_dsp/modules/audio_processing/noise_suppression_impl.h \
|
||||
webrtc_dsp/modules/audio_processing/aec/aec_resampler.h \
|
||||
webrtc_dsp/modules/audio_processing/aec/echo_cancellation.h \
|
||||
webrtc_dsp/modules/audio_processing/aec/aec_core.h \
|
||||
webrtc_dsp/modules/audio_processing/aec/aec_core_optimized_methods.h \
|
||||
webrtc_dsp/modules/audio_processing/aec/aec_common.h \
|
||||
webrtc_dsp/modules/audio_processing/voice_detection_impl.h \
|
||||
webrtc_dsp/modules/audio_processing/agc/legacy/analog_agc.h \
|
||||
webrtc_dsp/modules/audio_processing/agc/legacy/gain_control.h \
|
||||
webrtc_dsp/modules/audio_processing/agc/legacy/digital_agc.h \
|
||||
webrtc_dsp/modules/audio_processing/agc/mock_agc.h \
|
||||
webrtc_dsp/modules/audio_processing/agc/loudness_histogram.h \
|
||||
webrtc_dsp/modules/audio_processing/agc/gain_map_internal.h \
|
||||
webrtc_dsp/modules/audio_processing/agc/utility.h \
|
||||
webrtc_dsp/modules/audio_processing/agc/agc_manager_direct.h \
|
||||
webrtc_dsp/modules/audio_processing/agc/agc.h \
|
||||
webrtc_dsp/modules/audio_processing/common.h \
|
||||
webrtc_dsp/modules/audio_processing/audio_buffer.h \
|
||||
webrtc_dsp/modules/audio_processing/echo_control_mobile_impl.h \
|
||||
webrtc_dsp/modules/audio_processing/splitting_filter.h \
|
||||
webrtc_dsp/modules/audio_processing/low_cut_filter.h \
|
||||
webrtc_dsp/modules/audio_processing/audio_generator/file_audio_generator.h \
|
||||
webrtc_dsp/modules/audio_processing/three_band_filter_bank.h \
|
||||
webrtc_dsp/modules/audio_processing/echo_cancellation_impl.h \
|
||||
webrtc_dsp/modules/audio_processing/level_estimator_impl.h \
|
||||
webrtc_dsp/modules/audio_processing/gain_controller2.h \
|
||||
webrtc_dsp/modules/audio_processing/aecm/aecm_core.h \
|
||||
webrtc_dsp/modules/audio_processing/aecm/aecm_defines.h \
|
||||
webrtc_dsp/modules/audio_processing/aecm/echo_control_mobile.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/downsampled_render_buffer.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/subtractor_output_analyzer.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/residual_echo_estimator.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/shadow_filter_update_gain.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/aec_state.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/suppression_filter.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/block_delay_buffer.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/adaptive_fir_filter.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/cascaded_biquad_filter.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/matched_filter.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/subtractor_output.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/render_signal_analyzer.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/aec3_fft.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/echo_remover_metrics.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/filter_analyzer.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/subtractor.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/echo_path_delay_estimator.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/block_processor_metrics.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/fft_data.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/render_delay_controller_metrics.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/comfort_noise_generator.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/erl_estimator.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/echo_remover.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/matrix_buffer.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/reverb_model_estimator.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/echo_path_variability.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/moving_average.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/render_reverb_model.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/render_delay_controller.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/suppression_gain.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/erle_estimator.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/subband_erle_estimator.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/block_processor.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/fullband_erle_estimator.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/stationarity_estimator.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/echo_canceller3.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/skew_estimator.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/render_buffer.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/reverb_model_fallback.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/vector_buffer.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/reverb_frequency_response.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/echo_audibility.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/fft_buffer.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/aec3_common.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/vector_math.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/decimator.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/frame_blocker.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/block_framer.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/suppression_gain_limiter.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/delay_estimate.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/reverb_model.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/main_filter_update_gain.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/matched_filter_lag_aggregator.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/reverb_decay_estimator.h \
|
||||
webrtc_dsp/modules/audio_processing/aec3/render_delay_buffer.h \
|
||||
webrtc_dsp/modules/audio_processing/gain_control_impl.h \
|
||||
webrtc_dsp/modules/audio_processing/typing_detection.h \
|
||||
webrtc_dsp/modules/audio_processing/logging/apm_data_dumper.h \
|
||||
webrtc_dsp/modules/audio_processing/vad/vad_audio_proc_internal.h \
|
||||
webrtc_dsp/modules/audio_processing/vad/vad_circular_buffer.h \
|
||||
webrtc_dsp/modules/audio_processing/vad/pitch_based_vad.h \
|
||||
webrtc_dsp/modules/audio_processing/vad/pole_zero_filter.h \
|
||||
webrtc_dsp/modules/audio_processing/vad/gmm.h \
|
||||
webrtc_dsp/modules/audio_processing/vad/common.h \
|
||||
webrtc_dsp/modules/audio_processing/vad/vad_audio_proc.h \
|
||||
webrtc_dsp/modules/audio_processing/vad/voice_gmm_tables.h \
|
||||
webrtc_dsp/modules/audio_processing/vad/noise_gmm_tables.h \
|
||||
webrtc_dsp/modules/audio_processing/vad/pitch_internal.h \
|
||||
webrtc_dsp/modules/audio_processing/vad/standalone_vad.h \
|
||||
webrtc_dsp/modules/audio_processing/vad/voice_activity_detector.h \
|
||||
webrtc_dsp/modules/audio_processing/utility/ooura_fft_tables_neon_sse2.h \
|
||||
webrtc_dsp/modules/audio_processing/utility/delay_estimator_internal.h \
|
||||
webrtc_dsp/modules/audio_processing/utility/ooura_fft.h \
|
||||
webrtc_dsp/modules/audio_processing/utility/block_mean_calculator.h \
|
||||
webrtc_dsp/modules/audio_processing/utility/delay_estimator.h \
|
||||
webrtc_dsp/modules/audio_processing/utility/ooura_fft_tables_common.h \
|
||||
webrtc_dsp/modules/audio_processing/utility/delay_estimator_wrapper.h \
|
||||
webrtc_dsp/common_audio/mocks/mock_smoothing_filter.h \
|
||||
webrtc_dsp/common_audio/wav_file.h \
|
||||
webrtc_dsp/common_audio/sparse_fir_filter.h \
|
||||
webrtc_dsp/common_audio/fir_filter_sse.h \
|
||||
webrtc_dsp/common_audio/window_generator.h \
|
||||
webrtc_dsp/common_audio/ring_buffer.h \
|
||||
webrtc_dsp/common_audio/fir_filter.h \
|
||||
webrtc_dsp/common_audio/include/audio_util.h \
|
||||
webrtc_dsp/common_audio/real_fourier_ooura.h \
|
||||
webrtc_dsp/common_audio/smoothing_filter.h \
|
||||
webrtc_dsp/common_audio/resampler/sinc_resampler.h \
|
||||
webrtc_dsp/common_audio/resampler/include/push_resampler.h \
|
||||
webrtc_dsp/common_audio/resampler/include/resampler.h \
|
||||
webrtc_dsp/common_audio/resampler/push_sinc_resampler.h \
|
||||
webrtc_dsp/common_audio/resampler/sinusoidal_linear_chirp_source.h \
|
||||
webrtc_dsp/common_audio/fir_filter_factory.h \
|
||||
webrtc_dsp/common_audio/audio_converter.h \
|
||||
webrtc_dsp/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.h \
|
||||
webrtc_dsp/common_audio/third_party/fft4g/fft4g.h \
|
||||
webrtc_dsp/common_audio/channel_buffer.h \
|
||||
webrtc_dsp/common_audio/real_fourier.h \
|
||||
webrtc_dsp/common_audio/fir_filter_neon.h \
|
||||
webrtc_dsp/common_audio/fir_filter_c.h \
|
||||
webrtc_dsp/common_audio/signal_processing/complex_fft_tables.h \
|
||||
webrtc_dsp/common_audio/signal_processing/include/signal_processing_library.h \
|
||||
webrtc_dsp/common_audio/signal_processing/include/real_fft.h \
|
||||
webrtc_dsp/common_audio/signal_processing/include/spl_inl.h \
|
||||
webrtc_dsp/common_audio/signal_processing/include/spl_inl_armv7.h \
|
||||
webrtc_dsp/common_audio/signal_processing/dot_product_with_scale.h \
|
||||
webrtc_dsp/common_audio/signal_processing/resample_by_2_internal.h \
|
||||
webrtc_dsp/common_audio/wav_header.h \
|
||||
webrtc_dsp/common_audio/vad/vad_core.h \
|
||||
webrtc_dsp/common_audio/vad/include/vad.h \
|
||||
webrtc_dsp/common_audio/vad/include/webrtc_vad.h \
|
||||
webrtc_dsp/common_audio/vad/vad_gmm.h \
|
||||
webrtc_dsp/common_audio/vad/vad_sp.h \
|
||||
webrtc_dsp/common_audio/vad/vad_filterbank.h
|
||||
|
||||
else
|
||||
CFLAGS += -DTGVOIP_NO_DSP
|
||||
endif
|
||||
|
||||
libtgvoip_la_LDFLAGS = -version-number @LIBTGVOIP_MAJOR_VERSION@:@LIBTGVOIP_MINOR_VERSION@:@LIBTGVOIP_PATCH_VERSION@
|
||||
libtgvoip_la_SOURCES = $(SRC) $(TGVOIP_HDRS)
|
||||
tgvoipincludedir = $(includedir)/tgvoip
|
||||
nobase_tgvoipinclude_HEADERS = $(TGVOIP_HDRS)
|
||||
|
||||
pkgconfig_DATA = tgvoip.pc
|
||||
|
||||
CXXFLAGS += -std=gnu++0x $(CFLAGS)
|
||||
if TARGET_OS_OSX
|
||||
OBJCFLAGS = $(CFLAGS)
|
||||
OBJCXXFLAGS += -std=gnu++0x $(CFLAGS)
|
||||
endif
|
5242
TMessagesProj/jni/libtgvoip2/Makefile.in
Normal file
5242
TMessagesProj/jni/libtgvoip2/Makefile.in
Normal file
File diff suppressed because it is too large
Load diff
211
TMessagesProj/jni/libtgvoip2/MediaStreamItf.cpp
Normal file
211
TMessagesProj/jni/libtgvoip2/MediaStreamItf.cpp
Normal file
|
@ -0,0 +1,211 @@
|
|||
//
|
||||
// libtgvoip is free and unencumbered public domain software.
|
||||
// For more information, see http://unlicense.org or the UNLICENSE file
|
||||
// you should have received with this source code distribution.
|
||||
//
|
||||
|
||||
#include "logging.h"
|
||||
#include "MediaStreamItf.h"
|
||||
#include "EchoCanceller.h"
|
||||
#include <stdint.h>
|
||||
#include <algorithm>
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
|
||||
using namespace tgvoip;
|
||||
|
||||
void MediaStreamItf::SetCallback(size_t (*f)(unsigned char *, size_t, void*), void* param){
|
||||
std::lock_guard<std::mutex> lock(m_callback);
|
||||
callback=f;
|
||||
callbackParam=param;
|
||||
}
|
||||
|
||||
size_t MediaStreamItf::InvokeCallback(unsigned char *data, size_t length){
|
||||
std::lock_guard<std::mutex> lock(m_callback);
|
||||
if(callback)
|
||||
return (*callback)(data, length, callbackParam);
|
||||
return 0;
|
||||
}
|
||||
|
||||
AudioMixer::AudioMixer() : processedQueue(16), semaphore(16, 0){
|
||||
running=false;
|
||||
}
|
||||
|
||||
AudioMixer::~AudioMixer(){
|
||||
}
|
||||
|
||||
void AudioMixer::SetOutput(MediaStreamItf* output){
|
||||
output->SetCallback(OutputCallback, this);
|
||||
}
|
||||
|
||||
void AudioMixer::Start(){
|
||||
assert(!running);
|
||||
running=true;
|
||||
thread=new Thread(std::bind(&AudioMixer::RunThread, this));
|
||||
thread->SetName("AudioMixer");
|
||||
thread->Start();
|
||||
}
|
||||
|
||||
void AudioMixer::Stop(){
|
||||
if(!running){
|
||||
LOGE("Tried to stop AudioMixer that wasn't started");
|
||||
return;
|
||||
}
|
||||
running=false;
|
||||
semaphore.Release();
|
||||
thread->Join();
|
||||
delete thread;
|
||||
thread=NULL;
|
||||
}
|
||||
|
||||
void AudioMixer::DoCallback(unsigned char *data, size_t length){
|
||||
//memset(data, 0, 960*2);
|
||||
//LOGD("audio mixer callback, %d inputs", inputs.size());
|
||||
if(processedQueue.Size()==0)
|
||||
semaphore.Release(2);
|
||||
else
|
||||
semaphore.Release();
|
||||
Buffer buf=processedQueue.GetBlocking();
|
||||
memcpy(data, *buf, 960*2);
|
||||
}
|
||||
|
||||
size_t AudioMixer::OutputCallback(unsigned char *data, size_t length, void *arg){
|
||||
((AudioMixer*)arg)->DoCallback(data, length);
|
||||
return 960*2;
|
||||
}
|
||||
|
||||
void AudioMixer::AddInput(std::shared_ptr<MediaStreamItf> input){
|
||||
MutexGuard m(inputsMutex);
|
||||
MixerInput in;
|
||||
in.multiplier=1;
|
||||
in.source=input;
|
||||
inputs.push_back(in);
|
||||
}
|
||||
|
||||
void AudioMixer::RemoveInput(std::shared_ptr<MediaStreamItf> input){
|
||||
MutexGuard m(inputsMutex);
|
||||
for(std::vector<MixerInput>::iterator i=inputs.begin();i!=inputs.end();++i){
|
||||
if(i->source==input){
|
||||
inputs.erase(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioMixer::SetInputVolume(std::shared_ptr<MediaStreamItf> input, float volumeDB){
|
||||
MutexGuard m(inputsMutex);
|
||||
for(std::vector<MixerInput>::iterator i=inputs.begin();i!=inputs.end();++i){
|
||||
if(i->source==input){
|
||||
if(volumeDB==-INFINITY)
|
||||
i->multiplier=0;
|
||||
else
|
||||
i->multiplier=expf(volumeDB/20.0f * logf(10.0f));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioMixer::RunThread(){
|
||||
LOGV("AudioMixer thread started");
|
||||
while(running){
|
||||
semaphore.Acquire();
|
||||
if(!running)
|
||||
break;
|
||||
|
||||
try{
|
||||
Buffer data=bufferPool.Get();
|
||||
//LOGV("Audio mixer processing a frame");
|
||||
MutexGuard m(inputsMutex);
|
||||
int16_t *buf=reinterpret_cast<int16_t *>(*data);
|
||||
int16_t input[960];
|
||||
float out[960];
|
||||
memset(out, 0, 960*4);
|
||||
int usedInputs=0;
|
||||
for(std::vector<MixerInput>::iterator in=inputs.begin(); in!=inputs.end(); ++in){
|
||||
size_t res=in->source->InvokeCallback(reinterpret_cast<unsigned char *>(input), 960*2);
|
||||
if(!res || in->multiplier==0){
|
||||
//LOGV("AudioMixer: skipping silent packet");
|
||||
continue;
|
||||
}
|
||||
usedInputs++;
|
||||
float k=in->multiplier;
|
||||
if(k!=1){
|
||||
for(size_t i=0; i<960; i++){
|
||||
out[i]+=(float) input[i]*k;
|
||||
}
|
||||
}else{
|
||||
for(size_t i=0; i<960; i++){
|
||||
out[i]+=(float) input[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
if(usedInputs>0){
|
||||
for(size_t i=0; i<960; i++){
|
||||
if(out[i]>32767.0f)
|
||||
buf[i]=INT16_MAX;
|
||||
else if(out[i]<-32768.0f)
|
||||
buf[i]=INT16_MIN;
|
||||
else
|
||||
buf[i]=(int16_t) out[i];
|
||||
}
|
||||
}else{
|
||||
memset(*data, 0, 960*2);
|
||||
}
|
||||
if(echoCanceller)
|
||||
echoCanceller->SpeakerOutCallback(*data, 960*2);
|
||||
processedQueue.Put(std::move(data));
|
||||
}catch(std::bad_alloc& x){
|
||||
LOGE("AudioMixer: no buffers left");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
LOGI("======== audio mixer thread exiting =========");
|
||||
}
|
||||
|
||||
void AudioMixer::SetEchoCanceller(EchoCanceller *aec){
|
||||
echoCanceller=aec;
|
||||
}
|
||||
|
||||
AudioLevelMeter::AudioLevelMeter(){
|
||||
absMax=0;
|
||||
count=0;
|
||||
currentLevel=0;
|
||||
currentLevelFullRange=0;
|
||||
}
|
||||
|
||||
float AudioLevelMeter::GetLevel(){
|
||||
return currentLevel/9.0f;
|
||||
}
|
||||
|
||||
void AudioLevelMeter::Update(int16_t *samples, size_t count){
|
||||
// Number of bars on the indicator.
|
||||
// Note that the number of elements is specified because we are indexing it
|
||||
// in the range of 0-32
|
||||
const int8_t permutation[33]={0,1,2,3,4,4,5,5,5,5,6,6,6,6,6,7,7,7,7,8,8,8,9,9,9,9,9,9,9,9,9,9,9};
|
||||
int16_t absValue=0;
|
||||
for(unsigned int k=0;k<count;k++){
|
||||
int16_t absolute=(int16_t)abs(samples[k]);
|
||||
if (absolute>absValue)
|
||||
absValue=absolute;
|
||||
}
|
||||
|
||||
if(absValue>absMax)
|
||||
absMax = absValue;
|
||||
// Update level approximately 10 times per second
|
||||
if (this->count++==10){
|
||||
currentLevelFullRange=absMax;
|
||||
this->count=0;
|
||||
// Highest value for a int16_t is 0x7fff = 32767
|
||||
// Divide with 1000 to get in the range of 0-32 which is the range of
|
||||
// the permutation vector
|
||||
int32_t position=absMax/1000;
|
||||
// Make it less likely that the bar stays at position 0. I.e. only if
|
||||
// its in the range 0-250 (instead of 0-1000)
|
||||
/*if ((position==0) && (absMax>250)){
|
||||
position=1;
|
||||
}*/
|
||||
currentLevel=permutation[position];
|
||||
// Decay the absolute maximum (divide by 4)
|
||||
absMax >>= 2;
|
||||
}
|
||||
}
|
91
TMessagesProj/jni/libtgvoip2/MediaStreamItf.h
Normal file
91
TMessagesProj/jni/libtgvoip2/MediaStreamItf.h
Normal file
|
@ -0,0 +1,91 @@
|
|||
//
|
||||
// libtgvoip is free and unencumbered public domain software.
|
||||
// For more information, see http://unlicense.org or the UNLICENSE file
|
||||
// you should have received with this source code distribution.
|
||||
//
|
||||
|
||||
#ifndef LIBTGVOIP_MEDIASTREAMINPUT_H
|
||||
#define LIBTGVOIP_MEDIASTREAMINPUT_H
|
||||
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <stdint.h>
|
||||
#include "threading.h"
|
||||
#include "BlockingQueue.h"
|
||||
#include "Buffers.h"
|
||||
|
||||
namespace tgvoip{
|
||||
|
||||
class EchoCanceller;
|
||||
|
||||
class MediaStreamItf {
|
||||
public:
|
||||
virtual void Start() = 0;
|
||||
virtual void Stop() = 0;
|
||||
void SetCallback(size_t (*f)(unsigned char*, size_t, void*), void* param);
|
||||
|
||||
//protected:
|
||||
size_t InvokeCallback(unsigned char* data, size_t length);
|
||||
|
||||
virtual ~MediaStreamItf() = default;
|
||||
private:
|
||||
size_t (*callback)(unsigned char*, size_t, void*) = NULL;
|
||||
std::mutex m_callback;
|
||||
void* callbackParam;
|
||||
};
|
||||
|
||||
class AudioMixer : public MediaStreamItf{
|
||||
public:
|
||||
AudioMixer();
|
||||
virtual ~AudioMixer();
|
||||
void SetOutput(MediaStreamItf* output);
|
||||
virtual void Start();
|
||||
virtual void Stop();
|
||||
void AddInput(std::shared_ptr<MediaStreamItf> input);
|
||||
void RemoveInput(std::shared_ptr<MediaStreamItf> input);
|
||||
void SetInputVolume(std::shared_ptr<MediaStreamItf> input, float volumeDB);
|
||||
void SetEchoCanceller(EchoCanceller* aec);
|
||||
private:
|
||||
void RunThread();
|
||||
struct MixerInput{
|
||||
std::shared_ptr<MediaStreamItf> source;
|
||||
float multiplier;
|
||||
};
|
||||
Mutex inputsMutex;
|
||||
void DoCallback(unsigned char* data, size_t length);
|
||||
static size_t OutputCallback(unsigned char* data, size_t length, void* arg);
|
||||
std::vector<MixerInput> inputs;
|
||||
Thread* thread;
|
||||
BufferPool<960*2, 16> bufferPool;
|
||||
BlockingQueue<Buffer> processedQueue;
|
||||
Semaphore semaphore;
|
||||
EchoCanceller* echoCanceller;
|
||||
bool running;
|
||||
};
|
||||
|
||||
class CallbackWrapper : public MediaStreamItf{
|
||||
public:
|
||||
CallbackWrapper(){};
|
||||
virtual ~CallbackWrapper(){};
|
||||
virtual void Start(){};
|
||||
virtual void Stop(){};
|
||||
|
||||
};
|
||||
|
||||
class AudioLevelMeter{
|
||||
public:
|
||||
AudioLevelMeter();
|
||||
float GetLevel();
|
||||
void Update(int16_t* samples, size_t count);
|
||||
private:
|
||||
int16_t absMax;
|
||||
int16_t count;
|
||||
int8_t currentLevel;
|
||||
int16_t currentLevelFullRange;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
#endif //LIBTGVOIP_MEDIASTREAMINPUT_H
|
182
TMessagesProj/jni/libtgvoip2/MessageThread.cpp
Normal file
182
TMessagesProj/jni/libtgvoip2/MessageThread.cpp
Normal file
|
@ -0,0 +1,182 @@
|
|||
//
|
||||
// Created by Grishka on 17.06.2018.
|
||||
//
|
||||
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include "MessageThread.h"
|
||||
#include "VoIPController.h"
|
||||
#include "logging.h"
|
||||
|
||||
using namespace tgvoip;
|
||||
|
||||
MessageThread::MessageThread() : Thread(std::bind(&MessageThread::Run, this)){
|
||||
running=true;
|
||||
SetName("MessageThread");
|
||||
|
||||
#ifdef _WIN32
|
||||
#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY!=WINAPI_FAMILY_PHONE_APP
|
||||
event=CreateEvent(NULL, false, false, NULL);
|
||||
#else
|
||||
event=CreateEventEx(NULL, NULL, 0, EVENT_ALL_ACCESS);
|
||||
#endif
|
||||
#else
|
||||
pthread_cond_init(&cond, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
MessageThread::~MessageThread(){
|
||||
Stop();
|
||||
#ifdef _WIN32
|
||||
CloseHandle(event);
|
||||
#else
|
||||
pthread_cond_destroy(&cond);
|
||||
#endif
|
||||
}
|
||||
|
||||
void MessageThread::Stop(){
|
||||
if(running){
|
||||
running=false;
|
||||
#ifdef _WIN32
|
||||
SetEvent(event);
|
||||
#else
|
||||
pthread_cond_signal(&cond);
|
||||
#endif
|
||||
Join();
|
||||
}
|
||||
}
|
||||
|
||||
void MessageThread::Run(){
|
||||
queueMutex.Lock();
|
||||
while(running){
|
||||
double currentTime=VoIPController::GetCurrentTime();
|
||||
double waitTimeout;
|
||||
{
|
||||
MutexGuard _m(queueAccessMutex);
|
||||
waitTimeout=queue.empty() ? DBL_MAX : (queue[0].deliverAt-currentTime);
|
||||
}
|
||||
//LOGW("MessageThread wait timeout %f", waitTimeout);
|
||||
if(waitTimeout>0.0){
|
||||
#ifdef _WIN32
|
||||
queueMutex.Unlock();
|
||||
DWORD actualWaitTimeout=waitTimeout==DBL_MAX ? INFINITE : ((DWORD)round(waitTimeout*1000.0));
|
||||
#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY!=WINAPI_FAMILY_PHONE_APP
|
||||
WaitForSingleObject(event, actualWaitTimeout);
|
||||
#else
|
||||
WaitForSingleObjectEx(event, actualWaitTimeout, false);
|
||||
#endif
|
||||
// we don't really care if a context switch happens here and anything gets added to the queue by another thread
|
||||
// since any new no-delay messages will get delivered on this iteration anyway
|
||||
queueMutex.Lock();
|
||||
#else
|
||||
if(waitTimeout!=DBL_MAX){
|
||||
struct timeval now;
|
||||
struct timespec timeout;
|
||||
gettimeofday(&now, NULL);
|
||||
waitTimeout+=now.tv_sec;
|
||||
waitTimeout+=(now.tv_usec/1000000.0);
|
||||
timeout.tv_sec=(time_t)(floor(waitTimeout));
|
||||
timeout.tv_nsec=(long)((waitTimeout-floor(waitTimeout))*1000000000.0);
|
||||
pthread_cond_timedwait(&cond, queueMutex.NativeHandle(), &timeout);
|
||||
}else{
|
||||
pthread_cond_wait(&cond, queueMutex.NativeHandle());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if(!running){
|
||||
queueMutex.Unlock();
|
||||
return;
|
||||
}
|
||||
currentTime=VoIPController::GetCurrentTime();
|
||||
std::vector<Message> msgsToDeliverNow;
|
||||
{
|
||||
MutexGuard _m(queueAccessMutex);
|
||||
for(std::vector<Message>::iterator m=queue.begin();m!=queue.end();){
|
||||
if(m->deliverAt==0.0 || currentTime>=m->deliverAt){
|
||||
msgsToDeliverNow.push_back(*m);
|
||||
m=queue.erase(m);
|
||||
continue;
|
||||
}
|
||||
++m;
|
||||
}
|
||||
}
|
||||
|
||||
for(Message& m:msgsToDeliverNow){
|
||||
//LOGI("MessageThread delivering %u", m.msg);
|
||||
cancelCurrent=false;
|
||||
if(m.deliverAt==0.0)
|
||||
m.deliverAt=VoIPController::GetCurrentTime();
|
||||
if(m.func!=nullptr){
|
||||
m.func();
|
||||
}
|
||||
if(!cancelCurrent && m.interval>0.0){
|
||||
m.deliverAt+=m.interval;
|
||||
InsertMessageInternal(m);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
queueMutex.Unlock();
|
||||
}
|
||||
|
||||
uint32_t MessageThread::Post(std::function<void()> func, double delay, double interval){
|
||||
assert(delay>=0);
|
||||
//LOGI("MessageThread post [function] delay %f", delay);
|
||||
double currentTime=VoIPController::GetCurrentTime();
|
||||
Message m{lastMessageID++, delay==0.0 ? 0.0 : (currentTime+delay), interval, func};
|
||||
InsertMessageInternal(m);
|
||||
if(!IsCurrent()){
|
||||
#ifdef _WIN32
|
||||
SetEvent(event);
|
||||
#else
|
||||
pthread_cond_signal(&cond);
|
||||
#endif
|
||||
}
|
||||
return m.id;
|
||||
}
|
||||
|
||||
void MessageThread::InsertMessageInternal(MessageThread::Message &m){
|
||||
MutexGuard _m(queueAccessMutex);
|
||||
if(queue.empty()){
|
||||
queue.push_back(m);
|
||||
}else{
|
||||
if(queue[0].deliverAt>m.deliverAt){
|
||||
queue.insert(queue.begin(), m);
|
||||
}else{
|
||||
std::vector<Message>::iterator insertAfter=queue.begin();
|
||||
for(; insertAfter!=queue.end(); ++insertAfter){
|
||||
std::vector<Message>::iterator next=std::next(insertAfter);
|
||||
if(next==queue.end() || (next->deliverAt>m.deliverAt && insertAfter->deliverAt<=m.deliverAt)){
|
||||
queue.insert(next, m);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MessageThread::Cancel(uint32_t id){
|
||||
MutexGuard _m(queueAccessMutex);
|
||||
|
||||
for(std::vector<Message>::iterator m=queue.begin();m!=queue.end();){
|
||||
if(m->id==id){
|
||||
m=queue.erase(m);
|
||||
}else{
|
||||
++m;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MessageThread::CancelSelf(){
|
||||
assert(IsCurrent());
|
||||
cancelCurrent=true;
|
||||
}
|
54
TMessagesProj/jni/libtgvoip2/MessageThread.h
Normal file
54
TMessagesProj/jni/libtgvoip2/MessageThread.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
//
|
||||
// Created by Grishka on 17.06.2018.
|
||||
//
|
||||
|
||||
#ifndef LIBTGVOIP_MESSAGETHREAD_H
|
||||
#define LIBTGVOIP_MESSAGETHREAD_H
|
||||
|
||||
#include "threading.h"
|
||||
#include "utils.h"
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <atomic>
|
||||
|
||||
namespace tgvoip{
|
||||
class MessageThread : public Thread{
|
||||
public:
|
||||
TGVOIP_DISALLOW_COPY_AND_ASSIGN(MessageThread);
|
||||
MessageThread();
|
||||
virtual ~MessageThread();
|
||||
uint32_t Post(std::function<void()> func, double delay=0, double interval=0);
|
||||
void Cancel(uint32_t id);
|
||||
void CancelSelf();
|
||||
void Stop();
|
||||
|
||||
enum{
|
||||
INVALID_ID=0
|
||||
};
|
||||
private:
|
||||
struct Message{
|
||||
uint32_t id;
|
||||
double deliverAt;
|
||||
double interval;
|
||||
std::function<void()> func;
|
||||
};
|
||||
|
||||
void Run();
|
||||
void InsertMessageInternal(Message& m);
|
||||
|
||||
std::atomic<bool> running;
|
||||
std::vector<Message> queue;
|
||||
Mutex queueMutex;
|
||||
Mutex queueAccessMutex;
|
||||
uint32_t lastMessageID=1;
|
||||
bool cancelCurrent=false;
|
||||
|
||||
#ifdef _WIN32
|
||||
HANDLE event;
|
||||
#else
|
||||
pthread_cond_t cond;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
#endif //LIBTGVOIP_MESSAGETHREAD_H
|
650
TMessagesProj/jni/libtgvoip2/NetworkSocket.cpp
Normal file
650
TMessagesProj/jni/libtgvoip2/NetworkSocket.cpp
Normal file
|
@ -0,0 +1,650 @@
|
|||
//
|
||||
// Created by Grishka on 29.03.17.
|
||||
//
|
||||
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#if defined(_WIN32)
|
||||
#include <winsock2.h>
|
||||
#include "os/windows/NetworkSocketWinsock.h"
|
||||
#else
|
||||
#include "os/posix/NetworkSocketPosix.h"
|
||||
#endif
|
||||
#include "logging.h"
|
||||
#include "VoIPServerConfig.h"
|
||||
#include "VoIPController.h"
|
||||
#include "Buffers.h"
|
||||
#include "NetworkSocket.h"
|
||||
|
||||
#define MIN_UDP_PORT 16384
|
||||
#define MAX_UDP_PORT 32768
|
||||
|
||||
using namespace tgvoip;
|
||||
|
||||
NetworkSocket::NetworkSocket(NetworkProtocol protocol) : protocol(protocol){
|
||||
ipv6Timeout=ServerConfig::GetSharedInstance()->GetDouble("nat64_fallback_timeout", 3);
|
||||
failed=false;
|
||||
}
|
||||
|
||||
NetworkSocket::~NetworkSocket(){
|
||||
|
||||
}
|
||||
|
||||
std::string NetworkSocket::GetLocalInterfaceInfo(NetworkAddress *inet4addr, NetworkAddress *inet6addr){
|
||||
std::string r="not implemented";
|
||||
return r;
|
||||
}
|
||||
|
||||
uint16_t NetworkSocket::GenerateLocalPort(){
|
||||
uint16_t rnd;
|
||||
VoIPController::crypto.rand_bytes(reinterpret_cast<uint8_t*>(&rnd), 2);
|
||||
return (uint16_t) ((rnd%(MAX_UDP_PORT-MIN_UDP_PORT))+MIN_UDP_PORT);
|
||||
}
|
||||
|
||||
void NetworkSocket::SetMaxPriority(){
|
||||
}
|
||||
|
||||
bool NetworkSocket::IsFailed(){
|
||||
return failed;
|
||||
}
|
||||
|
||||
NetworkSocket *NetworkSocket::Create(NetworkProtocol protocol){
|
||||
#ifndef _WIN32
|
||||
return new NetworkSocketPosix(protocol);
|
||||
#else
|
||||
return new NetworkSocketWinsock(protocol);
|
||||
#endif
|
||||
}
|
||||
|
||||
NetworkAddress NetworkSocket::ResolveDomainName(std::string name){
|
||||
#ifndef _WIN32
|
||||
return NetworkSocketPosix::ResolveDomainName(name);
|
||||
#else
|
||||
return NetworkSocketWinsock::ResolveDomainName(name);
|
||||
#endif
|
||||
}
|
||||
|
||||
void NetworkSocket::GenerateTCPO2States(unsigned char* buffer, TCPO2State* recvState, TCPO2State* sendState){
|
||||
memset(recvState, 0, sizeof(TCPO2State));
|
||||
memset(sendState, 0, sizeof(TCPO2State));
|
||||
unsigned char nonce[64];
|
||||
uint32_t *first = reinterpret_cast<uint32_t*>(nonce), *second = first + 1;
|
||||
uint32_t first1 = 0x44414548U, first2 = 0x54534f50U, first3 = 0x20544547U, first4 = 0x20544547U, first5 = 0xeeeeeeeeU;
|
||||
uint32_t second1 = 0;
|
||||
do {
|
||||
VoIPController::crypto.rand_bytes(nonce, sizeof(nonce));
|
||||
} while (*first == first1 || *first == first2 || *first == first3 || *first == first4 || *first == first5 || *second == second1 || *reinterpret_cast<unsigned char*>(nonce) == 0xef);
|
||||
|
||||
// prepare encryption key/iv
|
||||
memcpy(sendState->key, nonce + 8, 32);
|
||||
memcpy(sendState->iv, nonce + 8 + 32, 16);
|
||||
|
||||
// prepare decryption key/iv
|
||||
char reversed[48];
|
||||
memcpy(reversed, nonce + 8, sizeof(reversed));
|
||||
std::reverse(reversed, reversed + sizeof(reversed));
|
||||
memcpy(recvState->key, reversed, 32);
|
||||
memcpy(recvState->iv, reversed + 32, 16);
|
||||
|
||||
// write protocol identifier
|
||||
*reinterpret_cast<uint32_t*>(nonce + 56) = 0xefefefefU;
|
||||
memcpy(buffer, nonce, 56);
|
||||
EncryptForTCPO2(nonce, sizeof(nonce), sendState);
|
||||
memcpy(buffer+56, nonce+56, 8);
|
||||
}
|
||||
|
||||
void NetworkSocket::EncryptForTCPO2(unsigned char *buffer, size_t len, TCPO2State *state){
|
||||
VoIPController::crypto.aes_ctr_encrypt(buffer, len, state->key, state->iv, state->ecount, &state->num);
|
||||
}
|
||||
|
||||
size_t NetworkSocket::Receive(unsigned char *buffer, size_t len){
|
||||
NetworkPacket pkt=Receive(len);
|
||||
if(pkt.IsEmpty())
|
||||
return 0;
|
||||
size_t actualLen=std::min(len, pkt.data.Length());
|
||||
memcpy(buffer, *pkt.data, actualLen);
|
||||
return actualLen;
|
||||
}
|
||||
|
||||
bool NetworkAddress::operator==(const NetworkAddress &other) const{
|
||||
if(isIPv6!=other.isIPv6)
|
||||
return false;
|
||||
if(!isIPv6){
|
||||
return addr.ipv4==other.addr.ipv4;
|
||||
}
|
||||
return memcmp(addr.ipv6, other.addr.ipv6, 16)==0;
|
||||
}
|
||||
|
||||
bool NetworkAddress::operator!=(const NetworkAddress &other) const{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
std::string NetworkAddress::ToString() const{
|
||||
if(isIPv6){
|
||||
#ifndef _WIN32
|
||||
return NetworkSocketPosix::V6AddressToString(addr.ipv6);
|
||||
#else
|
||||
return NetworkSocketWinsock::V6AddressToString(addr.ipv6);
|
||||
#endif
|
||||
}else{
|
||||
#ifndef _WIN32
|
||||
return NetworkSocketPosix::V4AddressToString(addr.ipv4);
|
||||
#else
|
||||
return NetworkSocketWinsock::V4AddressToString(addr.ipv4);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
bool NetworkAddress::IsEmpty() const{
|
||||
if(isIPv6){
|
||||
const uint64_t* a=reinterpret_cast<const uint64_t*>(addr.ipv6);
|
||||
return a[0]==0LL && a[1]==0LL;
|
||||
}
|
||||
return addr.ipv4==0;
|
||||
}
|
||||
|
||||
bool NetworkAddress::PrefixMatches(const unsigned int prefix, const NetworkAddress &other) const{
|
||||
if(isIPv6!=other.isIPv6)
|
||||
return false;
|
||||
if(!isIPv6){
|
||||
uint32_t mask=0xFFFFFFFF << (32-prefix);
|
||||
return (addr.ipv4 & mask) == (other.addr.ipv4 & mask);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
NetworkAddress NetworkAddress::Empty(){
|
||||
NetworkAddress addr;
|
||||
addr.isIPv6=false;
|
||||
addr.addr.ipv4=0;
|
||||
return addr;
|
||||
}
|
||||
|
||||
NetworkAddress NetworkAddress::IPv4(std::string str){
|
||||
NetworkAddress addr;
|
||||
addr.isIPv6=false;
|
||||
#ifndef _WIN32
|
||||
addr.addr.ipv4=NetworkSocketPosix::StringToV4Address(str);
|
||||
#else
|
||||
addr.addr.ipv4=NetworkSocketWinsock::StringToV4Address(str);
|
||||
#endif
|
||||
return addr;
|
||||
}
|
||||
|
||||
NetworkAddress NetworkAddress::IPv4(uint32_t addr){
|
||||
NetworkAddress a;
|
||||
a.isIPv6=false;
|
||||
a.addr.ipv4=addr;
|
||||
return a;
|
||||
}
|
||||
|
||||
NetworkAddress NetworkAddress::IPv6(std::string str){
|
||||
NetworkAddress addr;
|
||||
addr.isIPv6=false;
|
||||
#ifndef _WIN32
|
||||
NetworkSocketPosix::StringToV6Address(str, addr.addr.ipv6);
|
||||
#else
|
||||
NetworkSocketWinsock::StringToV6Address(str, addr.addr.ipv6);
|
||||
#endif
|
||||
return addr;
|
||||
}
|
||||
|
||||
NetworkAddress NetworkAddress::IPv6(const uint8_t addr[16]){
|
||||
NetworkAddress a;
|
||||
a.isIPv6=true;
|
||||
memcpy(a.addr.ipv6, addr, 16);
|
||||
return a;
|
||||
}
|
||||
|
||||
bool NetworkSocket::Select(std::vector<NetworkSocket *> &readFds, std::vector<NetworkSocket*> &writeFds, std::vector<NetworkSocket *> &errorFds, SocketSelectCanceller *canceller){
|
||||
#ifndef _WIN32
|
||||
return NetworkSocketPosix::Select(readFds, writeFds, errorFds, canceller);
|
||||
#else
|
||||
return NetworkSocketWinsock::Select(readFds, writeFds, errorFds, canceller);
|
||||
#endif
|
||||
}
|
||||
|
||||
SocketSelectCanceller::~SocketSelectCanceller(){
|
||||
|
||||
}
|
||||
|
||||
SocketSelectCanceller *SocketSelectCanceller::Create(){
|
||||
#ifndef _WIN32
|
||||
return new SocketSelectCancellerPosix();
|
||||
#else
|
||||
return new SocketSelectCancellerWin32();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
NetworkSocketTCPObfuscated::NetworkSocketTCPObfuscated(NetworkSocket *wrapped) : NetworkSocketWrapper(NetworkProtocol::TCP){
|
||||
this->wrapped=wrapped;
|
||||
}
|
||||
|
||||
NetworkSocketTCPObfuscated::~NetworkSocketTCPObfuscated(){
|
||||
if(wrapped)
|
||||
delete wrapped;
|
||||
}
|
||||
|
||||
NetworkSocket *NetworkSocketTCPObfuscated::GetWrapped(){
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
void NetworkSocketTCPObfuscated::InitConnection(){
|
||||
Buffer buf(64);
|
||||
GenerateTCPO2States(*buf, &recvState, &sendState);
|
||||
wrapped->Send(NetworkPacket{
|
||||
std::move(buf),
|
||||
NetworkAddress::Empty(),
|
||||
0,
|
||||
NetworkProtocol::TCP
|
||||
});
|
||||
}
|
||||
|
||||
void NetworkSocketTCPObfuscated::Send(NetworkPacket packet){
|
||||
BufferOutputStream os(packet.data.Length()+4);
|
||||
size_t len=packet.data.Length()/4;
|
||||
if(len<0x7F){
|
||||
os.WriteByte((unsigned char)len);
|
||||
}else{
|
||||
os.WriteByte(0x7F);
|
||||
os.WriteByte((unsigned char)(len & 0xFF));
|
||||
os.WriteByte((unsigned char)((len >> 8) & 0xFF));
|
||||
os.WriteByte((unsigned char)((len >> 16) & 0xFF));
|
||||
}
|
||||
os.WriteBytes(packet.data);
|
||||
EncryptForTCPO2(os.GetBuffer(), os.GetLength(), &sendState);
|
||||
wrapped->Send(NetworkPacket{
|
||||
Buffer(std::move(os)),
|
||||
NetworkAddress::Empty(),
|
||||
0,
|
||||
NetworkProtocol::TCP
|
||||
});
|
||||
//LOGD("Sent %u bytes", os.GetLength());
|
||||
}
|
||||
|
||||
bool NetworkSocketTCPObfuscated::OnReadyToSend(){
|
||||
LOGV("TCPO socket ready to send");
|
||||
if(!initialized){
|
||||
LOGV("Initializing TCPO2 connection");
|
||||
initialized=true;
|
||||
InitConnection();
|
||||
readyToSend=true;
|
||||
return false;
|
||||
}
|
||||
return wrapped->OnReadyToSend();
|
||||
}
|
||||
|
||||
NetworkPacket NetworkSocketTCPObfuscated::Receive(size_t maxLen){
|
||||
unsigned char len1;
|
||||
size_t packetLen=0;
|
||||
size_t offset=0;
|
||||
size_t len;
|
||||
len=wrapped->Receive(&len1, 1);
|
||||
if(len<=0){
|
||||
return NetworkPacket::Empty();
|
||||
}
|
||||
EncryptForTCPO2(&len1, 1, &recvState);
|
||||
|
||||
if(len1<0x7F){
|
||||
packetLen=(size_t)len1*4;
|
||||
}else{
|
||||
unsigned char len2[3];
|
||||
len=wrapped->Receive(len2, 3);
|
||||
if(len<=0){
|
||||
return NetworkPacket::Empty();
|
||||
}
|
||||
EncryptForTCPO2(len2, 3, &recvState);
|
||||
packetLen=((size_t)len2[0] | ((size_t)len2[1] << 8) | ((size_t)len2[2] << 16))*4;
|
||||
}
|
||||
|
||||
if(packetLen>1500){
|
||||
LOGW("packet too big to fit into buffer (%u vs %u)", (unsigned int)packetLen, (unsigned int)1500);
|
||||
return NetworkPacket::Empty();
|
||||
}
|
||||
Buffer buf(packetLen);
|
||||
|
||||
while(offset<packetLen){
|
||||
len=wrapped->Receive(*buf, packetLen-offset);
|
||||
if(len<=0){
|
||||
return NetworkPacket::Empty();
|
||||
}
|
||||
offset+=len;
|
||||
}
|
||||
EncryptForTCPO2(*buf, packetLen, &recvState);
|
||||
return NetworkPacket{
|
||||
std::move(buf),
|
||||
wrapped->GetConnectedAddress(),
|
||||
wrapped->GetConnectedPort(),
|
||||
NetworkProtocol::TCP
|
||||
};
|
||||
}
|
||||
|
||||
void NetworkSocketTCPObfuscated::Open(){
|
||||
|
||||
}
|
||||
|
||||
void NetworkSocketTCPObfuscated::Close(){
|
||||
wrapped->Close();
|
||||
}
|
||||
|
||||
void NetworkSocketTCPObfuscated::Connect(const NetworkAddress address, uint16_t port){
|
||||
wrapped->Connect(address, port);
|
||||
}
|
||||
|
||||
bool NetworkSocketTCPObfuscated::IsFailed(){
|
||||
return wrapped->IsFailed();
|
||||
}
|
||||
|
||||
NetworkSocketSOCKS5Proxy::NetworkSocketSOCKS5Proxy(NetworkSocket *tcp, NetworkSocket *udp, std::string username, std::string password) : NetworkSocketWrapper(udp ? NetworkProtocol::UDP : NetworkProtocol::TCP){
|
||||
this->tcp=tcp;
|
||||
this->udp=udp;
|
||||
this->username=username;
|
||||
this->password=password;
|
||||
}
|
||||
|
||||
NetworkSocketSOCKS5Proxy::~NetworkSocketSOCKS5Proxy(){
|
||||
delete tcp;
|
||||
}
|
||||
|
||||
void NetworkSocketSOCKS5Proxy::Send(NetworkPacket packet){
|
||||
if(protocol==NetworkProtocol::TCP){
|
||||
tcp->Send(std::move(packet));
|
||||
}else if(protocol==NetworkProtocol::UDP){
|
||||
BufferOutputStream out(1500);
|
||||
out.WriteInt16(0); // RSV
|
||||
out.WriteByte(0); // FRAG
|
||||
if(!packet.address.isIPv6){
|
||||
out.WriteByte(1); // ATYP (IPv4)
|
||||
out.WriteInt32(packet.address.addr.ipv4);
|
||||
}else{
|
||||
out.WriteByte(4); // ATYP (IPv6)
|
||||
out.WriteBytes(packet.address.addr.ipv6, 16);
|
||||
}
|
||||
out.WriteInt16(htons(packet.port));
|
||||
out.WriteBytes(packet.data);
|
||||
udp->Send(NetworkPacket{
|
||||
Buffer(std::move(out)),
|
||||
connectedAddress,
|
||||
connectedPort,
|
||||
NetworkProtocol::UDP
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
NetworkPacket NetworkSocketSOCKS5Proxy::Receive(size_t maxLen){
|
||||
if(protocol==NetworkProtocol::TCP){
|
||||
NetworkPacket packet=tcp->Receive();
|
||||
packet.address=connectedAddress;
|
||||
packet.port=connectedPort;
|
||||
return packet;
|
||||
}else{
|
||||
NetworkPacket p=udp->Receive();
|
||||
if(!p.IsEmpty() && p.address==connectedAddress && p.port==connectedPort){
|
||||
BufferInputStream in(p.data);
|
||||
in.ReadInt16(); // RSV
|
||||
in.ReadByte(); // FRAG
|
||||
unsigned char atyp=in.ReadByte();
|
||||
NetworkAddress address=NetworkAddress::Empty();
|
||||
if(atyp==1){ // IPv4
|
||||
address=NetworkAddress::IPv4((uint32_t) in.ReadInt32());
|
||||
}else if(atyp==4){ // IPv6
|
||||
unsigned char addr[16];
|
||||
in.ReadBytes(addr, 16);
|
||||
address=NetworkAddress::IPv6(addr);
|
||||
}
|
||||
return NetworkPacket{
|
||||
Buffer::CopyOf(p.data, in.GetOffset(), in.Remaining()),
|
||||
address,
|
||||
htons(in.ReadInt16()),
|
||||
protocol
|
||||
};
|
||||
}
|
||||
}
|
||||
return NetworkPacket::Empty();
|
||||
}
|
||||
|
||||
void NetworkSocketSOCKS5Proxy::Open(){
|
||||
|
||||
}
|
||||
|
||||
void NetworkSocketSOCKS5Proxy::Close(){
|
||||
tcp->Close();
|
||||
}
|
||||
|
||||
void NetworkSocketSOCKS5Proxy::Connect(const NetworkAddress address, uint16_t port){
|
||||
connectedAddress=address;
|
||||
connectedPort=port;
|
||||
}
|
||||
|
||||
NetworkSocket *NetworkSocketSOCKS5Proxy::GetWrapped(){
|
||||
return protocol==NetworkProtocol::TCP ? tcp : udp;
|
||||
}
|
||||
|
||||
void NetworkSocketSOCKS5Proxy::InitConnection(){
|
||||
}
|
||||
|
||||
bool NetworkSocketSOCKS5Proxy::IsFailed(){
|
||||
return NetworkSocket::IsFailed() || tcp->IsFailed();
|
||||
}
|
||||
|
||||
NetworkAddress NetworkSocketSOCKS5Proxy::GetConnectedAddress(){
|
||||
return connectedAddress;
|
||||
}
|
||||
|
||||
uint16_t NetworkSocketSOCKS5Proxy::GetConnectedPort(){
|
||||
return connectedPort;
|
||||
}
|
||||
|
||||
bool NetworkSocketSOCKS5Proxy::OnReadyToSend(){
|
||||
//LOGV("on ready to send, state=%d", state);
|
||||
if(state==ConnectionState::Initial){
|
||||
BufferOutputStream p(16);
|
||||
p.WriteByte(5); // VER
|
||||
if(!username.empty()){
|
||||
p.WriteByte(2); // NMETHODS
|
||||
p.WriteByte(0); // no auth
|
||||
p.WriteByte(2); // user/pass
|
||||
}else{
|
||||
p.WriteByte(1); // NMETHODS
|
||||
p.WriteByte(0); // no auth
|
||||
}
|
||||
tcp->Send(NetworkPacket{
|
||||
Buffer(std::move(p)),
|
||||
NetworkAddress::Empty(),
|
||||
0,
|
||||
NetworkProtocol::TCP
|
||||
});
|
||||
state=ConnectionState::WaitingForAuthMethod;
|
||||
return false;
|
||||
}
|
||||
return udp ? udp->OnReadyToSend() : tcp->OnReadyToSend();
|
||||
}
|
||||
|
||||
bool NetworkSocketSOCKS5Proxy::OnReadyToReceive(){
|
||||
//LOGV("on ready to receive state=%d", state);
|
||||
unsigned char buf[1024];
|
||||
if(state==ConnectionState::WaitingForAuthMethod){
|
||||
size_t l=tcp->Receive(buf, sizeof(buf));
|
||||
if(l<2 || tcp->IsFailed()){
|
||||
failed=true;
|
||||
return false;
|
||||
}
|
||||
BufferInputStream in(buf, l);
|
||||
unsigned char ver=in.ReadByte();
|
||||
unsigned char chosenMethod=in.ReadByte();
|
||||
LOGV("socks5: VER=%02X, METHOD=%02X", ver, chosenMethod);
|
||||
if(ver!=5){
|
||||
LOGW("socks5: incorrect VER in response");
|
||||
failed=true;
|
||||
return false;
|
||||
}
|
||||
if(chosenMethod==0){
|
||||
// connected, no further auth needed
|
||||
SendConnectionCommand();
|
||||
}else if(chosenMethod==2 && !username.empty()){
|
||||
BufferOutputStream p(512);
|
||||
p.WriteByte(1); // VER
|
||||
p.WriteByte((unsigned char)(username.length()>255 ? 255 : username.length())); // ULEN
|
||||
p.WriteBytes((unsigned char*)username.c_str(), username.length()>255 ? 255 : username.length()); // UNAME
|
||||
p.WriteByte((unsigned char)(password.length()>255 ? 255 : password.length())); // PLEN
|
||||
p.WriteBytes((unsigned char*)password.c_str(), password.length()>255 ? 255 : password.length()); // PASSWD
|
||||
tcp->Send(NetworkPacket{
|
||||
Buffer(std::move(p)),
|
||||
NetworkAddress::Empty(),
|
||||
0,
|
||||
NetworkProtocol::TCP
|
||||
});
|
||||
state=ConnectionState::WaitingForAuthResult;
|
||||
}else{
|
||||
LOGW("socks5: unsupported auth method");
|
||||
failed=true;
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}else if(state==ConnectionState::WaitingForAuthResult){
|
||||
size_t l=tcp->Receive(buf, sizeof(buf));
|
||||
if(l<2 || tcp->IsFailed()){
|
||||
failed=true;
|
||||
return false;
|
||||
}
|
||||
BufferInputStream in(buf, l);
|
||||
uint8_t ver=in.ReadByte();
|
||||
unsigned char status=in.ReadByte();
|
||||
LOGV("socks5: auth response VER=%02X, STATUS=%02X", ver, status);
|
||||
if(ver!=1){
|
||||
LOGW("socks5: auth response VER is incorrect");
|
||||
failed=true;
|
||||
return false;
|
||||
}
|
||||
if(status!=0){
|
||||
LOGW("socks5: username/password auth failed");
|
||||
failed=true;
|
||||
return false;
|
||||
}
|
||||
LOGV("socks5: authentication succeeded");
|
||||
SendConnectionCommand();
|
||||
return false;
|
||||
}else if(state==ConnectionState::WaitingForCommandResult){
|
||||
size_t l=tcp->Receive(buf, sizeof(buf));
|
||||
if(protocol==NetworkProtocol::TCP){
|
||||
if(l<2 || tcp->IsFailed()){
|
||||
LOGW("socks5: connect failed")
|
||||
failed=true;
|
||||
return false;
|
||||
}
|
||||
BufferInputStream in(buf, l);
|
||||
unsigned char ver=in.ReadByte();
|
||||
if(ver!=5){
|
||||
LOGW("socks5: connect: wrong ver in response");
|
||||
failed=true;
|
||||
return false;
|
||||
}
|
||||
unsigned char rep=in.ReadByte();
|
||||
if(rep!=0){
|
||||
LOGW("socks5: connect: failed with error %02X", rep);
|
||||
failed=true;
|
||||
return false;
|
||||
}
|
||||
LOGV("socks5: connect succeeded");
|
||||
state=ConnectionState::Connected;
|
||||
tcp=new NetworkSocketTCPObfuscated(tcp);
|
||||
readyToSend=true;
|
||||
return tcp->OnReadyToSend();
|
||||
}else if(protocol==NetworkProtocol::UDP){
|
||||
if(l<2 || tcp->IsFailed()){
|
||||
LOGW("socks5: udp associate failed");
|
||||
failed=true;
|
||||
return false;
|
||||
}
|
||||
try{
|
||||
BufferInputStream in(buf, l);
|
||||
unsigned char ver=in.ReadByte();
|
||||
unsigned char rep=in.ReadByte();
|
||||
if(ver!=5){
|
||||
LOGW("socks5: udp associate: wrong ver in response");
|
||||
failed=true;
|
||||
return false;
|
||||
}
|
||||
if(rep!=0){
|
||||
LOGW("socks5: udp associate failed with error %02X", rep);
|
||||
failed=true;
|
||||
return false;
|
||||
}
|
||||
in.ReadByte(); // RSV
|
||||
unsigned char atyp=in.ReadByte();
|
||||
if(atyp==1){
|
||||
uint32_t addr=(uint32_t) in.ReadInt32();
|
||||
connectedAddress=NetworkAddress::IPv4(addr);
|
||||
}else if(atyp==3){
|
||||
unsigned char len=in.ReadByte();
|
||||
char domain[256];
|
||||
memset(domain, 0, sizeof(domain));
|
||||
in.ReadBytes((unsigned char*)domain, len);
|
||||
LOGD("address type is domain, address=%s", domain);
|
||||
connectedAddress=ResolveDomainName(std::string(domain));
|
||||
if(connectedAddress.IsEmpty()){
|
||||
LOGW("socks5: failed to resolve domain name '%s'", domain);
|
||||
failed=true;
|
||||
return false;
|
||||
}
|
||||
}else if(atyp==4){
|
||||
unsigned char addr[16];
|
||||
in.ReadBytes(addr, 16);
|
||||
connectedAddress=NetworkAddress::IPv6(addr);
|
||||
}else{
|
||||
LOGW("socks5: unknown address type %d", atyp);
|
||||
failed=true;
|
||||
return false;
|
||||
}
|
||||
connectedPort=(uint16_t)ntohs(in.ReadInt16());
|
||||
state=ConnectionState::Connected;
|
||||
readyToSend=true;
|
||||
LOGV("socks5: udp associate successful, given endpoint %s:%d", connectedAddress.ToString().c_str(), connectedPort);
|
||||
}catch(std::out_of_range& x){
|
||||
LOGW("socks5: udp associate response parse failed");
|
||||
failed=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return udp ? udp->OnReadyToReceive() : tcp->OnReadyToReceive();
|
||||
}
|
||||
|
||||
void NetworkSocketSOCKS5Proxy::SendConnectionCommand(){
|
||||
BufferOutputStream out(1024);
|
||||
if(protocol==NetworkProtocol::TCP){
|
||||
out.WriteByte(5); // VER
|
||||
out.WriteByte(1); // CMD (CONNECT)
|
||||
out.WriteByte(0); // RSV
|
||||
if(!connectedAddress.isIPv6){
|
||||
out.WriteByte(1); // ATYP (IPv4)
|
||||
out.WriteInt32(connectedAddress.addr.ipv4);
|
||||
}else{
|
||||
out.WriteByte(4); // ATYP (IPv6)
|
||||
out.WriteBytes((unsigned char*)connectedAddress.addr.ipv6, 16);
|
||||
}
|
||||
out.WriteInt16(htons(connectedPort)); // DST.PORT
|
||||
}else if(protocol==NetworkProtocol::UDP){
|
||||
LOGV("Sending udp associate");
|
||||
out.WriteByte(5); // VER
|
||||
out.WriteByte(3); // CMD (UDP ASSOCIATE)
|
||||
out.WriteByte(0); // RSV
|
||||
out.WriteByte(1); // ATYP (IPv4)
|
||||
out.WriteInt32(0); // DST.ADDR
|
||||
out.WriteInt16(0); // DST.PORT
|
||||
}
|
||||
tcp->Send(NetworkPacket{
|
||||
Buffer(std::move(out)),
|
||||
NetworkAddress::Empty(),
|
||||
0,
|
||||
NetworkProtocol::TCP
|
||||
});
|
||||
state=ConnectionState::WaitingForCommandResult;
|
||||
}
|
||||
|
||||
bool NetworkSocketSOCKS5Proxy::NeedSelectForSending(){
|
||||
return state==ConnectionState::Initial || state==ConnectionState::Connected;
|
||||
}
|
201
TMessagesProj/jni/libtgvoip2/NetworkSocket.h
Normal file
201
TMessagesProj/jni/libtgvoip2/NetworkSocket.h
Normal file
|
@ -0,0 +1,201 @@
|
|||
//
|
||||
// Created by Grishka on 29.03.17.
|
||||
//
|
||||
|
||||
#ifndef LIBTGVOIP_NETWORKSOCKET_H
|
||||
#define LIBTGVOIP_NETWORKSOCKET_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
#include "utils.h"
|
||||
#include "Buffers.h"
|
||||
|
||||
namespace tgvoip {
|
||||
|
||||
enum class NetworkProtocol{
|
||||
UDP=0,
|
||||
TCP
|
||||
};
|
||||
|
||||
struct TCPO2State{
|
||||
unsigned char key[32];
|
||||
unsigned char iv[16];
|
||||
unsigned char ecount[16];
|
||||
uint32_t num;
|
||||
};
|
||||
|
||||
class NetworkAddress{
|
||||
public:
|
||||
virtual std::string ToString() const;
|
||||
bool operator==(const NetworkAddress& other) const;
|
||||
bool operator!=(const NetworkAddress& other) const;
|
||||
virtual ~NetworkAddress()=default;
|
||||
virtual bool IsEmpty() const;
|
||||
virtual bool PrefixMatches(const unsigned int prefix, const NetworkAddress& other) const;
|
||||
|
||||
static NetworkAddress Empty();
|
||||
static NetworkAddress IPv4(std::string str);
|
||||
static NetworkAddress IPv4(uint32_t addr);
|
||||
static NetworkAddress IPv6(std::string str);
|
||||
static NetworkAddress IPv6(const uint8_t addr[16]);
|
||||
|
||||
bool isIPv6=false;
|
||||
union{
|
||||
uint32_t ipv4;
|
||||
uint8_t ipv6[16];
|
||||
} addr;
|
||||
|
||||
private:
|
||||
NetworkAddress(){};
|
||||
};
|
||||
|
||||
struct NetworkPacket{
|
||||
TGVOIP_MOVE_ONLY(NetworkPacket);
|
||||
Buffer data;
|
||||
NetworkAddress address;
|
||||
uint16_t port;
|
||||
NetworkProtocol protocol;
|
||||
|
||||
static NetworkPacket Empty(){
|
||||
return NetworkPacket{Buffer(), NetworkAddress::Empty(), 0, NetworkProtocol::UDP};
|
||||
}
|
||||
|
||||
bool IsEmpty(){
|
||||
return data.IsEmpty() || (protocol==NetworkProtocol::UDP && (port==0 || address.IsEmpty()));
|
||||
}
|
||||
};
|
||||
|
||||
class SocketSelectCanceller{
|
||||
public:
|
||||
virtual ~SocketSelectCanceller();
|
||||
virtual void CancelSelect()=0;
|
||||
static SocketSelectCanceller* Create();
|
||||
};
|
||||
|
||||
class NetworkSocket{
|
||||
public:
|
||||
friend class NetworkSocketPosix;
|
||||
friend class NetworkSocketWinsock;
|
||||
|
||||
TGVOIP_DISALLOW_COPY_AND_ASSIGN(NetworkSocket);
|
||||
NetworkSocket(NetworkProtocol protocol);
|
||||
virtual ~NetworkSocket();
|
||||
virtual void Send(NetworkPacket packet)=0;
|
||||
virtual NetworkPacket Receive(size_t maxLen=0)=0;
|
||||
size_t Receive(unsigned char* buffer, size_t len);
|
||||
virtual void Open()=0;
|
||||
virtual void Close()=0;
|
||||
virtual uint16_t GetLocalPort(){ return 0; };
|
||||
virtual void Connect(const NetworkAddress address, uint16_t port)=0;
|
||||
virtual std::string GetLocalInterfaceInfo(NetworkAddress* inet4addr, NetworkAddress* inet6addr);
|
||||
virtual void OnActiveInterfaceChanged(){};
|
||||
virtual NetworkAddress GetConnectedAddress(){ return NetworkAddress::Empty(); };
|
||||
virtual uint16_t GetConnectedPort(){ return 0; };
|
||||
virtual void SetTimeouts(int sendTimeout, int recvTimeout){};
|
||||
|
||||
virtual bool IsFailed();
|
||||
virtual bool IsReadyToSend(){
|
||||
return readyToSend;
|
||||
}
|
||||
virtual bool OnReadyToSend(){ readyToSend=true; return true; };
|
||||
virtual bool OnReadyToReceive(){ return true; };
|
||||
void SetTimeout(double timeout){
|
||||
this->timeout=timeout;
|
||||
};
|
||||
|
||||
static NetworkSocket* Create(NetworkProtocol protocol);
|
||||
static NetworkAddress ResolveDomainName(std::string name);
|
||||
static bool Select(std::vector<NetworkSocket*>& readFds, std::vector<NetworkSocket*>& writeFds, std::vector<NetworkSocket*>& errorFds, SocketSelectCanceller* canceller);
|
||||
|
||||
protected:
|
||||
virtual uint16_t GenerateLocalPort();
|
||||
virtual void SetMaxPriority();
|
||||
|
||||
static void GenerateTCPO2States(unsigned char* buffer, TCPO2State* recvState, TCPO2State* sendState);
|
||||
static void EncryptForTCPO2(unsigned char* buffer, size_t len, TCPO2State* state);
|
||||
double ipv6Timeout;
|
||||
unsigned char nat64Prefix[12];
|
||||
std::atomic<bool> failed;
|
||||
bool readyToSend=false;
|
||||
double lastSuccessfulOperationTime=0.0;
|
||||
double timeout=0.0;
|
||||
NetworkProtocol protocol;
|
||||
};
|
||||
|
||||
class NetworkSocketWrapper : public NetworkSocket{
|
||||
public:
|
||||
NetworkSocketWrapper(NetworkProtocol protocol) : NetworkSocket(protocol){};
|
||||
virtual ~NetworkSocketWrapper(){};
|
||||
virtual NetworkSocket* GetWrapped()=0;
|
||||
virtual void InitConnection()=0;
|
||||
virtual void SetNonBlocking(bool){};
|
||||
};
|
||||
|
||||
class NetworkSocketTCPObfuscated : public NetworkSocketWrapper{
|
||||
public:
|
||||
NetworkSocketTCPObfuscated(NetworkSocket* wrapped);
|
||||
virtual ~NetworkSocketTCPObfuscated();
|
||||
virtual NetworkSocket* GetWrapped();
|
||||
virtual void InitConnection();
|
||||
virtual void Send(NetworkPacket packet) override;
|
||||
virtual NetworkPacket Receive(size_t maxLen) override;
|
||||
virtual void Open();
|
||||
virtual void Close();
|
||||
virtual void Connect(const NetworkAddress address, uint16_t port);
|
||||
virtual bool OnReadyToSend();
|
||||
|
||||
virtual bool IsFailed();
|
||||
virtual bool IsReadyToSend(){
|
||||
return readyToSend && wrapped->IsReadyToSend();
|
||||
};
|
||||
|
||||
private:
|
||||
NetworkSocket* wrapped;
|
||||
TCPO2State recvState;
|
||||
TCPO2State sendState;
|
||||
bool initialized=false;
|
||||
};
|
||||
|
||||
class NetworkSocketSOCKS5Proxy : public NetworkSocketWrapper{
|
||||
public:
|
||||
NetworkSocketSOCKS5Proxy(NetworkSocket* tcp, NetworkSocket* udp, std::string username, std::string password);
|
||||
virtual ~NetworkSocketSOCKS5Proxy();
|
||||
virtual void Send(NetworkPacket packet) override;
|
||||
virtual NetworkPacket Receive(size_t maxLen) override;
|
||||
virtual void Open() override;
|
||||
virtual void Close();
|
||||
virtual void Connect(const NetworkAddress address, uint16_t port);
|
||||
virtual NetworkSocket *GetWrapped();
|
||||
virtual void InitConnection();
|
||||
virtual bool IsFailed();
|
||||
virtual NetworkAddress GetConnectedAddress();
|
||||
virtual uint16_t GetConnectedPort();
|
||||
virtual bool OnReadyToSend();
|
||||
virtual bool OnReadyToReceive();
|
||||
|
||||
bool NeedSelectForSending();
|
||||
|
||||
private:
|
||||
void SendConnectionCommand();
|
||||
enum ConnectionState{
|
||||
Initial,
|
||||
WaitingForAuthMethod,
|
||||
WaitingForAuthResult,
|
||||
WaitingForCommandResult,
|
||||
Connected
|
||||
};
|
||||
NetworkSocket* tcp;
|
||||
NetworkSocket* udp;
|
||||
std::string username;
|
||||
std::string password;
|
||||
NetworkAddress connectedAddress=NetworkAddress::Empty();
|
||||
uint16_t connectedPort;
|
||||
ConnectionState state=ConnectionState::Initial;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //LIBTGVOIP_NETWORKSOCKET_H
|
287
TMessagesProj/jni/libtgvoip2/OpusDecoder.cpp
Normal file
287
TMessagesProj/jni/libtgvoip2/OpusDecoder.cpp
Normal file
|
@ -0,0 +1,287 @@
|
|||
//
|
||||
// libtgvoip is free and unencumbered public domain software.
|
||||
// For more information, see http://unlicense.org or the UNLICENSE file
|
||||
// you should have received with this source code distribution.
|
||||
//
|
||||
|
||||
#include "OpusDecoder.h"
|
||||
#include "audio/Resampler.h"
|
||||
#include "logging.h"
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <algorithm>
|
||||
#if defined HAVE_CONFIG_H || defined TGVOIP_USE_INSTALLED_OPUS
|
||||
#include <opus/opus.h>
|
||||
#else
|
||||
#include "opus.h"
|
||||
#endif
|
||||
|
||||
#include "VoIPController.h"
|
||||
|
||||
#define PACKET_SIZE (960 * 2)
|
||||
|
||||
using namespace tgvoip;
|
||||
|
||||
tgvoip::OpusDecoder::OpusDecoder(const std::shared_ptr<MediaStreamItf>& dst, bool isAsync, bool needEC) {
|
||||
dst->SetCallback(OpusDecoder::Callback, this);
|
||||
Initialize(isAsync, needEC);
|
||||
}
|
||||
|
||||
tgvoip::OpusDecoder::OpusDecoder(const std::unique_ptr<MediaStreamItf>& dst, bool isAsync, bool needEC) {
|
||||
dst->SetCallback(OpusDecoder::Callback, this);
|
||||
Initialize(isAsync, needEC);
|
||||
}
|
||||
|
||||
tgvoip::OpusDecoder::OpusDecoder(MediaStreamItf* dst, bool isAsync, bool needEC) {
|
||||
dst->SetCallback(OpusDecoder::Callback, this);
|
||||
Initialize(isAsync, needEC);
|
||||
}
|
||||
|
||||
void tgvoip::OpusDecoder::Initialize(bool isAsync, bool needEC) {
|
||||
async = isAsync;
|
||||
if (async) {
|
||||
decodedQueue = new BlockingQueue<Buffer>(33);
|
||||
semaphore = new Semaphore(32, 0);
|
||||
} else {
|
||||
decodedQueue = NULL;
|
||||
semaphore = NULL;
|
||||
}
|
||||
dec=opus_decoder_create(48000, 1, NULL);
|
||||
if (needEC)
|
||||
ecDec = opus_decoder_create(48000, 1, NULL);
|
||||
else
|
||||
ecDec = NULL;
|
||||
// todo buffer = reinterpret_cast<unsigned char*>(aligned_alloc(2, 8192));
|
||||
buffer=(unsigned char *) malloc(8192);
|
||||
lastDecoded = NULL;
|
||||
outputBufferSize = 0;
|
||||
echoCanceller = NULL;
|
||||
frameDuration = 20;
|
||||
consecutiveLostPackets = 0;
|
||||
enableDTX = false;
|
||||
silentPacketCount = 0;
|
||||
levelMeter = NULL;
|
||||
nextLen = 0;
|
||||
running = false;
|
||||
remainingDataLen = 0;
|
||||
processedBuffer = NULL;
|
||||
prevWasEC = false;
|
||||
prevLastSample = 0;
|
||||
}
|
||||
|
||||
tgvoip::OpusDecoder::~OpusDecoder() {
|
||||
opus_decoder_destroy(dec);
|
||||
if (ecDec)
|
||||
opus_decoder_destroy(ecDec);
|
||||
free(buffer);
|
||||
if (decodedQueue)
|
||||
delete decodedQueue;
|
||||
if (semaphore)
|
||||
delete semaphore;
|
||||
}
|
||||
|
||||
|
||||
void tgvoip::OpusDecoder::SetEchoCanceller(EchoCanceller* canceller) {
|
||||
echoCanceller = canceller;
|
||||
}
|
||||
|
||||
size_t tgvoip::OpusDecoder::Callback(unsigned char* data, size_t len, void* param) {
|
||||
return (reinterpret_cast<OpusDecoder*>(param)->HandleCallback(data, len));
|
||||
}
|
||||
|
||||
size_t tgvoip::OpusDecoder::HandleCallback(unsigned char* data, size_t len) {
|
||||
if (async) {
|
||||
if (!running) {
|
||||
memset(data, 0, len);
|
||||
return 0;
|
||||
}
|
||||
if (outputBufferSize == 0) {
|
||||
outputBufferSize = len;
|
||||
int packetsNeeded;
|
||||
if (len > PACKET_SIZE)
|
||||
packetsNeeded = len / PACKET_SIZE;
|
||||
else
|
||||
packetsNeeded = 1;
|
||||
packetsNeeded *= 2;
|
||||
semaphore->Release(packetsNeeded);
|
||||
}
|
||||
assert(outputBufferSize == len && "output buffer size is supposed to be the same throughout callbacks");
|
||||
if (len == PACKET_SIZE) {
|
||||
Buffer lastDecoded=decodedQueue->GetBlocking();
|
||||
if (lastDecoded.IsEmpty())
|
||||
return 0;
|
||||
memcpy(data, *lastDecoded, PACKET_SIZE);
|
||||
semaphore->Release();
|
||||
if (silentPacketCount > 0) {
|
||||
silentPacketCount--;
|
||||
if (levelMeter)
|
||||
levelMeter->Update(reinterpret_cast<int16_t*>(data), 0);
|
||||
return 0;
|
||||
}
|
||||
if (echoCanceller) {
|
||||
echoCanceller->SpeakerOutCallback(data, PACKET_SIZE);
|
||||
}
|
||||
} else {
|
||||
LOGE("Opus decoder buffer length != 960 samples");
|
||||
abort();
|
||||
}
|
||||
} else {
|
||||
if (remainingDataLen == 0 && silentPacketCount == 0) {
|
||||
int duration = DecodeNextFrame();
|
||||
remainingDataLen = static_cast<size_t>(duration) / 20 * 960 * 2;
|
||||
}
|
||||
if (silentPacketCount > 0 || remainingDataLen == 0 || !processedBuffer){
|
||||
if (silentPacketCount > 0)
|
||||
silentPacketCount--;
|
||||
memset(data, 0, 960 * 2);
|
||||
if (levelMeter)
|
||||
levelMeter->Update(reinterpret_cast<int16_t*>(data), 0);
|
||||
return 0;
|
||||
}
|
||||
memcpy(data, processedBuffer, 960 * 2);
|
||||
remainingDataLen -= 960 * 2;
|
||||
if (remainingDataLen > 0) {
|
||||
memmove(processedBuffer, processedBuffer + 960 * 2, remainingDataLen);
|
||||
}
|
||||
}
|
||||
if (levelMeter)
|
||||
levelMeter->Update(reinterpret_cast<int16_t*>(data), len / 2);
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
void tgvoip::OpusDecoder::Start() {
|
||||
if (!async)
|
||||
return;
|
||||
running = true;
|
||||
thread = new Thread(std::bind(&tgvoip::OpusDecoder::RunThread, this));
|
||||
thread->SetName("opus_decoder");
|
||||
thread->SetMaxPriority();
|
||||
thread->Start();
|
||||
}
|
||||
|
||||
void tgvoip::OpusDecoder::Stop() {
|
||||
if (!running || !async)
|
||||
return;
|
||||
running = false;
|
||||
semaphore->Release();
|
||||
thread->Join();
|
||||
delete thread;
|
||||
}
|
||||
|
||||
void tgvoip::OpusDecoder::RunThread() {
|
||||
LOGI("decoder: packets per frame %d", packetsPerFrame);
|
||||
while(running) {
|
||||
int playbackDuration = DecodeNextFrame();
|
||||
for (int i = 0; i < playbackDuration / 20; i++) {
|
||||
semaphore->Acquire();
|
||||
if (!running) {
|
||||
LOGI("==== decoder exiting ====");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Buffer buf=bufferPool.Get();
|
||||
if (remainingDataLen > 0) {
|
||||
for (effects::AudioEffect*& effect:postProcEffects) {
|
||||
effect->Process(reinterpret_cast<int16_t*>(processedBuffer+(PACKET_SIZE * i)), 960);
|
||||
}
|
||||
buf.CopyFrom(processedBuffer + (PACKET_SIZE * i), 0, PACKET_SIZE);
|
||||
} else {
|
||||
//LOGE("Error decoding, result=%d", size);
|
||||
memset(*buf, 0, PACKET_SIZE);
|
||||
}
|
||||
decodedQueue->Put(std::move(buf));
|
||||
} catch (const std::bad_alloc&) {
|
||||
LOGW("decoder: no buffers left!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int tgvoip::OpusDecoder::DecodeNextFrame() {
|
||||
int playbackDuration = 0;
|
||||
bool isEC = false;
|
||||
size_t len = jitterBuffer->HandleOutput(buffer, 8192, 0, true, playbackDuration, isEC);
|
||||
bool fec = false;
|
||||
if (!len) {
|
||||
fec = true;
|
||||
len = jitterBuffer->HandleOutput(buffer, 8192, 0, false, playbackDuration, isEC);
|
||||
//if(len)
|
||||
// LOGV("Trying FEC...");
|
||||
}
|
||||
int size;
|
||||
if (len) {
|
||||
size = opus_decode(isEC ? ecDec : dec, buffer, len, reinterpret_cast<opus_int16*>(decodeBuffer), packetsPerFrame * 960, fec ? 1 : 0);
|
||||
consecutiveLostPackets = 0;
|
||||
if (prevWasEC != isEC && size) {
|
||||
// It turns out the waveforms generated by the PLC feature are also great to help smooth out the
|
||||
// otherwise audible transition between the frames from different decoders. Those are basically an extrapolation
|
||||
// of the previous successfully decoded data -- which is exactly what we need here.
|
||||
size = opus_decode(prevWasEC ? ecDec : dec, NULL, 0, reinterpret_cast<opus_int16*>(nextBuffer), packetsPerFrame * 960, 0);
|
||||
if (size) {
|
||||
int16_t* plcSamples = reinterpret_cast<int16_t*>(nextBuffer);
|
||||
int16_t* samples = reinterpret_cast<int16_t*>(decodeBuffer);
|
||||
constexpr float coeffs[] = {0.999802f, 0.995062f, 0.984031f, 0.966778f, 0.943413f, 0.914084f, 0.878975f, 0.838309f, 0.792344f, 0.741368f,
|
||||
0.685706f, 0.625708f, 0.561754f, 0.494249f, 0.423619f, 0.350311f, 0.274788f, 0.197527f, 0.119018f, 0.039757f};
|
||||
for (int i = 0; i < 20; i++) {
|
||||
samples[i] = static_cast<int16_t>(round(plcSamples[i] * coeffs[i] + samples[i] * (1.f - coeffs[i])));
|
||||
}
|
||||
}
|
||||
}
|
||||
prevWasEC = isEC;
|
||||
prevLastSample = decodeBuffer[size - 1];
|
||||
} else { // do packet loss concealment
|
||||
consecutiveLostPackets++;
|
||||
if (consecutiveLostPackets > 2 && enableDTX) {
|
||||
silentPacketCount += packetsPerFrame;
|
||||
size = packetsPerFrame * 960;
|
||||
} else {
|
||||
size = opus_decode(prevWasEC ? ecDec : dec, NULL, 0, reinterpret_cast<opus_int16*>(decodeBuffer), packetsPerFrame * 960, 0);
|
||||
//LOGV("PLC");
|
||||
}
|
||||
}
|
||||
if (size < 0)
|
||||
LOGW("decoder: opus_decode error %d", size);
|
||||
remainingDataLen = size;
|
||||
if (playbackDuration == 80) {
|
||||
processedBuffer = buffer;
|
||||
audio::Resampler::Rescale60To80(reinterpret_cast<int16_t*>(decodeBuffer),
|
||||
reinterpret_cast<int16_t*>(processedBuffer));
|
||||
} else if (playbackDuration == 40) {
|
||||
processedBuffer = buffer;
|
||||
audio::Resampler::Rescale60To40(reinterpret_cast<int16_t*>(decodeBuffer),
|
||||
reinterpret_cast<int16_t*>(processedBuffer));
|
||||
} else {
|
||||
processedBuffer = decodeBuffer;
|
||||
}
|
||||
return playbackDuration;
|
||||
}
|
||||
|
||||
|
||||
void tgvoip::OpusDecoder::SetFrameDuration(uint32_t duration) {
|
||||
frameDuration = duration;
|
||||
packetsPerFrame = frameDuration / 20;
|
||||
}
|
||||
|
||||
|
||||
void tgvoip::OpusDecoder::SetJitterBuffer(std::shared_ptr<JitterBuffer> jitterBuffer) {
|
||||
this->jitterBuffer = jitterBuffer;
|
||||
}
|
||||
|
||||
void tgvoip::OpusDecoder::SetDTX(bool enable) {
|
||||
enableDTX = enable;
|
||||
}
|
||||
|
||||
void tgvoip::OpusDecoder::SetLevelMeter(AudioLevelMeter* levelMeter) {
|
||||
this->levelMeter = levelMeter;
|
||||
}
|
||||
|
||||
void tgvoip::OpusDecoder::AddAudioEffect(effects::AudioEffect* effect) {
|
||||
postProcEffects.push_back(effect);
|
||||
}
|
||||
|
||||
void tgvoip::OpusDecoder::RemoveAudioEffect(effects::AudioEffect *effect) {
|
||||
std::vector<effects::AudioEffect*>::iterator it = std::find(postProcEffects.begin(), postProcEffects.end(), effect);
|
||||
if (it != postProcEffects.end())
|
||||
postProcEffects.erase(it);
|
||||
}
|
81
TMessagesProj/jni/libtgvoip2/OpusDecoder.h
Normal file
81
TMessagesProj/jni/libtgvoip2/OpusDecoder.h
Normal file
|
@ -0,0 +1,81 @@
|
|||
//
|
||||
// libtgvoip is free and unencumbered public domain software.
|
||||
// For more information, see http://unlicense.org or the UNLICENSE file
|
||||
// you should have received with this source code distribution.
|
||||
//
|
||||
|
||||
#ifndef LIBTGVOIP_OPUSDECODER_H
|
||||
#define LIBTGVOIP_OPUSDECODER_H
|
||||
|
||||
|
||||
#include "MediaStreamItf.h"
|
||||
#include "threading.h"
|
||||
#include "BlockingQueue.h"
|
||||
#include "Buffers.h"
|
||||
#include "EchoCanceller.h"
|
||||
#include "JitterBuffer.h"
|
||||
#include "utils.h"
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
|
||||
struct OpusDecoder;
|
||||
|
||||
namespace tgvoip{
|
||||
class OpusDecoder {
|
||||
public:
|
||||
TGVOIP_DISALLOW_COPY_AND_ASSIGN(OpusDecoder);
|
||||
virtual void Start();
|
||||
|
||||
virtual void Stop();
|
||||
|
||||
OpusDecoder(const std::shared_ptr<MediaStreamItf>& dst, bool isAsync, bool needEC);
|
||||
OpusDecoder(const std::unique_ptr<MediaStreamItf>& dst, bool isAsync, bool needEC);
|
||||
OpusDecoder(MediaStreamItf* dst, bool isAsync, bool needEC);
|
||||
virtual ~OpusDecoder();
|
||||
size_t HandleCallback(unsigned char* data, size_t len);
|
||||
void SetEchoCanceller(EchoCanceller* canceller);
|
||||
void SetFrameDuration(uint32_t duration);
|
||||
void SetJitterBuffer(std::shared_ptr<JitterBuffer> jitterBuffer);
|
||||
void SetDTX(bool enable);
|
||||
void SetLevelMeter(AudioLevelMeter* levelMeter);
|
||||
void AddAudioEffect(effects::AudioEffect* effect);
|
||||
void RemoveAudioEffect(effects::AudioEffect* effect);
|
||||
|
||||
private:
|
||||
void Initialize(bool isAsync, bool needEC);
|
||||
static size_t Callback(unsigned char* data, size_t len, void* param);
|
||||
void RunThread();
|
||||
int DecodeNextFrame();
|
||||
::OpusDecoder* dec;
|
||||
::OpusDecoder* ecDec;
|
||||
BlockingQueue<Buffer>* decodedQueue;
|
||||
BufferPool<960*2, 32> bufferPool;
|
||||
unsigned char* buffer;
|
||||
unsigned char* lastDecoded;
|
||||
unsigned char* processedBuffer;
|
||||
size_t outputBufferSize;
|
||||
std::atomic<bool> running;
|
||||
Thread* thread;
|
||||
Semaphore* semaphore;
|
||||
uint32_t frameDuration;
|
||||
EchoCanceller* echoCanceller;
|
||||
std::shared_ptr<JitterBuffer> jitterBuffer;
|
||||
AudioLevelMeter* levelMeter;
|
||||
int consecutiveLostPackets;
|
||||
bool enableDTX;
|
||||
size_t silentPacketCount;
|
||||
std::vector<effects::AudioEffect*> postProcEffects;
|
||||
std::atomic<bool> async;
|
||||
alignas(2) unsigned char nextBuffer[8192];
|
||||
alignas(2) unsigned char decodeBuffer[8192];
|
||||
size_t nextLen;
|
||||
unsigned int packetsPerFrame;
|
||||
ptrdiff_t remainingDataLen;
|
||||
bool prevWasEC;
|
||||
int16_t prevLastSample;
|
||||
};
|
||||
}
|
||||
|
||||
#endif //LIBTGVOIP_OPUSDECODER_H
|
265
TMessagesProj/jni/libtgvoip2/OpusEncoder.cpp
Normal file
265
TMessagesProj/jni/libtgvoip2/OpusEncoder.cpp
Normal file
|
@ -0,0 +1,265 @@
|
|||
//
|
||||
// libtgvoip is free and unencumbered public domain software.
|
||||
// For more information, see http://unlicense.org or the UNLICENSE file
|
||||
// you should have received with this source code distribution.
|
||||
//
|
||||
|
||||
#include "OpusEncoder.h"
|
||||
#include <assert.h>
|
||||
#include <algorithm>
|
||||
#include "logging.h"
|
||||
#include "VoIPServerConfig.h"
|
||||
#if defined HAVE_CONFIG_H || defined TGVOIP_USE_INSTALLED_OPUS
|
||||
#include <opus/opus.h>
|
||||
#else
|
||||
#include "opus.h"
|
||||
#endif
|
||||
|
||||
namespace{
|
||||
int serverConfigValueToBandwidth(int config){
|
||||
switch(config){
|
||||
case 0:
|
||||
return OPUS_BANDWIDTH_NARROWBAND;
|
||||
case 1:
|
||||
return OPUS_BANDWIDTH_MEDIUMBAND;
|
||||
case 2:
|
||||
return OPUS_BANDWIDTH_WIDEBAND;
|
||||
case 3:
|
||||
return OPUS_BANDWIDTH_SUPERWIDEBAND;
|
||||
case 4:
|
||||
default:
|
||||
return OPUS_BANDWIDTH_FULLBAND;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tgvoip::OpusEncoder::OpusEncoder(MediaStreamItf *source, bool needSecondary):queue(10){
|
||||
this->source=source;
|
||||
source->SetCallback(tgvoip::OpusEncoder::Callback, this);
|
||||
enc=opus_encoder_create(48000, 1, OPUS_APPLICATION_VOIP, NULL);
|
||||
opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(10));
|
||||
opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(1));
|
||||
opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC(1));
|
||||
opus_encoder_ctl(enc, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE));
|
||||
opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_AUTO));
|
||||
requestedBitrate=20000;
|
||||
currentBitrate=0;
|
||||
running=false;
|
||||
echoCanceller=NULL;
|
||||
complexity=10;
|
||||
frameDuration=20;
|
||||
levelMeter=NULL;
|
||||
vadNoVoiceBitrate=static_cast<uint32_t>(ServerConfig::GetSharedInstance()->GetInt("audio_vad_no_voice_bitrate", 6000));
|
||||
vadModeVoiceBandwidth=serverConfigValueToBandwidth(ServerConfig::GetSharedInstance()->GetInt("audio_vad_bandwidth", 3));
|
||||
vadModeNoVoiceBandwidth=serverConfigValueToBandwidth(ServerConfig::GetSharedInstance()->GetInt("audio_vad_no_voice_bandwidth", 0));
|
||||
secondaryEnabledBandwidth=serverConfigValueToBandwidth(ServerConfig::GetSharedInstance()->GetInt("audio_extra_ec_bandwidth", 2));
|
||||
secondaryEncoderEnabled=false;
|
||||
|
||||
if(needSecondary){
|
||||
secondaryEncoder=opus_encoder_create(48000, 1, OPUS_APPLICATION_VOIP, NULL);
|
||||
opus_encoder_ctl(secondaryEncoder, OPUS_SET_COMPLEXITY(10));
|
||||
opus_encoder_ctl(secondaryEncoder, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE));
|
||||
opus_encoder_ctl(secondaryEncoder, OPUS_SET_BITRATE(8000));
|
||||
}else{
|
||||
secondaryEncoder=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
tgvoip::OpusEncoder::~OpusEncoder(){
|
||||
opus_encoder_destroy(enc);
|
||||
if(secondaryEncoder)
|
||||
opus_encoder_destroy(secondaryEncoder);
|
||||
}
|
||||
|
||||
void tgvoip::OpusEncoder::Start(){
|
||||
if(running)
|
||||
return;
|
||||
running=true;
|
||||
thread=new Thread(std::bind(&tgvoip::OpusEncoder::RunThread, this));
|
||||
thread->SetName("OpusEncoder");
|
||||
thread->SetMaxPriority();
|
||||
thread->Start();
|
||||
}
|
||||
|
||||
void tgvoip::OpusEncoder::Stop(){
|
||||
if(!running)
|
||||
return;
|
||||
running=false;
|
||||
queue.Put(Buffer());
|
||||
thread->Join();
|
||||
delete thread;
|
||||
}
|
||||
|
||||
|
||||
void tgvoip::OpusEncoder::SetBitrate(uint32_t bitrate){
|
||||
requestedBitrate=bitrate;
|
||||
}
|
||||
|
||||
void tgvoip::OpusEncoder::Encode(int16_t* data, size_t len){
|
||||
if(requestedBitrate!=currentBitrate){
|
||||
opus_encoder_ctl(enc, OPUS_SET_BITRATE(requestedBitrate));
|
||||
currentBitrate=requestedBitrate;
|
||||
LOGV("opus_encoder: setting bitrate to %u", currentBitrate);
|
||||
}
|
||||
if(levelMeter)
|
||||
levelMeter->Update(data, len);
|
||||
if(secondaryEncoderEnabled!=wasSecondaryEncoderEnabled){
|
||||
wasSecondaryEncoderEnabled=secondaryEncoderEnabled;
|
||||
}
|
||||
int32_t r=opus_encode(enc, data, static_cast<int>(len), buffer, 4096);
|
||||
// int bw;
|
||||
// opus_encoder_ctl(enc, OPUS_GET_BANDWIDTH(&bw));
|
||||
// LOGV("Opus bandwidth: %d", bw);
|
||||
if(r<=0){
|
||||
LOGE("Error encoding: %d", r);
|
||||
}else if(r==1){
|
||||
LOGW("DTX");
|
||||
}else if(running){
|
||||
//LOGV("Packet size = %d", r);
|
||||
int32_t secondaryLen=0;
|
||||
unsigned char secondaryBuffer[128];
|
||||
if(secondaryEncoderEnabled && secondaryEncoder){
|
||||
secondaryLen=opus_encode(secondaryEncoder, data, static_cast<int>(len), secondaryBuffer, sizeof(secondaryBuffer));
|
||||
//LOGV("secondaryLen %d", secondaryLen);
|
||||
}
|
||||
InvokeCallback(buffer, (size_t)r, secondaryBuffer, (size_t)secondaryLen);
|
||||
}
|
||||
}
|
||||
|
||||
size_t tgvoip::OpusEncoder::Callback(unsigned char *data, size_t len, void* param){
|
||||
assert(len==960*2);
|
||||
OpusEncoder* e=(OpusEncoder*)param;
|
||||
try{
|
||||
Buffer buf=e->bufferPool.Get();
|
||||
buf.CopyFrom(data, 0, 960*2);
|
||||
e->queue.Put(std::move(buf));
|
||||
}catch(std::bad_alloc& x){
|
||||
LOGW("opus_encoder: no buffer slots left");
|
||||
if(e->complexity>1){
|
||||
e->complexity--;
|
||||
opus_encoder_ctl(e->enc, OPUS_SET_COMPLEXITY(e->complexity));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
uint32_t tgvoip::OpusEncoder::GetBitrate(){
|
||||
return requestedBitrate;
|
||||
}
|
||||
|
||||
void tgvoip::OpusEncoder::SetEchoCanceller(EchoCanceller* aec){
|
||||
echoCanceller=aec;
|
||||
}
|
||||
|
||||
void tgvoip::OpusEncoder::RunThread(){
|
||||
uint32_t bufferedCount=0;
|
||||
uint32_t packetsPerFrame=frameDuration/20;
|
||||
LOGV("starting encoder, packets per frame=%d", packetsPerFrame);
|
||||
int16_t* frame;
|
||||
if(packetsPerFrame>1)
|
||||
frame=(int16_t*) malloc(960*2*packetsPerFrame);
|
||||
else
|
||||
frame=NULL;
|
||||
bool frameHasVoice=false;
|
||||
bool wasVadMode=false;
|
||||
while(running){
|
||||
Buffer _packet=queue.GetBlocking();
|
||||
if(!_packet.IsEmpty()){
|
||||
int16_t* packet=(int16_t*)*_packet;
|
||||
bool hasVoice=true;
|
||||
if(echoCanceller)
|
||||
echoCanceller->ProcessInput(packet, 960, hasVoice);
|
||||
if(!postProcEffects.empty()){
|
||||
for(effects::AudioEffect* effect:postProcEffects){
|
||||
effect->Process(packet, 960);
|
||||
}
|
||||
}
|
||||
if(packetsPerFrame==1){
|
||||
Encode(packet, 960);
|
||||
}else{
|
||||
memcpy(frame+(960*bufferedCount), packet, 960*2);
|
||||
frameHasVoice=frameHasVoice || hasVoice;
|
||||
bufferedCount++;
|
||||
if(bufferedCount==packetsPerFrame){
|
||||
if(vadMode){
|
||||
if(frameHasVoice){
|
||||
opus_encoder_ctl(enc, OPUS_SET_BITRATE(currentBitrate));
|
||||
if(secondaryEncoder){
|
||||
opus_encoder_ctl(secondaryEncoder, OPUS_SET_BITRATE(currentBitrate));
|
||||
}
|
||||
}else{
|
||||
opus_encoder_ctl(enc, OPUS_SET_BITRATE(vadNoVoiceBitrate));
|
||||
if(secondaryEncoder){
|
||||
opus_encoder_ctl(secondaryEncoder, OPUS_SET_BITRATE(vadNoVoiceBitrate));
|
||||
}
|
||||
}
|
||||
wasVadMode=true;
|
||||
}else if(wasVadMode){
|
||||
wasVadMode=false;
|
||||
opus_encoder_ctl(enc, OPUS_SET_BITRATE(currentBitrate));
|
||||
if(secondaryEncoder){
|
||||
opus_encoder_ctl(secondaryEncoder, OPUS_SET_BITRATE(currentBitrate));
|
||||
}
|
||||
}
|
||||
Encode(frame, 960*packetsPerFrame);
|
||||
bufferedCount=0;
|
||||
frameHasVoice=false;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(frame)
|
||||
free(frame);
|
||||
}
|
||||
|
||||
|
||||
void tgvoip::OpusEncoder::SetOutputFrameDuration(uint32_t duration){
|
||||
frameDuration=duration;
|
||||
}
|
||||
|
||||
|
||||
void tgvoip::OpusEncoder::SetPacketLoss(int percent){
|
||||
packetLossPercent=std::min(20, percent);
|
||||
opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(packetLossPercent));
|
||||
opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC(percent>0 && !secondaryEncoderEnabled ? 1 : 0));
|
||||
}
|
||||
|
||||
int tgvoip::OpusEncoder::GetPacketLoss(){
|
||||
return packetLossPercent;
|
||||
}
|
||||
|
||||
void tgvoip::OpusEncoder::SetDTX(bool enable){
|
||||
opus_encoder_ctl(enc, OPUS_SET_DTX(enable ? 1 : 0));
|
||||
}
|
||||
|
||||
void tgvoip::OpusEncoder::SetLevelMeter(tgvoip::AudioLevelMeter *levelMeter){
|
||||
this->levelMeter=levelMeter;
|
||||
}
|
||||
|
||||
void tgvoip::OpusEncoder::SetCallback(std::function <void(unsigned char*, size_t, unsigned char*, size_t)> f){
|
||||
callback=f;
|
||||
}
|
||||
|
||||
void tgvoip::OpusEncoder::InvokeCallback(unsigned char *data, size_t length, unsigned char *secondaryData, size_t secondaryLength){
|
||||
callback(data, length, secondaryData, secondaryLength);
|
||||
}
|
||||
|
||||
void tgvoip::OpusEncoder::SetSecondaryEncoderEnabled(bool enabled){
|
||||
secondaryEncoderEnabled=enabled;
|
||||
}
|
||||
|
||||
void tgvoip::OpusEncoder::SetVadMode(bool vad){
|
||||
vadMode=vad;
|
||||
}
|
||||
void tgvoip::OpusEncoder::AddAudioEffect(effects::AudioEffect *effect){
|
||||
postProcEffects.push_back(effect);
|
||||
}
|
||||
|
||||
void tgvoip::OpusEncoder::RemoveAudioEffect(effects::AudioEffect *effect){
|
||||
std::vector<effects::AudioEffect*>::iterator i=std::find(postProcEffects.begin(), postProcEffects.end(), effect);
|
||||
if(i!=postProcEffects.end())
|
||||
postProcEffects.erase(i);
|
||||
}
|
82
TMessagesProj/jni/libtgvoip2/OpusEncoder.h
Normal file
82
TMessagesProj/jni/libtgvoip2/OpusEncoder.h
Normal file
|
@ -0,0 +1,82 @@
|
|||
//
|
||||
// libtgvoip is free and unencumbered public domain software.
|
||||
// For more information, see http://unlicense.org or the UNLICENSE file
|
||||
// you should have received with this source code distribution.
|
||||
//
|
||||
|
||||
#ifndef LIBTGVOIP_OPUSENCODER_H
|
||||
#define LIBTGVOIP_OPUSENCODER_H
|
||||
|
||||
|
||||
#include "MediaStreamItf.h"
|
||||
#include "threading.h"
|
||||
#include "BlockingQueue.h"
|
||||
#include "Buffers.h"
|
||||
#include "EchoCanceller.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <atomic>
|
||||
|
||||
struct OpusEncoder;
|
||||
|
||||
namespace tgvoip{
|
||||
class OpusEncoder{
|
||||
public:
|
||||
TGVOIP_DISALLOW_COPY_AND_ASSIGN(OpusEncoder);
|
||||
OpusEncoder(MediaStreamItf* source, bool needSecondary);
|
||||
virtual ~OpusEncoder();
|
||||
virtual void Start();
|
||||
virtual void Stop();
|
||||
void SetBitrate(uint32_t bitrate);
|
||||
void SetEchoCanceller(EchoCanceller* aec);
|
||||
void SetOutputFrameDuration(uint32_t duration);
|
||||
void SetPacketLoss(int percent);
|
||||
int GetPacketLoss();
|
||||
uint32_t GetBitrate();
|
||||
void SetDTX(bool enable);
|
||||
void SetLevelMeter(AudioLevelMeter* levelMeter);
|
||||
void SetCallback(std::function <void(unsigned char*, size_t, unsigned char*, size_t)> callback);
|
||||
void SetSecondaryEncoderEnabled(bool enabled);
|
||||
void SetVadMode(bool vad);
|
||||
void AddAudioEffect(effects::AudioEffect* effect);
|
||||
void RemoveAudioEffect(effects::AudioEffect* effect);
|
||||
int GetComplexity(){
|
||||
return complexity;
|
||||
}
|
||||
|
||||
private:
|
||||
static size_t Callback(unsigned char* data, size_t len, void* param);
|
||||
void RunThread();
|
||||
void Encode(int16_t* data, size_t len);
|
||||
void InvokeCallback(unsigned char* data, size_t length, unsigned char* secondaryData, size_t secondaryLength);
|
||||
MediaStreamItf* source;
|
||||
::OpusEncoder* enc;
|
||||
::OpusEncoder* secondaryEncoder;
|
||||
unsigned char buffer[4096];
|
||||
std::atomic<uint32_t> requestedBitrate;
|
||||
uint32_t currentBitrate;
|
||||
Thread* thread;
|
||||
BlockingQueue<Buffer> queue;
|
||||
BufferPool<960*2, 10> bufferPool;
|
||||
EchoCanceller* echoCanceller;
|
||||
std::atomic<int> complexity;
|
||||
std::atomic<bool> running;
|
||||
uint32_t frameDuration;
|
||||
int packetLossPercent;
|
||||
AudioLevelMeter* levelMeter;
|
||||
std::atomic<bool> secondaryEncoderEnabled;
|
||||
bool vadMode=false;
|
||||
uint32_t vadNoVoiceBitrate;
|
||||
std::vector<effects::AudioEffect*> postProcEffects;
|
||||
int secondaryEnabledBandwidth;
|
||||
int vadModeVoiceBandwidth;
|
||||
int vadModeNoVoiceBandwidth;
|
||||
|
||||
bool wasSecondaryEncoderEnabled=false;
|
||||
|
||||
std::function <void(unsigned char*, size_t, unsigned char*, size_t)> callback;
|
||||
};
|
||||
}
|
||||
|
||||
#endif //LIBTGVOIP_OPUSENCODER_H
|
226
TMessagesProj/jni/libtgvoip2/PacketReassembler.cpp
Normal file
226
TMessagesProj/jni/libtgvoip2/PacketReassembler.cpp
Normal file
|
@ -0,0 +1,226 @@
|
|||
//
|
||||
// Created by Grishka on 19.03.2018.
|
||||
//
|
||||
|
||||
#include "PacketReassembler.h"
|
||||
#include "logging.h"
|
||||
#include "PrivateDefines.h"
|
||||
#include "video/VideoFEC.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <sstream>
|
||||
|
||||
#define NUM_OLD_PACKETS 3
|
||||
#define NUM_FEC_PACKETS 10
|
||||
|
||||
using namespace tgvoip;
|
||||
using namespace tgvoip::video;
|
||||
|
||||
PacketReassembler::PacketReassembler(){
|
||||
}
|
||||
|
||||
PacketReassembler::~PacketReassembler(){
|
||||
}
|
||||
|
||||
void PacketReassembler::Reset(){
|
||||
|
||||
}
|
||||
|
||||
void PacketReassembler::AddFragment(Buffer pkt, unsigned int fragmentIndex, unsigned int fragmentCount, uint32_t pts, uint8_t _fseq, bool keyframe, uint16_t rotation){
|
||||
for(std::unique_ptr<Packet>& packet:packets){
|
||||
if(packet->timestamp==pts){
|
||||
if(fragmentCount!=packet->partCount){
|
||||
LOGE("Received fragment total count %u inconsistent with previous %u", fragmentCount, packet->partCount);
|
||||
return;
|
||||
}
|
||||
if(fragmentIndex>=packet->partCount){
|
||||
LOGE("Received fragment index %u is greater than total %u", fragmentIndex, fragmentCount);
|
||||
return;
|
||||
}
|
||||
packet->AddFragment(std::move(pkt), fragmentIndex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
uint32_t fseq=(lastFrameSeq & 0xFFFFFF00) | (uint32_t)_fseq;
|
||||
if((uint8_t)lastFrameSeq>_fseq)
|
||||
fseq+=256;
|
||||
//LOGV("fseq: %u", (unsigned int)fseq);
|
||||
|
||||
/*if(pts<maxTimestamp){
|
||||
LOGW("Received fragment doesn't belong here (ts=%u < maxTs=%u)", pts, maxTimestamp);
|
||||
return;
|
||||
}*/
|
||||
if(lastFrameSeq>3 && fseq<lastFrameSeq-3){
|
||||
LOGW("Packet too late (fseq=%u, lastFseq=%u)", fseq, lastFrameSeq);
|
||||
return;
|
||||
}
|
||||
if(fragmentIndex>=fragmentCount){
|
||||
LOGE("Received fragment index %u is out of bounds %u", fragmentIndex, fragmentCount);
|
||||
return;
|
||||
}
|
||||
if(fragmentCount>255){
|
||||
LOGE("Received fragment total count too big %u", fragmentCount);
|
||||
return;
|
||||
}
|
||||
|
||||
maxTimestamp=std::max(maxTimestamp, pts);
|
||||
|
||||
packets.push_back(std::unique_ptr<Packet>(new Packet(fseq, pts, fragmentCount, 0, keyframe, rotation)));
|
||||
packets[packets.size()-1]->AddFragment(std::move(pkt), fragmentIndex);
|
||||
while(packets.size()>3){
|
||||
std::unique_ptr<Packet>& _old=packets[0];
|
||||
if(_old->receivedPartCount==_old->partCount){
|
||||
std::unique_ptr<Packet> old=std::move(packets[0]);
|
||||
packets.erase(packets.begin());
|
||||
|
||||
Buffer buffer=old->Reassemble();
|
||||
callback(std::move(buffer), old->seq, old->isKeyframe, old->rotation);
|
||||
oldPackets.push_back(std::move(old));
|
||||
while(oldPackets.size()>NUM_OLD_PACKETS)
|
||||
oldPackets.erase(oldPackets.begin());
|
||||
}else{
|
||||
LOGW("Packet %u not reassembled (%u of %u)", packets[0]->seq, packets[0]->receivedPartCount, packets[0]->partCount);
|
||||
if(packets[0]->partCount-packets[0]->receivedPartCount==1 && !waitingForFEC){
|
||||
bool found=false;
|
||||
for(FecPacket& fec:fecPackets){
|
||||
if(packets[0]->seq<=fec.seq && packets[0]->seq>fec.seq-fec.prevFrameCount){
|
||||
LOGI("Found FEC packet: %u %u", fec.seq, fec.prevFrameCount);
|
||||
found=true;
|
||||
TryDecodeFEC(fec);
|
||||
packets.erase(packets.begin());
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!found){
|
||||
waitingForFEC=true;
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
waitingForFEC=false;
|
||||
LOGE("unrecoverable packet loss");
|
||||
std::unique_ptr<Packet> old=std::move(packets[0]);
|
||||
packets.erase(packets.begin());
|
||||
oldPackets.push_back(std::move(old));
|
||||
while(oldPackets.size()>NUM_OLD_PACKETS)
|
||||
oldPackets.erase(oldPackets.begin());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lastFrameSeq=fseq;
|
||||
}
|
||||
|
||||
void PacketReassembler::AddFEC(Buffer data, uint8_t _fseq, unsigned int frameCount, unsigned int fecScheme){
|
||||
uint32_t fseq=(lastFrameSeq & 0xFFFFFF00) | (uint32_t)_fseq;
|
||||
std::ostringstream _s;
|
||||
for(unsigned int i=0;i<frameCount;i++){
|
||||
_s << (fseq-i);
|
||||
_s << " ";
|
||||
}
|
||||
//LOGV("Received FEC packet: len %u, scheme %u, frames %s", (unsigned int)data.Length(), fecScheme, _s.str().c_str());
|
||||
FecPacket fec{
|
||||
fseq,
|
||||
frameCount,
|
||||
fecScheme,
|
||||
std::move(data)
|
||||
};
|
||||
|
||||
if(waitingForFEC){
|
||||
if(packets[0]->seq<=fec.seq && packets[0]->seq>fec.seq-fec.prevFrameCount){
|
||||
LOGI("Found FEC packet: %u %u", fec.seq, fec.prevFrameCount);
|
||||
TryDecodeFEC(fec);
|
||||
packets.erase(packets.begin());
|
||||
waitingForFEC=false;
|
||||
}
|
||||
}
|
||||
fecPackets.push_back(std::move(fec));
|
||||
while(fecPackets.size()>NUM_FEC_PACKETS)
|
||||
fecPackets.erase(fecPackets.begin());
|
||||
}
|
||||
|
||||
void PacketReassembler::SetCallback(std::function<void(Buffer packet, uint32_t pts, bool keyframe, uint16_t rotation)> callback){
|
||||
this->callback=callback;
|
||||
}
|
||||
|
||||
bool PacketReassembler::TryDecodeFEC(PacketReassembler::FecPacket &fec){
|
||||
/*LOGI("Decoding FEC");
|
||||
|
||||
std::vector<Buffer> packetsForRecovery;
|
||||
for(std::unique_ptr<Packet>& p:oldPackets){
|
||||
if(p->seq<=fec.seq && p->seq>fec.seq-fec.prevFrameCount){
|
||||
LOGD("Adding frame %u from old", p->seq);
|
||||
for(uint32_t i=0;i<p->partCount;i++){
|
||||
packetsForRecovery.push_back(i<p->parts.size() ? Buffer::CopyOf(p->parts[i]) : Buffer());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(std::unique_ptr<Packet>& p:packets){
|
||||
if(p->seq<=fec.seq && p->seq>fec.seq-fec.prevFrameCount){
|
||||
LOGD("Adding frame %u from pending", p->seq);
|
||||
for(uint32_t i=0;i<p->partCount;i++){
|
||||
//LOGV("[%u] size %u", i, p.parts[i].Length());
|
||||
packetsForRecovery.push_back(i<p->parts.size() ? Buffer::CopyOf(p->parts[i]) : Buffer());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(fec.fecScheme==FEC_SCHEME_XOR){
|
||||
Buffer recovered=ParityFEC::Decode(packetsForRecovery, fec.data);
|
||||
LOGI("Recovered packet size %u", (unsigned int)recovered.Length());
|
||||
if(!recovered.IsEmpty()){
|
||||
std::unique_ptr<Packet>& pkt=packets[0];
|
||||
if(pkt->parts.size()<pkt->partCount){
|
||||
pkt->parts.push_back(std::move(recovered));
|
||||
}else{
|
||||
for(Buffer &b:pkt->parts){
|
||||
if(b.IsEmpty()){
|
||||
b=std::move(recovered);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
pkt->receivedPartCount++;
|
||||
callback(pkt->Reassemble(), pkt->seq, pkt->isKeyframe, pkt->rotation);
|
||||
}
|
||||
}*/
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#pragma mark - Packet
|
||||
|
||||
void PacketReassembler::Packet::AddFragment(Buffer pkt, uint32_t fragmentIndex){
|
||||
//LOGV("Add fragment %u/%u to packet %u", fragmentIndex, partCount, timestamp);
|
||||
if(parts.size()==fragmentIndex){
|
||||
parts.push_back(std::move(pkt));
|
||||
//LOGV("add1");
|
||||
}else if(parts.size()>fragmentIndex){
|
||||
assert(parts[fragmentIndex].IsEmpty());
|
||||
parts[fragmentIndex]=std::move(pkt);
|
||||
//LOGV("add2");
|
||||
}else{
|
||||
while(parts.size()<fragmentIndex)
|
||||
parts.push_back(Buffer());
|
||||
parts.push_back(std::move(pkt));
|
||||
//LOGV("add3");
|
||||
}
|
||||
receivedPartCount++;
|
||||
//assert(parts.size()>=receivedPartCount);
|
||||
if(parts.size()<receivedPartCount)
|
||||
LOGW("Received %u parts but parts.size is %u", (unsigned int)receivedPartCount, (unsigned int)parts.size());
|
||||
}
|
||||
|
||||
Buffer PacketReassembler::Packet::Reassemble(){
|
||||
assert(partCount==receivedPartCount);
|
||||
assert(parts.size()==partCount);
|
||||
if(partCount==1){
|
||||
return Buffer::CopyOf(parts[0]);
|
||||
}
|
||||
BufferOutputStream out(10240);
|
||||
for(unsigned int i=0;i<partCount;i++){
|
||||
out.WriteBytes(parts[i]);
|
||||
//parts[i]=Buffer();
|
||||
}
|
||||
return Buffer(std::move(out));
|
||||
}
|
64
TMessagesProj/jni/libtgvoip2/PacketReassembler.h
Normal file
64
TMessagesProj/jni/libtgvoip2/PacketReassembler.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
//
|
||||
// Created by Grishka on 19.03.2018.
|
||||
//
|
||||
|
||||
#ifndef TGVOIP_PACKETREASSEMBLER_H
|
||||
#define TGVOIP_PACKETREASSEMBLER_H
|
||||
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
|
||||
#include "Buffers.h"
|
||||
#include "logging.h"
|
||||
|
||||
namespace tgvoip {
|
||||
class PacketReassembler{
|
||||
public:
|
||||
PacketReassembler();
|
||||
virtual ~PacketReassembler();
|
||||
|
||||
void Reset();
|
||||
void AddFragment(Buffer pkt, unsigned int fragmentIndex, unsigned int fragmentCount, uint32_t pts, uint8_t fseq, bool keyframe, uint16_t rotation);
|
||||
void AddFEC(Buffer data, uint8_t fseq, unsigned int frameCount, unsigned int fecScheme);
|
||||
void SetCallback(std::function<void(Buffer packet, uint32_t pts, bool keyframe, uint16_t rotation)> callback);
|
||||
|
||||
private:
|
||||
struct Packet{
|
||||
uint32_t seq;
|
||||
uint32_t timestamp;
|
||||
uint32_t partCount;
|
||||
uint32_t receivedPartCount;
|
||||
bool isKeyframe;
|
||||
uint16_t rotation;
|
||||
std::vector<Buffer> parts;
|
||||
|
||||
Packet(uint32_t seq, uint32_t timestamp, uint32_t partCount, uint32_t receivedPartCount, bool keyframe, uint16_t rotation)
|
||||
:seq(seq), timestamp(timestamp), partCount(partCount), receivedPartCount(receivedPartCount), isKeyframe(keyframe), rotation(rotation){
|
||||
|
||||
}
|
||||
|
||||
void AddFragment(Buffer pkt, uint32_t fragmentIndex);
|
||||
Buffer Reassemble();
|
||||
};
|
||||
struct FecPacket{
|
||||
uint32_t seq;
|
||||
uint32_t prevFrameCount;
|
||||
uint32_t fecScheme;
|
||||
Buffer data;
|
||||
};
|
||||
|
||||
bool TryDecodeFEC(FecPacket& fec);
|
||||
|
||||
std::function<void(Buffer, uint32_t, bool, uint16_t)> callback;
|
||||
std::vector<std::unique_ptr<Packet>> packets;
|
||||
std::vector<std::unique_ptr<Packet>> oldPackets; // for FEC
|
||||
std::vector<FecPacket> fecPackets;
|
||||
uint32_t maxTimestamp=0;
|
||||
uint32_t lastFrameSeq=0;
|
||||
bool waitingForFEC=false;
|
||||
};
|
||||
}
|
||||
|
||||
#endif //TGVOIP_PACKETREASSEMBLER_H
|
64
TMessagesProj/jni/libtgvoip2/PacketSender.h
Normal file
64
TMessagesProj/jni/libtgvoip2/PacketSender.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
//
|
||||
// Created by Grishka on 19/03/2019.
|
||||
//
|
||||
|
||||
#ifndef LIBTGVOIP_PACKETSENDER_H
|
||||
#define LIBTGVOIP_PACKETSENDER_H
|
||||
|
||||
#include "VoIPController.h"
|
||||
#include <functional>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace tgvoip{
|
||||
class PacketSender{
|
||||
public:
|
||||
PacketSender(VoIPController* controller) : controller(controller) {};
|
||||
virtual ~PacketSender(){};
|
||||
virtual void PacketAcknowledged(uint32_t seq, double sendTime, double ackTime, uint8_t type, uint32_t size)=0;
|
||||
virtual void PacketLost(uint32_t seq, uint8_t type, uint32_t size)=0;
|
||||
|
||||
protected:
|
||||
void SendExtra(Buffer& data, unsigned char type){
|
||||
controller->SendExtra(data, type);
|
||||
}
|
||||
|
||||
void IncrementUnsentStreamPackets(){
|
||||
controller->unsentStreamPackets++;
|
||||
}
|
||||
|
||||
uint32_t SendPacket(VoIPController::PendingOutgoingPacket pkt){
|
||||
uint32_t seq=controller->GenerateOutSeq();
|
||||
pkt.seq=seq;
|
||||
controller->SendOrEnqueuePacket(std::move(pkt), true, this);
|
||||
return seq;
|
||||
}
|
||||
|
||||
double GetConnectionInitTime(){
|
||||
return controller->connectionInitTime;
|
||||
}
|
||||
|
||||
const HistoricBuffer<double, 32>& RTTHistory(){
|
||||
return controller->rttHistory;
|
||||
}
|
||||
|
||||
MessageThread& GetMessageThread(){
|
||||
return controller->messageThread;
|
||||
}
|
||||
|
||||
const VoIPController::ProtocolInfo& GetProtocolInfo(){
|
||||
return controller->protocolInfo;
|
||||
}
|
||||
|
||||
void SendStreamFlags(VoIPController::Stream& stm){
|
||||
controller->SendStreamFlags(stm);
|
||||
}
|
||||
|
||||
const VoIPController::Config& GetConfig(){
|
||||
return controller->config;
|
||||
}
|
||||
|
||||
VoIPController* controller;
|
||||
};
|
||||
}
|
||||
|
||||
#endif //LIBTGVOIP_PACKETSENDER_H
|
142
TMessagesProj/jni/libtgvoip2/PrivateDefines.h
Normal file
142
TMessagesProj/jni/libtgvoip2/PrivateDefines.h
Normal file
|
@ -0,0 +1,142 @@
|
|||
//
|
||||
// Created by Grishka on 20.04.2018.
|
||||
//
|
||||
|
||||
#ifndef TGVOIP_PRIVATEDEFINES_H
|
||||
#define TGVOIP_PRIVATEDEFINES_H
|
||||
|
||||
#define PKT_INIT 1
|
||||
#define PKT_INIT_ACK 2
|
||||
#define PKT_STREAM_STATE 3
|
||||
#define PKT_STREAM_DATA 4
|
||||
#define PKT_UPDATE_STREAMS 5
|
||||
#define PKT_PING 6
|
||||
#define PKT_PONG 7
|
||||
#define PKT_STREAM_DATA_X2 8
|
||||
#define PKT_STREAM_DATA_X3 9
|
||||
#define PKT_LAN_ENDPOINT 10
|
||||
#define PKT_NETWORK_CHANGED 11
|
||||
#define PKT_SWITCH_PREF_RELAY 12
|
||||
#define PKT_SWITCH_TO_P2P 13
|
||||
#define PKT_NOP 14
|
||||
//#define PKT_GROUP_CALL_KEY 15 // replaced with 'extra' in 2.1 (protocol v6)
|
||||
//#define PKT_REQUEST_GROUP 16
|
||||
#define PKT_STREAM_EC 17
|
||||
|
||||
#define IS_MOBILE_NETWORK(x) (x==NET_TYPE_GPRS || x==NET_TYPE_EDGE || x==NET_TYPE_3G || x==NET_TYPE_HSPA || x==NET_TYPE_LTE || x==NET_TYPE_OTHER_MOBILE)
|
||||
|
||||
#define PROTOCOL_NAME 0x50567247 // "GrVP" in little endian (reversed here)
|
||||
#define PROTOCOL_VERSION 9
|
||||
#define MIN_PROTOCOL_VERSION 3
|
||||
|
||||
#define STREAM_DATA_FLAG_LEN16 0x40
|
||||
#define STREAM_DATA_FLAG_HAS_MORE_FLAGS 0x80
|
||||
// Since the data can't be larger than the MTU anyway,
|
||||
// 5 top bits of data length are allocated for these flags
|
||||
#define STREAM_DATA_XFLAG_KEYFRAME (1 << 15)
|
||||
#define STREAM_DATA_XFLAG_FRAGMENTED (1 << 14)
|
||||
#define STREAM_DATA_XFLAG_EXTRA_FEC (1 << 13)
|
||||
|
||||
#define STREAM_TYPE_AUDIO 1
|
||||
#define STREAM_TYPE_VIDEO 2
|
||||
|
||||
#define FOURCC(a,b,c,d) ((uint32_t)d | ((uint32_t)c << 8) | ((uint32_t)b << 16) | ((uint32_t)a << 24))
|
||||
#define PRINT_FOURCC(x) (char)(x >> 24), (char)(x >> 16), (char)(x >> 8), (char)x
|
||||
|
||||
#define CODEC_OPUS_OLD 1
|
||||
#define CODEC_OPUS FOURCC('O','P','U','S')
|
||||
|
||||
#define CODEC_AVC FOURCC('A','V','C',' ')
|
||||
#define CODEC_HEVC FOURCC('H','E','V','C')
|
||||
#define CODEC_VP8 FOURCC('V','P','8','0')
|
||||
#define CODEC_VP9 FOURCC('V','P','9','0')
|
||||
#define CODEC_AV1 FOURCC('A','V','0','1')
|
||||
|
||||
#define DEFAULT_MTU 1100
|
||||
|
||||
/*flags:# voice_call_id:flags.2?int128 in_seq_no:flags.4?int out_seq_no:flags.4?int
|
||||
* recent_received_mask:flags.5?int proto:flags.3?int extra:flags.1?string raw_data:flags.0?string*/
|
||||
#define PFLAG_HAS_DATA 1
|
||||
#define PFLAG_HAS_EXTRA 2
|
||||
#define PFLAG_HAS_CALL_ID 4
|
||||
#define PFLAG_HAS_PROTO 8
|
||||
#define PFLAG_HAS_SEQ 16
|
||||
#define PFLAG_HAS_RECENT_RECV 32
|
||||
#define PFLAG_HAS_SENDER_TAG_HASH 64
|
||||
|
||||
#define XPFLAG_HAS_EXTRA 1
|
||||
#define XPFLAG_HAS_RECV_TS 2
|
||||
|
||||
#define EXTRA_TYPE_STREAM_FLAGS 1
|
||||
#define EXTRA_TYPE_STREAM_CSD 2
|
||||
#define EXTRA_TYPE_LAN_ENDPOINT 3
|
||||
#define EXTRA_TYPE_NETWORK_CHANGED 4
|
||||
#define EXTRA_TYPE_GROUP_CALL_KEY 5
|
||||
#define EXTRA_TYPE_REQUEST_GROUP 6
|
||||
#define EXTRA_TYPE_IPV6_ENDPOINT 7
|
||||
|
||||
#define STREAM_FLAG_ENABLED 1
|
||||
#define STREAM_FLAG_DTX 2
|
||||
#define STREAM_FLAG_EXTRA_EC 4
|
||||
#define STREAM_FLAG_PAUSED 8
|
||||
|
||||
#define STREAM_RFLAG_SUPPORTED 1
|
||||
|
||||
#define INIT_FLAG_DATA_SAVING_ENABLED 1
|
||||
#define INIT_FLAG_GROUP_CALLS_SUPPORTED 2
|
||||
#define INIT_FLAG_VIDEO_SEND_SUPPORTED 4
|
||||
#define INIT_FLAG_VIDEO_RECV_SUPPORTED 8
|
||||
|
||||
#define INIT_VIDEO_RES_NONE 0
|
||||
#define INIT_VIDEO_RES_240 1
|
||||
#define INIT_VIDEO_RES_360 2
|
||||
#define INIT_VIDEO_RES_480 3
|
||||
#define INIT_VIDEO_RES_720 4
|
||||
#define INIT_VIDEO_RES_1080 5
|
||||
#define INIT_VIDEO_RES_1440 6
|
||||
#define INIT_VIDEO_RES_4K 7
|
||||
|
||||
#define TLID_DECRYPTED_AUDIO_BLOCK 0xDBF948C1
|
||||
#define TLID_SIMPLE_AUDIO_BLOCK 0xCC0D0E76
|
||||
#define TLID_UDP_REFLECTOR_PEER_INFO 0x27D9371C
|
||||
#define TLID_UDP_REFLECTOR_PEER_INFO_IPV6 0x83fc73b1
|
||||
#define TLID_UDP_REFLECTOR_SELF_INFO 0xc01572c7
|
||||
#define TLID_UDP_REFLECTOR_REQUEST_PACKETS_INFO 0x1a06fc96
|
||||
#define TLID_UDP_REFLECTOR_LAST_PACKETS_INFO 0x0e107305
|
||||
#define TLID_VECTOR 0x1cb5c415
|
||||
#define PAD4(x) (4-(x+(x<=253 ? 1 : 0))%4)
|
||||
|
||||
#define MAX_RECENT_PACKETS 128
|
||||
|
||||
#define SHA1_LENGTH 20
|
||||
#define SHA256_LENGTH 32
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define MSC_STACK_FALLBACK(a, b) (b)
|
||||
#else
|
||||
#define MSC_STACK_FALLBACK(a, b) (a)
|
||||
#endif
|
||||
|
||||
#define SEQ_MAX 0xFFFFFFFF
|
||||
|
||||
inline bool seqgt(uint32_t s1, uint32_t s2){
|
||||
return ((s1>s2) && (s1-s2<=SEQ_MAX/2)) || ((s1<s2) && (s2-s1>SEQ_MAX/2));
|
||||
}
|
||||
|
||||
#define NEED_RATE_FLAG_SHITTY_INTERNET_MODE 1
|
||||
#define NEED_RATE_FLAG_UDP_NA 2
|
||||
#define NEED_RATE_FLAG_UDP_BAD 4
|
||||
#define NEED_RATE_FLAG_RECONNECTING 8
|
||||
|
||||
#define VIDEO_FRAME_FLAG_KEYFRAME 1
|
||||
|
||||
#define VIDEO_ROTATION_MASK 3
|
||||
#define VIDEO_ROTATION_0 0
|
||||
#define VIDEO_ROTATION_90 1
|
||||
#define VIDEO_ROTATION_180 2
|
||||
#define VIDEO_ROTATION_270 3
|
||||
|
||||
#define FEC_SCHEME_XOR 1
|
||||
#define FEC_SCHEME_CM256 2
|
||||
|
||||
#endif //TGVOIP_PRIVATEDEFINES_H
|
426
TMessagesProj/jni/libtgvoip2/TgVoip.cpp
Normal file
426
TMessagesProj/jni/libtgvoip2/TgVoip.cpp
Normal file
|
@ -0,0 +1,426 @@
|
|||
#include <mutex>
|
||||
|
||||
#include "TgVoip.h"
|
||||
|
||||
#include "VoIPController.h"
|
||||
#include "VoIPServerConfig.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifndef TGVOIP_USE_CUSTOM_CRYPTO
|
||||
extern "C" {
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/aes.h>
|
||||
//#include <openssl/modes.h>
|
||||
#include <openssl/rand.h>
|
||||
}
|
||||
|
||||
void tgvoip_openssl_aes_ige_encrypt(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv){
|
||||
AES_KEY akey;
|
||||
AES_set_encrypt_key(key, 32*8, &akey);
|
||||
AES_ige_encrypt(in, out, length, &akey, iv, AES_ENCRYPT);
|
||||
}
|
||||
|
||||
void tgvoip_openssl_aes_ige_decrypt(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv){
|
||||
AES_KEY akey;
|
||||
AES_set_decrypt_key(key, 32*8, &akey);
|
||||
AES_ige_encrypt(in, out, length, &akey, iv, AES_DECRYPT);
|
||||
}
|
||||
|
||||
void tgvoip_openssl_rand_bytes(uint8_t* buffer, size_t len){
|
||||
RAND_bytes(buffer, len);
|
||||
}
|
||||
|
||||
void tgvoip_openssl_sha1(uint8_t* msg, size_t len, uint8_t* output){
|
||||
SHA1(msg, len, output);
|
||||
}
|
||||
|
||||
void tgvoip_openssl_sha256(uint8_t* msg, size_t len, uint8_t* output){
|
||||
SHA256(msg, len, output);
|
||||
}
|
||||
|
||||
void tgvoip_openssl_aes_ctr_encrypt(uint8_t* inout, size_t length, uint8_t* key, uint8_t* iv, uint8_t* ecount, uint32_t* num){
|
||||
AES_KEY akey;
|
||||
AES_set_encrypt_key(key, 32*8, &akey);
|
||||
AES_ctr128_encrypt(inout, inout, length, &akey, iv, ecount, num);
|
||||
}
|
||||
|
||||
void tgvoip_openssl_aes_cbc_encrypt(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv){
|
||||
AES_KEY akey;
|
||||
AES_set_encrypt_key(key, 256, &akey);
|
||||
AES_cbc_encrypt(in, out, length, &akey, iv, AES_ENCRYPT);
|
||||
}
|
||||
|
||||
void tgvoip_openssl_aes_cbc_decrypt(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv){
|
||||
AES_KEY akey;
|
||||
AES_set_decrypt_key(key, 256, &akey);
|
||||
AES_cbc_encrypt(in, out, length, &akey, iv, AES_DECRYPT);
|
||||
}
|
||||
|
||||
tgvoip::CryptoFunctions tgvoip::VoIPController::crypto={
|
||||
tgvoip_openssl_rand_bytes,
|
||||
tgvoip_openssl_sha1,
|
||||
tgvoip_openssl_sha256,
|
||||
tgvoip_openssl_aes_ige_encrypt,
|
||||
tgvoip_openssl_aes_ige_decrypt,
|
||||
tgvoip_openssl_aes_ctr_encrypt,
|
||||
tgvoip_openssl_aes_cbc_encrypt,
|
||||
tgvoip_openssl_aes_cbc_decrypt
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
class TgVoipImpl : public TgVoip {
|
||||
public:
|
||||
TgVoipImpl(
|
||||
std::vector<TgVoipEndpoint> const &endpoints,
|
||||
TgVoipPersistentState const &persistentState,
|
||||
std::unique_ptr<TgVoipProxy> const &proxy,
|
||||
TgVoipConfig const &config,
|
||||
TgVoipEncryptionKey const &encryptionKey,
|
||||
TgVoipNetworkType initialNetworkType
|
||||
#ifdef TGVOIP_USE_CUSTOM_CRYPTO
|
||||
,
|
||||
TgVoipCrypto const &crypto
|
||||
#endif
|
||||
#ifdef TGVOIP_USE_CALLBACK_AUDIO_IO
|
||||
,
|
||||
TgVoipAudioDataCallbacks const &audioDataCallbacks
|
||||
#endif
|
||||
) {
|
||||
#ifdef TGVOIP_USE_CUSTOM_CRYPTO
|
||||
tgvoip::VoIPController::crypto.sha1 = crypto.sha1;
|
||||
tgvoip::VoIPController::crypto.sha256 = crypto.sha256;
|
||||
tgvoip::VoIPController::crypto.rand_bytes = crypto.rand_bytes;
|
||||
tgvoip::VoIPController::crypto.aes_ige_encrypt = crypto.aes_ige_encrypt;
|
||||
tgvoip::VoIPController::crypto.aes_ige_decrypt = crypto.aes_ige_decrypt;
|
||||
tgvoip::VoIPController::crypto.aes_ctr_encrypt = crypto.aes_ctr_encrypt;
|
||||
#endif
|
||||
|
||||
controller_ = new tgvoip::VoIPController();
|
||||
controller_->implData = this;
|
||||
|
||||
#ifdef TGVOIP_USE_CALLBACK_AUDIO_IO
|
||||
controller_->SetAudioDataCallbacks(audioDataCallbacks.input, audioDataCallbacks.output, audioDataCallbacks.preprocessed);
|
||||
#endif
|
||||
|
||||
controller_->SetPersistentState(persistentState.value);
|
||||
|
||||
if (proxy != nullptr) {
|
||||
controller_->SetProxy(tgvoip::PROXY_SOCKS5, proxy->host, proxy->port, proxy->login, proxy->password);
|
||||
}
|
||||
|
||||
auto callbacks = tgvoip::VoIPController::Callbacks();
|
||||
callbacks.connectionStateChanged = &TgVoipImpl::controllerStateCallback;
|
||||
callbacks.groupCallKeyReceived = nullptr;
|
||||
callbacks.groupCallKeySent = nullptr;
|
||||
callbacks.signalBarCountChanged = &TgVoipImpl::signalBarsCallback;
|
||||
callbacks.upgradeToGroupCallRequested = nullptr;
|
||||
controller_->SetCallbacks(callbacks);
|
||||
|
||||
std::vector<tgvoip::Endpoint> mappedEndpoints;
|
||||
for (auto endpoint : endpoints) {
|
||||
tgvoip::Endpoint::Type mappedType;
|
||||
switch (endpoint.type) {
|
||||
case TgVoipEndpointType::UdpRelay:
|
||||
mappedType = tgvoip::Endpoint::Type::UDP_RELAY;
|
||||
break;
|
||||
case TgVoipEndpointType::Lan:
|
||||
mappedType = tgvoip::Endpoint::Type::UDP_P2P_LAN;
|
||||
break;
|
||||
case TgVoipEndpointType::Inet:
|
||||
mappedType = tgvoip::Endpoint::Type::UDP_P2P_INET;
|
||||
break;
|
||||
case TgVoipEndpointType::TcpRelay:
|
||||
mappedType = tgvoip::Endpoint::Type::TCP_RELAY;
|
||||
break;
|
||||
default:
|
||||
mappedType = tgvoip::Endpoint::Type::UDP_RELAY;
|
||||
break;
|
||||
}
|
||||
|
||||
tgvoip::IPv4Address address(endpoint.host.ipv4);
|
||||
tgvoip::IPv6Address addressv6(endpoint.host.ipv6);
|
||||
|
||||
mappedEndpoints.emplace_back(endpoint.endpointId, endpoint.port, address, addressv6, mappedType, endpoint.peerTag);
|
||||
}
|
||||
|
||||
int mappedDataSaving;
|
||||
switch (config.dataSaving) {
|
||||
case TgVoipDataSaving::Mobile:
|
||||
mappedDataSaving = tgvoip::DATA_SAVING_MOBILE;
|
||||
break;
|
||||
case TgVoipDataSaving::Always:
|
||||
mappedDataSaving = tgvoip::DATA_SAVING_ALWAYS;
|
||||
break;
|
||||
default:
|
||||
mappedDataSaving = tgvoip::DATA_SAVING_NEVER;
|
||||
break;
|
||||
}
|
||||
|
||||
tgvoip::VoIPController::Config mappedConfig(
|
||||
config.initializationTimeout,
|
||||
config.receiveTimeout,
|
||||
mappedDataSaving,
|
||||
config.enableAEC,
|
||||
config.enableNS,
|
||||
config.enableAGC,
|
||||
config.enableCallUpgrade
|
||||
);
|
||||
mappedConfig.logFilePath = config.logPath;
|
||||
mappedConfig.statsDumpFilePath = {};
|
||||
|
||||
controller_->SetConfig(mappedConfig);
|
||||
|
||||
setNetworkType(initialNetworkType);
|
||||
|
||||
std::vector<uint8_t> encryptionKeyValue = encryptionKey.value;
|
||||
controller_->SetEncryptionKey(reinterpret_cast<char*>(encryptionKeyValue.data()), encryptionKey.isOutgoing);
|
||||
controller_->SetRemoteEndpoints(mappedEndpoints, config.enableP2P, config.maxApiLayer);
|
||||
|
||||
controller_->Start();
|
||||
|
||||
controller_->Connect();
|
||||
}
|
||||
|
||||
~TgVoipImpl() {
|
||||
|
||||
}
|
||||
|
||||
void setOnStateUpdated(std::function<void(TgVoipState)> onStateUpdated) {
|
||||
std::lock_guard<std::mutex> lock(m_onStateUpdated);
|
||||
onStateUpdated_ = onStateUpdated;
|
||||
}
|
||||
|
||||
void setOnSignalBarsUpdated(std::function<void(int)> onSignalBarsUpdated) {
|
||||
std::lock_guard<std::mutex> lock(m_onSignalBarsUpdated);
|
||||
onSignalBarsUpdated_ = onSignalBarsUpdated;
|
||||
}
|
||||
|
||||
void setNetworkType(TgVoipNetworkType networkType) override {
|
||||
int mappedType;
|
||||
|
||||
switch (networkType) {
|
||||
case TgVoipNetworkType::Unknown:
|
||||
mappedType = tgvoip::NET_TYPE_UNKNOWN;
|
||||
break;
|
||||
case TgVoipNetworkType::Gprs:
|
||||
mappedType = tgvoip::NET_TYPE_GPRS;
|
||||
break;
|
||||
case TgVoipNetworkType::Edge:
|
||||
mappedType = tgvoip::NET_TYPE_EDGE;
|
||||
break;
|
||||
case TgVoipNetworkType::ThirdGeneration:
|
||||
mappedType = tgvoip::NET_TYPE_3G;
|
||||
break;
|
||||
case TgVoipNetworkType::Hspa:
|
||||
mappedType = tgvoip::NET_TYPE_HSPA;
|
||||
break;
|
||||
case TgVoipNetworkType::Lte:
|
||||
mappedType = tgvoip::NET_TYPE_LTE;
|
||||
break;
|
||||
case TgVoipNetworkType::WiFi:
|
||||
mappedType = tgvoip::NET_TYPE_WIFI;
|
||||
break;
|
||||
case TgVoipNetworkType::Ethernet:
|
||||
mappedType = tgvoip::NET_TYPE_ETHERNET;
|
||||
break;
|
||||
case TgVoipNetworkType::OtherHighSpeed:
|
||||
mappedType = tgvoip::NET_TYPE_OTHER_HIGH_SPEED;
|
||||
break;
|
||||
case TgVoipNetworkType::OtherLowSpeed:
|
||||
mappedType = tgvoip::NET_TYPE_OTHER_LOW_SPEED;
|
||||
break;
|
||||
case TgVoipNetworkType::OtherMobile:
|
||||
mappedType = tgvoip::NET_TYPE_OTHER_MOBILE;
|
||||
break;
|
||||
case TgVoipNetworkType::Dialup:
|
||||
mappedType = tgvoip::NET_TYPE_DIALUP;
|
||||
break;
|
||||
default:
|
||||
mappedType = tgvoip::NET_TYPE_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
controller_->SetNetworkType(mappedType);
|
||||
}
|
||||
|
||||
void setMuteMicrophone(bool muteMicrophone) override {
|
||||
controller_->SetMicMute(muteMicrophone);
|
||||
}
|
||||
|
||||
void setAudioOutputGainControlEnabled(bool enabled) override {
|
||||
controller_->SetAudioOutputGainControlEnabled(enabled);
|
||||
}
|
||||
|
||||
void setEchoCancellationStrength(int strength) override {
|
||||
controller_->SetEchoCancellationStrength(strength);
|
||||
}
|
||||
|
||||
std::string getLastError() override {
|
||||
switch (controller_->GetLastError()) {
|
||||
case tgvoip::ERROR_INCOMPATIBLE: return "ERROR_INCOMPATIBLE";
|
||||
case tgvoip::ERROR_TIMEOUT: return "ERROR_TIMEOUT";
|
||||
case tgvoip::ERROR_AUDIO_IO: return "ERROR_AUDIO_IO";
|
||||
case tgvoip::ERROR_PROXY: return "ERROR_PROXY";
|
||||
default: return "ERROR_UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
std::string getDebugInfo() override {
|
||||
return controller_->GetDebugString();
|
||||
}
|
||||
|
||||
int64_t getPreferredRelayId() override {
|
||||
return controller_->GetPreferredRelayID();
|
||||
}
|
||||
|
||||
TgVoipTrafficStats getTrafficStats() override {
|
||||
tgvoip::VoIPController::TrafficStats stats;
|
||||
controller_->GetStats(&stats);
|
||||
return {
|
||||
.bytesSentWifi = stats.bytesSentWifi,
|
||||
.bytesReceivedWifi = stats.bytesRecvdWifi,
|
||||
.bytesSentMobile = stats.bytesSentMobile,
|
||||
.bytesReceivedMobile = stats.bytesRecvdMobile
|
||||
};
|
||||
}
|
||||
|
||||
TgVoipPersistentState getPersistentState() override {
|
||||
return {controller_->GetPersistentState()};
|
||||
}
|
||||
|
||||
TgVoipFinalState stop() override {
|
||||
controller_->Stop();
|
||||
|
||||
TgVoipFinalState finalState = {
|
||||
.persistentState = getPersistentState(),
|
||||
.debugLog = controller_->GetDebugLog(),
|
||||
.trafficStats = getTrafficStats(),
|
||||
.isRatingSuggested = controller_->NeedRate()
|
||||
};
|
||||
|
||||
delete controller_;
|
||||
controller_ = nullptr;
|
||||
|
||||
return finalState;
|
||||
}
|
||||
|
||||
static void controllerStateCallback(tgvoip::VoIPController* controller, int state) {
|
||||
TgVoipImpl* self = reinterpret_cast<TgVoipImpl*>(controller->implData);
|
||||
std::lock_guard<std::mutex> lock(self->m_onStateUpdated);
|
||||
|
||||
if (self->onStateUpdated_) {
|
||||
TgVoipState mappedState;
|
||||
switch (state) {
|
||||
case tgvoip::STATE_WAIT_INIT:
|
||||
mappedState = TgVoipState::WaitInit;
|
||||
break;
|
||||
case tgvoip::STATE_WAIT_INIT_ACK:
|
||||
mappedState = TgVoipState::WaitInitAck;
|
||||
break;
|
||||
case tgvoip::STATE_ESTABLISHED:
|
||||
mappedState = TgVoipState::Estabilished;
|
||||
break;
|
||||
case tgvoip::STATE_FAILED:
|
||||
mappedState = TgVoipState::Failed;
|
||||
break;
|
||||
case tgvoip::STATE_RECONNECTING:
|
||||
mappedState = TgVoipState::Reconnecting;
|
||||
break;
|
||||
default:
|
||||
mappedState = TgVoipState::Estabilished;
|
||||
break;
|
||||
}
|
||||
|
||||
self->onStateUpdated_(mappedState);
|
||||
}
|
||||
}
|
||||
|
||||
static void signalBarsCallback(tgvoip::VoIPController* controller, int signalBars) {
|
||||
TgVoipImpl* self = reinterpret_cast<TgVoipImpl*>(controller->implData);
|
||||
std::lock_guard<std::mutex> lock(self->m_onSignalBarsUpdated);
|
||||
|
||||
if (self->onSignalBarsUpdated_) {
|
||||
self->onSignalBarsUpdated_(signalBars);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
tgvoip::VoIPController *controller_;
|
||||
std::function<void(TgVoipState)> onStateUpdated_;
|
||||
std::function<void(int)> onSignalBarsUpdated_;
|
||||
std::mutex m_onStateUpdated, m_onSignalBarsUpdated;
|
||||
};
|
||||
|
||||
std::function<void(std::string const &)> globalLoggingFunction;
|
||||
|
||||
void __tgvoip_call_tglog(const char *format, ...){
|
||||
va_list vaArgs;
|
||||
va_start(vaArgs, format);
|
||||
|
||||
va_list vaCopy;
|
||||
va_copy(vaCopy, vaArgs);
|
||||
const int length = std::vsnprintf(nullptr, 0, format, vaCopy);
|
||||
va_end(vaCopy);
|
||||
|
||||
std::vector<char> zc(length + 1);
|
||||
std::vsnprintf(zc.data(), zc.size(), format, vaArgs);
|
||||
va_end(vaArgs);
|
||||
|
||||
if (globalLoggingFunction != nullptr) {
|
||||
globalLoggingFunction(std::string(zc.data(), zc.size()));
|
||||
}
|
||||
}
|
||||
|
||||
void TgVoip::setLoggingFunction(std::function<void(std::string const &)> loggingFunction) {
|
||||
globalLoggingFunction = loggingFunction;
|
||||
}
|
||||
|
||||
void TgVoip::setGlobalServerConfig(const std::string &serverConfig) {
|
||||
tgvoip::ServerConfig::GetSharedInstance()->Update(serverConfig);
|
||||
}
|
||||
|
||||
int TgVoip::getConnectionMaxLayer() {
|
||||
return tgvoip::VoIPController::GetConnectionMaxLayer();
|
||||
}
|
||||
|
||||
std::string TgVoip::getVersion() {
|
||||
return tgvoip::VoIPController::GetVersion();
|
||||
}
|
||||
|
||||
TgVoip *TgVoip::makeInstance(
|
||||
TgVoipConfig const &config,
|
||||
TgVoipPersistentState const &persistentState,
|
||||
std::vector<TgVoipEndpoint> const &endpoints,
|
||||
std::unique_ptr<TgVoipProxy> const &proxy,
|
||||
TgVoipNetworkType initialNetworkType,
|
||||
TgVoipEncryptionKey const &encryptionKey
|
||||
#ifdef TGVOIP_USE_CUSTOM_CRYPTO
|
||||
,
|
||||
TgVoipCrypto const &crypto
|
||||
#endif
|
||||
#ifdef TGVOIP_USE_CALLBACK_AUDIO_IO
|
||||
,
|
||||
TgVoipAudioDataCallbacks const &audioDataCallbacks
|
||||
#endif
|
||||
) {
|
||||
return new TgVoipImpl(
|
||||
endpoints,
|
||||
persistentState,
|
||||
proxy,
|
||||
config,
|
||||
encryptionKey,
|
||||
initialNetworkType
|
||||
#ifdef TGVOIP_USE_CUSTOM_CRYPTO
|
||||
,
|
||||
crypto
|
||||
#endif
|
||||
#ifdef TGVOIP_USE_CALLBACK_AUDIO_IO
|
||||
,
|
||||
audioDataCallbacks
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
TgVoip::~TgVoip() = default;
|
169
TMessagesProj/jni/libtgvoip2/TgVoip.h
Normal file
169
TMessagesProj/jni/libtgvoip2/TgVoip.h
Normal file
|
@ -0,0 +1,169 @@
|
|||
#ifndef __TGVOIP_H
|
||||
#define __TGVOIP_H
|
||||
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
struct TgVoipProxy {
|
||||
std::string host;
|
||||
uint16_t port;
|
||||
std::string login;
|
||||
std::string password;
|
||||
};
|
||||
|
||||
enum class TgVoipEndpointType {
|
||||
Inet,
|
||||
Lan,
|
||||
UdpRelay,
|
||||
TcpRelay
|
||||
};
|
||||
|
||||
struct TgVoipEdpointHost {
|
||||
std::string ipv4;
|
||||
std::string ipv6;
|
||||
};
|
||||
|
||||
struct TgVoipEndpoint {
|
||||
int64_t endpointId;
|
||||
TgVoipEdpointHost host;
|
||||
uint16_t port;
|
||||
TgVoipEndpointType type;
|
||||
unsigned char peerTag[16];
|
||||
};
|
||||
|
||||
enum class TgVoipNetworkType {
|
||||
Unknown,
|
||||
Gprs,
|
||||
Edge,
|
||||
ThirdGeneration,
|
||||
Hspa,
|
||||
Lte,
|
||||
WiFi,
|
||||
Ethernet,
|
||||
OtherHighSpeed,
|
||||
OtherLowSpeed,
|
||||
OtherMobile,
|
||||
Dialup
|
||||
};
|
||||
|
||||
enum class TgVoipDataSaving {
|
||||
Never,
|
||||
Mobile,
|
||||
Always
|
||||
};
|
||||
|
||||
struct TgVoipPersistentState {
|
||||
std::vector<uint8_t> value;
|
||||
};
|
||||
|
||||
#ifdef TGVOIP_USE_CUSTOM_CRYPTO
|
||||
struct TgVoipCrypto {
|
||||
void (*rand_bytes)(uint8_t* buffer, size_t length);
|
||||
void (*sha1)(uint8_t* msg, size_t length, uint8_t* output);
|
||||
void (*sha256)(uint8_t* msg, size_t length, uint8_t* output);
|
||||
void (*aes_ige_encrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv);
|
||||
void (*aes_ige_decrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv);
|
||||
void (*aes_ctr_encrypt)(uint8_t* inout, size_t length, uint8_t* key, uint8_t* iv, uint8_t* ecount, uint32_t* num);
|
||||
void (*aes_cbc_encrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv);
|
||||
void (*aes_cbc_decrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv);
|
||||
};
|
||||
#endif
|
||||
|
||||
struct TgVoipConfig {
|
||||
double initializationTimeout;
|
||||
double receiveTimeout;
|
||||
TgVoipDataSaving dataSaving;
|
||||
bool enableP2P;
|
||||
bool enableAEC;
|
||||
bool enableNS;
|
||||
bool enableAGC;
|
||||
bool enableCallUpgrade;
|
||||
#ifndef _WIN32
|
||||
std::string logPath;
|
||||
#else
|
||||
std::wstring logPath;
|
||||
#endif
|
||||
int maxApiLayer;
|
||||
};
|
||||
|
||||
struct TgVoipEncryptionKey {
|
||||
std::vector<uint8_t> value;
|
||||
bool isOutgoing;
|
||||
};
|
||||
|
||||
enum class TgVoipState {
|
||||
WaitInit,
|
||||
WaitInitAck,
|
||||
Estabilished,
|
||||
Failed,
|
||||
Reconnecting
|
||||
};
|
||||
|
||||
struct TgVoipTrafficStats {
|
||||
uint64_t bytesSentWifi;
|
||||
uint64_t bytesReceivedWifi;
|
||||
uint64_t bytesSentMobile;
|
||||
uint64_t bytesReceivedMobile;
|
||||
};
|
||||
|
||||
struct TgVoipFinalState {
|
||||
TgVoipPersistentState persistentState;
|
||||
std::string debugLog;
|
||||
TgVoipTrafficStats trafficStats;
|
||||
bool isRatingSuggested;
|
||||
};
|
||||
|
||||
struct TgVoipAudioDataCallbacks {
|
||||
std::function<void(int16_t*, size_t)> input;
|
||||
std::function<void(int16_t*, size_t)> output;
|
||||
std::function<void(int16_t*, size_t)> preprocessed;
|
||||
};
|
||||
|
||||
class TgVoip {
|
||||
protected:
|
||||
TgVoip() = default;
|
||||
|
||||
public:
|
||||
static void setLoggingFunction(std::function<void(std::string const &)> loggingFunction);
|
||||
static void setGlobalServerConfig(std::string const &serverConfig);
|
||||
static int getConnectionMaxLayer();
|
||||
static std::string getVersion();
|
||||
static TgVoip *makeInstance(
|
||||
TgVoipConfig const &config,
|
||||
TgVoipPersistentState const &persistentState,
|
||||
std::vector<TgVoipEndpoint> const &endpoints,
|
||||
std::unique_ptr<TgVoipProxy> const &proxy,
|
||||
TgVoipNetworkType initialNetworkType,
|
||||
TgVoipEncryptionKey const &encryptionKey
|
||||
#ifdef TGVOIP_USE_CUSTOM_CRYPTO
|
||||
,
|
||||
TgVoipCrypto const &crypto
|
||||
#endif
|
||||
#ifdef TGVOIP_USE_CALLBACK_AUDIO_IO
|
||||
,
|
||||
TgVoipAudioDataCallbacks const &audioDataCallbacks
|
||||
#endif
|
||||
);
|
||||
|
||||
virtual ~TgVoip();
|
||||
|
||||
virtual void setNetworkType(TgVoipNetworkType networkType) = 0;
|
||||
virtual void setMuteMicrophone(bool muteMicrophone) = 0;
|
||||
virtual void setAudioOutputGainControlEnabled(bool enabled) = 0;
|
||||
virtual void setEchoCancellationStrength(int strength) = 0;
|
||||
|
||||
virtual std::string getLastError() = 0;
|
||||
virtual std::string getDebugInfo() = 0;
|
||||
virtual int64_t getPreferredRelayId() = 0;
|
||||
virtual TgVoipTrafficStats getTrafficStats() = 0;
|
||||
virtual TgVoipPersistentState getPersistentState() = 0;
|
||||
|
||||
virtual void setOnStateUpdated(std::function<void(TgVoipState)> onStateUpdated) = 0;
|
||||
virtual void setOnSignalBarsUpdated(std::function<void(int)> onSignalBarsUpdated) = 0;
|
||||
|
||||
virtual TgVoipFinalState stop() = 0;
|
||||
};
|
||||
|
||||
#endif
|
24
TMessagesProj/jni/libtgvoip2/UNLICENSE
Normal file
24
TMessagesProj/jni/libtgvoip2/UNLICENSE
Normal file
|
@ -0,0 +1,24 @@
|
|||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <http://unlicense.org/>
|
3992
TMessagesProj/jni/libtgvoip2/VoIPController.cpp
Normal file
3992
TMessagesProj/jni/libtgvoip2/VoIPController.cpp
Normal file
File diff suppressed because it is too large
Load diff
887
TMessagesProj/jni/libtgvoip2/VoIPController.h
Normal file
887
TMessagesProj/jni/libtgvoip2/VoIPController.h
Normal file
|
@ -0,0 +1,887 @@
|
|||
//
|
||||
// libtgvoip is free and unencumbered public domain software.
|
||||
// For more information, see http://unlicense.org or the UNLICENSE file
|
||||
// you should have received with this source code distribution.
|
||||
//
|
||||
|
||||
#ifndef __VOIPCONTROLLER_H
|
||||
#define __VOIPCONTROLLER_H
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef __APPLE__
|
||||
#include <TargetConditionals.h>
|
||||
#include "os/darwin/AudioUnitIO.h"
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include "video/VideoSource.h"
|
||||
#include "video/VideoRenderer.h"
|
||||
#include <atomic>
|
||||
#include "video/ScreamCongestionController.h"
|
||||
#include "audio/AudioInput.h"
|
||||
#include "BlockingQueue.h"
|
||||
#include "audio/AudioOutput.h"
|
||||
#include "audio/AudioIO.h"
|
||||
#include "JitterBuffer.h"
|
||||
#include "OpusDecoder.h"
|
||||
#include "OpusEncoder.h"
|
||||
#include "EchoCanceller.h"
|
||||
#include "CongestionControl.h"
|
||||
#include "NetworkSocket.h"
|
||||
#include "Buffers.h"
|
||||
#include "PacketReassembler.h"
|
||||
#include "MessageThread.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define LIBTGVOIP_VERSION "2.6"
|
||||
|
||||
#ifdef _WIN32
|
||||
#undef GetCurrentTime
|
||||
#undef ERROR_TIMEOUT
|
||||
#endif
|
||||
|
||||
#define TGVOIP_PEER_CAP_GROUP_CALLS 1
|
||||
#define TGVOIP_PEER_CAP_VIDEO_CAPTURE 2
|
||||
#define TGVOIP_PEER_CAP_VIDEO_DISPLAY 4
|
||||
|
||||
namespace tgvoip{
|
||||
|
||||
enum{
|
||||
PROXY_NONE=0,
|
||||
PROXY_SOCKS5,
|
||||
//PROXY_HTTP
|
||||
};
|
||||
|
||||
enum{
|
||||
STATE_WAIT_INIT=1,
|
||||
STATE_WAIT_INIT_ACK,
|
||||
STATE_ESTABLISHED,
|
||||
STATE_FAILED,
|
||||
STATE_RECONNECTING
|
||||
};
|
||||
|
||||
enum{
|
||||
ERROR_UNKNOWN=0,
|
||||
ERROR_INCOMPATIBLE,
|
||||
ERROR_TIMEOUT,
|
||||
ERROR_AUDIO_IO,
|
||||
ERROR_PROXY
|
||||
};
|
||||
|
||||
enum{
|
||||
NET_TYPE_UNKNOWN=0,
|
||||
NET_TYPE_GPRS,
|
||||
NET_TYPE_EDGE,
|
||||
NET_TYPE_3G,
|
||||
NET_TYPE_HSPA,
|
||||
NET_TYPE_LTE,
|
||||
NET_TYPE_WIFI,
|
||||
NET_TYPE_ETHERNET,
|
||||
NET_TYPE_OTHER_HIGH_SPEED,
|
||||
NET_TYPE_OTHER_LOW_SPEED,
|
||||
NET_TYPE_DIALUP,
|
||||
NET_TYPE_OTHER_MOBILE
|
||||
};
|
||||
|
||||
enum{
|
||||
DATA_SAVING_NEVER=0,
|
||||
DATA_SAVING_MOBILE,
|
||||
DATA_SAVING_ALWAYS
|
||||
};
|
||||
|
||||
struct CryptoFunctions{
|
||||
void (*rand_bytes)(uint8_t* buffer, size_t length);
|
||||
void (*sha1)(uint8_t* msg, size_t length, uint8_t* output);
|
||||
void (*sha256)(uint8_t* msg, size_t length, uint8_t* output);
|
||||
void (*aes_ige_encrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv);
|
||||
void (*aes_ige_decrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv);
|
||||
void (*aes_ctr_encrypt)(uint8_t* inout, size_t length, uint8_t* key, uint8_t* iv, uint8_t* ecount, uint32_t* num);
|
||||
void (*aes_cbc_encrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv);
|
||||
void (*aes_cbc_decrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv);
|
||||
};
|
||||
|
||||
struct CellularCarrierInfo{
|
||||
std::string name;
|
||||
std::string mcc;
|
||||
std::string mnc;
|
||||
std::string countryCode;
|
||||
};
|
||||
|
||||
// API compatibility
|
||||
struct IPv4Address{
|
||||
IPv4Address(std::string addr) : addr(addr){};
|
||||
std::string addr;
|
||||
};
|
||||
struct IPv6Address{
|
||||
IPv6Address(std::string addr) : addr(addr){};
|
||||
std::string addr;
|
||||
};
|
||||
|
||||
class Endpoint{
|
||||
friend class VoIPController;
|
||||
friend class VoIPGroupController;
|
||||
public:
|
||||
|
||||
enum Type{
|
||||
UDP_P2P_INET=1,
|
||||
UDP_P2P_LAN,
|
||||
UDP_RELAY,
|
||||
TCP_RELAY
|
||||
};
|
||||
|
||||
Endpoint(int64_t id, uint16_t port, const IPv4Address& address, const IPv6Address& v6address, Type type, unsigned char* peerTag);
|
||||
Endpoint(int64_t id, uint16_t port, const NetworkAddress address, const NetworkAddress v6address, Type type, unsigned char* peerTag);
|
||||
Endpoint();
|
||||
~Endpoint();
|
||||
const NetworkAddress& GetAddress() const;
|
||||
NetworkAddress& GetAddress();
|
||||
bool IsIPv6Only() const;
|
||||
int64_t CleanID() const;
|
||||
int64_t id;
|
||||
uint16_t port;
|
||||
NetworkAddress address;
|
||||
NetworkAddress v6address;
|
||||
Type type;
|
||||
unsigned char peerTag[16];
|
||||
|
||||
private:
|
||||
double lastPingTime;
|
||||
uint32_t lastPingSeq;
|
||||
HistoricBuffer<double, 6> rtts;
|
||||
HistoricBuffer<double, 4> selfRtts;
|
||||
std::map<int64_t, double> udpPingTimes;
|
||||
double averageRTT;
|
||||
std::shared_ptr<NetworkSocket> socket;
|
||||
int udpPongCount;
|
||||
int totalUdpPings=0;
|
||||
int totalUdpPingReplies=0;
|
||||
};
|
||||
|
||||
class AudioDevice{
|
||||
public:
|
||||
std::string id;
|
||||
std::string displayName;
|
||||
};
|
||||
|
||||
class AudioOutputDevice : public AudioDevice{
|
||||
|
||||
};
|
||||
|
||||
class AudioInputDevice : public AudioDevice{
|
||||
|
||||
};
|
||||
|
||||
class AudioInputTester{
|
||||
public:
|
||||
AudioInputTester(const std::string deviceID);
|
||||
~AudioInputTester();
|
||||
TGVOIP_DISALLOW_COPY_AND_ASSIGN(AudioInputTester);
|
||||
float GetAndResetLevel();
|
||||
bool Failed(){
|
||||
return io && io->Failed();
|
||||
}
|
||||
private:
|
||||
void Update(int16_t* samples, size_t count);
|
||||
audio::AudioIO* io=NULL;
|
||||
audio::AudioInput* input=NULL;
|
||||
int16_t maxSample=0;
|
||||
std::string deviceID;
|
||||
};
|
||||
|
||||
class PacketSender;
|
||||
namespace video{
|
||||
class VideoPacketSender;
|
||||
}
|
||||
|
||||
class VoIPController{
|
||||
friend class VoIPGroupController;
|
||||
friend class PacketSender;
|
||||
public:
|
||||
TGVOIP_DISALLOW_COPY_AND_ASSIGN(VoIPController);
|
||||
struct Config{
|
||||
Config(double initTimeout=30.0, double recvTimeout=20.0, int dataSaving=DATA_SAVING_NEVER, bool enableAEC=false, bool enableNS=false, bool enableAGC=false, bool enableCallUpgrade=false){
|
||||
this->initTimeout=initTimeout;
|
||||
this->recvTimeout=recvTimeout;
|
||||
this->dataSaving=dataSaving;
|
||||
this->enableAEC=enableAEC;
|
||||
this->enableNS=enableNS;
|
||||
this->enableAGC=enableAGC;
|
||||
this->enableCallUpgrade=enableCallUpgrade;
|
||||
}
|
||||
|
||||
double initTimeout;
|
||||
double recvTimeout;
|
||||
int dataSaving;
|
||||
#ifndef _WIN32
|
||||
std::string logFilePath="";
|
||||
std::string statsDumpFilePath="";
|
||||
#else
|
||||
std::wstring logFilePath=L"";
|
||||
std::wstring statsDumpFilePath=L"";
|
||||
#endif
|
||||
|
||||
bool enableAEC;
|
||||
bool enableNS;
|
||||
bool enableAGC;
|
||||
|
||||
bool enableCallUpgrade;
|
||||
|
||||
bool logPacketStats=false;
|
||||
bool enableVolumeControl=false;
|
||||
|
||||
bool enableVideoSend=false;
|
||||
bool enableVideoReceive=false;
|
||||
};
|
||||
|
||||
struct TrafficStats{
|
||||
uint64_t bytesSentWifi;
|
||||
uint64_t bytesRecvdWifi;
|
||||
uint64_t bytesSentMobile;
|
||||
uint64_t bytesRecvdMobile;
|
||||
};
|
||||
|
||||
|
||||
VoIPController();
|
||||
virtual ~VoIPController();
|
||||
|
||||
/**
|
||||
* Set the initial endpoints (relays)
|
||||
* @param endpoints Endpoints converted from phone.PhoneConnection TL objects
|
||||
* @param allowP2p Whether p2p connectivity is allowed
|
||||
* @param connectionMaxLayer The max_layer field from the phoneCallProtocol object returned by Telegram server.
|
||||
* DO NOT HARDCODE THIS VALUE, it's extremely important for backwards compatibility.
|
||||
*/
|
||||
void SetRemoteEndpoints(std::vector<Endpoint> endpoints, bool allowP2p, int32_t connectionMaxLayer);
|
||||
/**
|
||||
* Initialize and start all the internal threads
|
||||
*/
|
||||
void Start();
|
||||
/**
|
||||
* Stop any internal threads. Don't call any other methods after this.
|
||||
*/
|
||||
void Stop();
|
||||
/**
|
||||
* Initiate connection
|
||||
*/
|
||||
void Connect();
|
||||
Endpoint& GetRemoteEndpoint();
|
||||
/**
|
||||
* Get the debug info string to be displayed in client UI
|
||||
*/
|
||||
virtual std::string GetDebugString();
|
||||
/**
|
||||
* Notify the library of network type change
|
||||
* @param type The new network type
|
||||
*/
|
||||
virtual void SetNetworkType(int type);
|
||||
/**
|
||||
* Get the average round-trip time for network packets
|
||||
* @return
|
||||
*/
|
||||
double GetAverageRTT();
|
||||
static double GetCurrentTime();
|
||||
/**
|
||||
* Use this field to store any of your context data associated with this call
|
||||
*/
|
||||
void* implData;
|
||||
/**
|
||||
*
|
||||
* @param mute
|
||||
*/
|
||||
virtual void SetMicMute(bool mute);
|
||||
/**
|
||||
*
|
||||
* @param key
|
||||
* @param isOutgoing
|
||||
*/
|
||||
void SetEncryptionKey(char* key, bool isOutgoing);
|
||||
/**
|
||||
*
|
||||
* @param cfg
|
||||
*/
|
||||
void SetConfig(const Config& cfg);
|
||||
void DebugCtl(int request, int param);
|
||||
/**
|
||||
*
|
||||
* @param stats
|
||||
*/
|
||||
void GetStats(TrafficStats* stats);
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
int64_t GetPreferredRelayID();
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
int GetLastError();
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static CryptoFunctions crypto;
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
static const char* GetVersion();
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
std::string GetDebugLog();
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
static std::vector<AudioInputDevice> EnumerateAudioInputs();
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
static std::vector<AudioOutputDevice> EnumerateAudioOutputs();
|
||||
/**
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
void SetCurrentAudioInput(std::string id);
|
||||
/**
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
void SetCurrentAudioOutput(std::string id);
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
std::string GetCurrentAudioInputID();
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
std::string GetCurrentAudioOutputID();
|
||||
/**
|
||||
* Set the proxy server to route the data through. Call this before connecting.
|
||||
* @param protocol PROXY_NONE or PROXY_SOCKS5
|
||||
* @param address IP address or domain name of the server
|
||||
* @param port Port of the server
|
||||
* @param username Username; empty string for anonymous
|
||||
* @param password Password; empty string if none
|
||||
*/
|
||||
void SetProxy(int protocol, std::string address, uint16_t port, std::string username, std::string password);
|
||||
/**
|
||||
* Get the number of signal bars to display in the client UI.
|
||||
* @return the number of signal bars, from 1 to 4
|
||||
*/
|
||||
int GetSignalBarsCount();
|
||||
/**
|
||||
* Enable or disable AGC (automatic gain control) on audio output. Should only be enabled on phones when the earpiece speaker is being used.
|
||||
* The audio output will be louder with this on.
|
||||
* AGC with speakerphone or other kinds of loud speakers has detrimental effects on some echo cancellation implementations.
|
||||
* @param enabled I usually pick argument names to be self-explanatory
|
||||
*/
|
||||
void SetAudioOutputGainControlEnabled(bool enabled);
|
||||
/**
|
||||
* Get the additional capabilities of the peer client app
|
||||
* @return corresponding TGVOIP_PEER_CAP_* flags OR'ed together
|
||||
*/
|
||||
uint32_t GetPeerCapabilities();
|
||||
/**
|
||||
* Send the peer the key for the group call to prepare this private call to an upgrade to a E2E group call.
|
||||
* The peer must have the TGVOIP_PEER_CAP_GROUP_CALLS capability. After the peer acknowledges the key, Callbacks::groupCallKeySent will be called.
|
||||
* @param key newly-generated group call key, must be exactly 265 bytes long
|
||||
*/
|
||||
void SendGroupCallKey(unsigned char* key);
|
||||
/**
|
||||
* In an incoming call, request the peer to generate a new encryption key, send it to you and upgrade this call to a E2E group call.
|
||||
*/
|
||||
void RequestCallUpgrade();
|
||||
void SetEchoCancellationStrength(int strength);
|
||||
int GetConnectionState();
|
||||
bool NeedRate();
|
||||
/**
|
||||
* Get the maximum connection layer supported by this libtgvoip version.
|
||||
* Pass this as <code>max_layer</code> in the phone.phoneConnection TL object when requesting and accepting calls.
|
||||
*/
|
||||
static int32_t GetConnectionMaxLayer(){
|
||||
return 92;
|
||||
};
|
||||
/**
|
||||
* Get the persistable state of the library, like proxy capabilities, to save somewhere on the disk. Call this at the end of the call.
|
||||
* Using this will speed up the connection establishment in some cases.
|
||||
*/
|
||||
std::vector<uint8_t> GetPersistentState();
|
||||
/**
|
||||
* Load the persistable state. Call this before starting the call.
|
||||
*/
|
||||
void SetPersistentState(std::vector<uint8_t> state);
|
||||
|
||||
#if defined(TGVOIP_USE_CALLBACK_AUDIO_IO)
|
||||
void SetAudioDataCallbacks(std::function<void(int16_t*, size_t)> input, std::function<void(int16_t*, size_t)> output, std::function<void(int16_t*, size_t)> preprocessed);
|
||||
#endif
|
||||
|
||||
void SetVideoCodecSpecificData(const std::vector<Buffer>& data);
|
||||
|
||||
struct Callbacks{
|
||||
void (*connectionStateChanged)(VoIPController*, int);
|
||||
void (*signalBarCountChanged)(VoIPController*, int);
|
||||
void (*groupCallKeySent)(VoIPController*);
|
||||
void (*groupCallKeyReceived)(VoIPController*, const unsigned char*);
|
||||
void (*upgradeToGroupCallRequested)(VoIPController*);
|
||||
};
|
||||
void SetCallbacks(Callbacks callbacks);
|
||||
|
||||
float GetOutputLevel(){
|
||||
return 0.0f;
|
||||
};
|
||||
void SetVideoSource(video::VideoSource* source);
|
||||
void SetVideoRenderer(video::VideoRenderer* renderer);
|
||||
|
||||
void SetInputVolume(float level);
|
||||
void SetOutputVolume(float level);
|
||||
#if defined(__APPLE__) && defined(TARGET_OS_OSX)
|
||||
void SetAudioOutputDuckingEnabled(bool enabled);
|
||||
#endif
|
||||
|
||||
struct PendingOutgoingPacket{
|
||||
PendingOutgoingPacket(uint32_t seq, unsigned char type, size_t len, Buffer&& data, int64_t endpoint){
|
||||
this->seq=seq;
|
||||
this->type=type;
|
||||
this->len=len;
|
||||
this->data=std::move(data);
|
||||
this->endpoint=endpoint;
|
||||
}
|
||||
PendingOutgoingPacket(PendingOutgoingPacket&& other){
|
||||
seq=other.seq;
|
||||
type=other.type;
|
||||
len=other.len;
|
||||
data=std::move(other.data);
|
||||
endpoint=other.endpoint;
|
||||
}
|
||||
PendingOutgoingPacket& operator=(PendingOutgoingPacket&& other){
|
||||
if(this!=&other){
|
||||
seq=other.seq;
|
||||
type=other.type;
|
||||
len=other.len;
|
||||
data=std::move(other.data);
|
||||
endpoint=other.endpoint;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
TGVOIP_DISALLOW_COPY_AND_ASSIGN(PendingOutgoingPacket);
|
||||
uint32_t seq;
|
||||
unsigned char type;
|
||||
size_t len;
|
||||
Buffer data;
|
||||
int64_t endpoint;
|
||||
};
|
||||
|
||||
struct Stream{
|
||||
int32_t userID;
|
||||
unsigned char id;
|
||||
unsigned char type;
|
||||
uint32_t codec;
|
||||
bool enabled;
|
||||
bool extraECEnabled;
|
||||
uint16_t frameDuration;
|
||||
std::shared_ptr<JitterBuffer> jitterBuffer;
|
||||
std::shared_ptr<OpusDecoder> decoder;
|
||||
std::shared_ptr<PacketReassembler> packetReassembler;
|
||||
std::shared_ptr<CallbackWrapper> callbackWrapper;
|
||||
std::vector<Buffer> codecSpecificData;
|
||||
bool csdIsValid=false;
|
||||
bool paused=false;
|
||||
int resolution;
|
||||
unsigned int width=0;
|
||||
unsigned int height=0;
|
||||
uint16_t rotation=0;
|
||||
};
|
||||
|
||||
struct ProtocolInfo{
|
||||
uint32_t version;
|
||||
uint32_t maxVideoResolution;
|
||||
std::vector<uint32_t> videoDecoders;
|
||||
bool videoCaptureSupported;
|
||||
bool videoDisplaySupported;
|
||||
bool callUpgradeSupported;
|
||||
};
|
||||
|
||||
private:
|
||||
struct UnacknowledgedExtraData;
|
||||
|
||||
protected:
|
||||
struct RecentOutgoingPacket{
|
||||
uint32_t seq;
|
||||
uint16_t id; // for group calls only
|
||||
double sendTime;
|
||||
double ackTime;
|
||||
uint8_t type;
|
||||
uint32_t size;
|
||||
PacketSender* sender;
|
||||
bool lost;
|
||||
};
|
||||
struct QueuedPacket{
|
||||
Buffer data;
|
||||
unsigned char type;
|
||||
HistoricBuffer<uint32_t, 16> seqs;
|
||||
double firstSentTime;
|
||||
double lastSentTime;
|
||||
double retryInterval;
|
||||
double timeout;
|
||||
};
|
||||
virtual void ProcessIncomingPacket(NetworkPacket& packet, Endpoint& srcEndpoint);
|
||||
virtual void ProcessExtraData(Buffer& data);
|
||||
virtual void WritePacketHeader(uint32_t seq, BufferOutputStream* s, unsigned char type, uint32_t length, PacketSender* source);
|
||||
virtual void SendPacket(unsigned char* data, size_t len, Endpoint& ep, PendingOutgoingPacket& srcPacket);
|
||||
virtual void SendInit();
|
||||
virtual void SendUdpPing(Endpoint& endpoint);
|
||||
virtual void SendRelayPings();
|
||||
virtual void OnAudioOutputReady();
|
||||
virtual void SendExtra(Buffer& data, unsigned char type);
|
||||
void SendStreamFlags(Stream& stream);
|
||||
void InitializeTimers();
|
||||
void ResetEndpointPingStats();
|
||||
void SendVideoFrame(const Buffer& frame, uint32_t flags, uint32_t rotation);
|
||||
void ProcessIncomingVideoFrame(Buffer frame, uint32_t pts, bool keyframe, uint16_t rotation);
|
||||
std::shared_ptr<Stream> GetStreamByType(int type, bool outgoing);
|
||||
std::shared_ptr<Stream> GetStreamByID(unsigned char id, bool outgoing);
|
||||
Endpoint* GetEndpointForPacket(const PendingOutgoingPacket& pkt);
|
||||
bool SendOrEnqueuePacket(PendingOutgoingPacket pkt, bool enqueue=true, PacketSender* source=NULL);
|
||||
static std::string NetworkTypeToString(int type);
|
||||
CellularCarrierInfo GetCarrierInfo();
|
||||
|
||||
private:
|
||||
struct UnacknowledgedExtraData{
|
||||
unsigned char type;
|
||||
Buffer data;
|
||||
uint32_t firstContainingSeq;
|
||||
};
|
||||
struct RecentIncomingPacket{
|
||||
uint32_t seq;
|
||||
double recvTime;
|
||||
};
|
||||
enum{
|
||||
UDP_UNKNOWN=0,
|
||||
UDP_PING_PENDING,
|
||||
UDP_PING_SENT,
|
||||
UDP_AVAILABLE,
|
||||
UDP_NOT_AVAILABLE,
|
||||
UDP_BAD
|
||||
};
|
||||
struct DebugLoggedPacket{
|
||||
int32_t seq;
|
||||
double timestamp;
|
||||
int32_t length;
|
||||
};
|
||||
struct RawPendingOutgoingPacket{
|
||||
TGVOIP_MOVE_ONLY(RawPendingOutgoingPacket);
|
||||
NetworkPacket packet;
|
||||
std::shared_ptr<NetworkSocket> socket;
|
||||
};
|
||||
|
||||
void RunRecvThread();
|
||||
void RunSendThread();
|
||||
void HandleAudioInput(unsigned char* data, size_t len, unsigned char* secondaryData, size_t secondaryLen);
|
||||
void UpdateAudioBitrateLimit();
|
||||
void SetState(int state);
|
||||
void UpdateAudioOutputState();
|
||||
void InitUDPProxy();
|
||||
void UpdateDataSavingState();
|
||||
void KDF(unsigned char* msgKey, size_t x, unsigned char* aesKey, unsigned char* aesIv);
|
||||
void KDF2(unsigned char* msgKey, size_t x, unsigned char* aesKey, unsigned char* aesIv);
|
||||
void SendPublicEndpointsRequest();
|
||||
void SendPublicEndpointsRequest(const Endpoint& relay);
|
||||
Endpoint& GetEndpointByType(int type);
|
||||
void SendPacketReliably(unsigned char type, unsigned char* data, size_t len, double retryInterval, double timeout);
|
||||
uint32_t GenerateOutSeq();
|
||||
void ActuallySendPacket(NetworkPacket pkt, Endpoint& ep);
|
||||
void InitializeAudio();
|
||||
void StartAudio();
|
||||
void ProcessAcknowledgedOutgoingExtra(UnacknowledgedExtraData& extra);
|
||||
void AddIPv6Relays();
|
||||
void AddTCPRelays();
|
||||
void SendUdpPings();
|
||||
void EvaluateUdpPingResults();
|
||||
void UpdateRTT();
|
||||
void UpdateCongestion();
|
||||
void UpdateAudioBitrate();
|
||||
void UpdateSignalBars();
|
||||
void UpdateQueuedPackets();
|
||||
void SendNopPacket();
|
||||
void TickJitterBufferAndCongestionControl();
|
||||
void ResetUdpAvailability();
|
||||
std::string GetPacketTypeString(unsigned char type);
|
||||
void SetupOutgoingVideoStream();
|
||||
bool WasOutgoingPacketAcknowledged(uint32_t seq);
|
||||
RecentOutgoingPacket* GetRecentOutgoingPacket(uint32_t seq);
|
||||
void NetworkPacketReceived(std::shared_ptr<NetworkPacket> packet);
|
||||
void TrySendQueuedPackets();
|
||||
|
||||
int state;
|
||||
std::map<int64_t, Endpoint> endpoints;
|
||||
int64_t currentEndpoint=0;
|
||||
int64_t preferredRelay=0;
|
||||
int64_t peerPreferredRelay=0;
|
||||
std::atomic<bool> runReceiver;
|
||||
std::atomic<uint32_t> seq;
|
||||
uint32_t lastRemoteSeq;
|
||||
uint32_t lastRemoteAckSeq;
|
||||
uint32_t lastSentSeq;
|
||||
std::vector<RecentOutgoingPacket> recentOutgoingPackets;
|
||||
std::vector<uint32_t> recentIncomingPackets;
|
||||
HistoricBuffer<uint32_t, 10, double> sendLossCountHistory;
|
||||
uint32_t audioTimestampIn;
|
||||
uint32_t audioTimestampOut;
|
||||
tgvoip::audio::AudioIO* audioIO=NULL;
|
||||
tgvoip::audio::AudioInput* audioInput=NULL;
|
||||
tgvoip::audio::AudioOutput* audioOutput=NULL;
|
||||
OpusEncoder* encoder;
|
||||
std::vector<PendingOutgoingPacket> sendQueue;
|
||||
EchoCanceller* echoCanceller;
|
||||
std::atomic<bool> stopping;
|
||||
bool audioOutStarted;
|
||||
Thread* recvThread;
|
||||
Thread* sendThread;
|
||||
uint32_t packetsReceived;
|
||||
uint32_t recvLossCount;
|
||||
uint32_t prevSendLossCount;
|
||||
uint32_t firstSentPing;
|
||||
HistoricBuffer<double, 32> rttHistory;
|
||||
bool waitingForAcks;
|
||||
int networkType;
|
||||
int dontSendPackets;
|
||||
int lastError;
|
||||
bool micMuted;
|
||||
uint32_t maxBitrate;
|
||||
std::vector<std::shared_ptr<Stream>> outgoingStreams;
|
||||
std::vector<std::shared_ptr<Stream>> incomingStreams;
|
||||
unsigned char encryptionKey[256];
|
||||
unsigned char keyFingerprint[8];
|
||||
unsigned char callID[16];
|
||||
double stateChangeTime;
|
||||
bool waitingForRelayPeerInfo;
|
||||
bool allowP2p;
|
||||
bool dataSavingMode;
|
||||
bool dataSavingRequestedByPeer;
|
||||
std::string activeNetItfName;
|
||||
double publicEndpointsReqTime;
|
||||
std::vector<QueuedPacket> queuedPackets;
|
||||
double connectionInitTime;
|
||||
double lastRecvPacketTime;
|
||||
Config config;
|
||||
int32_t peerVersion;
|
||||
CongestionControl* conctl;
|
||||
TrafficStats stats;
|
||||
bool receivedInit;
|
||||
bool receivedInitAck;
|
||||
bool isOutgoing;
|
||||
NetworkSocket* udpSocket;
|
||||
NetworkSocket* realUdpSocket;
|
||||
FILE* statsDump;
|
||||
std::string currentAudioInput;
|
||||
std::string currentAudioOutput;
|
||||
bool useTCP;
|
||||
bool useUDP;
|
||||
bool didAddTcpRelays;
|
||||
SocketSelectCanceller* selectCanceller;
|
||||
HistoricBuffer<unsigned char, 4, int> signalBarsHistory;
|
||||
bool audioStarted=false;
|
||||
|
||||
int udpConnectivityState;
|
||||
double lastUdpPingTime;
|
||||
int udpPingCount;
|
||||
int echoCancellationStrength;
|
||||
|
||||
int proxyProtocol;
|
||||
std::string proxyAddress;
|
||||
uint16_t proxyPort;
|
||||
std::string proxyUsername;
|
||||
std::string proxyPassword;
|
||||
NetworkAddress resolvedProxyAddress=NetworkAddress::Empty();
|
||||
|
||||
uint32_t peerCapabilities;
|
||||
Callbacks callbacks;
|
||||
bool didReceiveGroupCallKey;
|
||||
bool didReceiveGroupCallKeyAck;
|
||||
bool didSendGroupCallKey;
|
||||
bool didSendUpgradeRequest;
|
||||
bool didInvokeUpgradeCallback;
|
||||
|
||||
int32_t connectionMaxLayer;
|
||||
bool useMTProto2;
|
||||
bool setCurrentEndpointToTCP;
|
||||
|
||||
std::vector<UnacknowledgedExtraData> currentExtras;
|
||||
std::unordered_map<uint8_t, uint64_t> lastReceivedExtrasByType;
|
||||
bool useIPv6;
|
||||
bool peerIPv6Available;
|
||||
NetworkAddress myIPv6=NetworkAddress::Empty();
|
||||
bool shittyInternetMode;
|
||||
int extraEcLevel=0;
|
||||
std::vector<Buffer> ecAudioPackets;
|
||||
bool didAddIPv6Relays;
|
||||
bool didSendIPv6Endpoint;
|
||||
int publicEndpointsReqCount=0;
|
||||
bool wasEstablished=false;
|
||||
bool receivedFirstStreamPacket=false;
|
||||
std::atomic<unsigned int> unsentStreamPackets;
|
||||
HistoricBuffer<unsigned int, 5> unsentStreamPacketsHistory;
|
||||
bool needReInitUdpProxy=true;
|
||||
bool needRate=false;
|
||||
std::vector<DebugLoggedPacket> debugLoggedPackets;
|
||||
BufferPool<1024, 32> outgoingAudioBufferPool;
|
||||
BlockingQueue<RawPendingOutgoingPacket> rawSendQueue;
|
||||
|
||||
uint32_t initTimeoutID=MessageThread::INVALID_ID;
|
||||
uint32_t udpPingTimeoutID=MessageThread::INVALID_ID;
|
||||
|
||||
effects::Volume outputVolume;
|
||||
effects::Volume inputVolume;
|
||||
|
||||
std::vector<uint32_t> peerVideoDecoders;
|
||||
|
||||
MessageThread messageThread;
|
||||
|
||||
// Locked whenever the endpoints vector is modified (but not endpoints themselves) and whenever iterated outside of messageThread.
|
||||
// After the call is started, only messageThread is allowed to modify the endpoints vector.
|
||||
Mutex endpointsMutex;
|
||||
// Locked while audio i/o is being initialized and deinitialized so as to allow it to fully initialize before deinitialization begins.
|
||||
Mutex audioIOMutex;
|
||||
|
||||
#if defined(TGVOIP_USE_CALLBACK_AUDIO_IO)
|
||||
std::function<void(int16_t*, size_t)> audioInputDataCallback;
|
||||
std::function<void(int16_t*, size_t)> audioOutputDataCallback;
|
||||
std::function<void(int16_t*, size_t)> audioPreprocDataCallback;
|
||||
::OpusDecoder* preprocDecoder=nullptr;
|
||||
int16_t preprocBuffer[4096];
|
||||
#endif
|
||||
#if defined(__APPLE__) && defined(TARGET_OS_OSX)
|
||||
bool macAudioDuckingEnabled=true;
|
||||
#endif
|
||||
|
||||
video::VideoSource* videoSource=NULL;
|
||||
video::VideoRenderer* videoRenderer=NULL;
|
||||
uint32_t lastReceivedVideoFrameNumber=UINT32_MAX;
|
||||
|
||||
video::VideoPacketSender* videoPacketSender=NULL;
|
||||
uint32_t sendLosses=0;
|
||||
uint32_t unacknowledgedIncomingPacketCount=0;
|
||||
|
||||
ProtocolInfo protocolInfo={0};
|
||||
|
||||
/*** debug report problems ***/
|
||||
bool wasReconnecting=false;
|
||||
bool wasExtraEC=false;
|
||||
bool wasEncoderLaggy=false;
|
||||
bool wasNetworkHandover=false;
|
||||
|
||||
/*** persistable state values ***/
|
||||
bool proxySupportsUDP=true;
|
||||
bool proxySupportsTCP=true;
|
||||
std::string lastTestedProxyServer="";
|
||||
|
||||
/*** server config values ***/
|
||||
uint32_t maxAudioBitrate;
|
||||
uint32_t maxAudioBitrateEDGE;
|
||||
uint32_t maxAudioBitrateGPRS;
|
||||
uint32_t maxAudioBitrateSaving;
|
||||
uint32_t initAudioBitrate;
|
||||
uint32_t initAudioBitrateEDGE;
|
||||
uint32_t initAudioBitrateGPRS;
|
||||
uint32_t initAudioBitrateSaving;
|
||||
uint32_t minAudioBitrate;
|
||||
uint32_t audioBitrateStepIncr;
|
||||
uint32_t audioBitrateStepDecr;
|
||||
double relaySwitchThreshold;
|
||||
double p2pToRelaySwitchThreshold;
|
||||
double relayToP2pSwitchThreshold;
|
||||
double reconnectingTimeout;
|
||||
uint32_t needRateFlags;
|
||||
double rateMaxAcceptableRTT;
|
||||
double rateMaxAcceptableSendLoss;
|
||||
double packetLossToEnableExtraEC;
|
||||
uint32_t maxUnsentStreamPackets;
|
||||
uint32_t unackNopThreshold;
|
||||
|
||||
public:
|
||||
#ifdef __APPLE__
|
||||
static double machTimebase;
|
||||
static uint64_t machTimestart;
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
static int64_t win32TimeScale;
|
||||
static bool didInitWin32TimeScale;
|
||||
#endif
|
||||
};
|
||||
|
||||
class VoIPGroupController : public VoIPController{
|
||||
public:
|
||||
VoIPGroupController(int32_t timeDifference);
|
||||
virtual ~VoIPGroupController();
|
||||
void SetGroupCallInfo(unsigned char* encryptionKey, unsigned char* reflectorGroupTag, unsigned char* reflectorSelfTag, unsigned char* reflectorSelfSecret, unsigned char* reflectorSelfTagHash, int32_t selfUserID, NetworkAddress reflectorAddress, NetworkAddress reflectorAddressV6, uint16_t reflectorPort);
|
||||
void AddGroupCallParticipant(int32_t userID, unsigned char* memberTagHash, unsigned char* serializedStreams, size_t streamsLength);
|
||||
void RemoveGroupCallParticipant(int32_t userID);
|
||||
float GetParticipantAudioLevel(int32_t userID);
|
||||
virtual void SetMicMute(bool mute);
|
||||
void SetParticipantVolume(int32_t userID, float volume);
|
||||
void SetParticipantStreams(int32_t userID, unsigned char* serializedStreams, size_t length);
|
||||
static size_t GetInitialStreams(unsigned char* buf, size_t size);
|
||||
|
||||
struct Callbacks : public VoIPController::Callbacks{
|
||||
void (*updateStreams)(VoIPGroupController*, unsigned char*, size_t);
|
||||
void (*participantAudioStateChanged)(VoIPGroupController*, int32_t, bool);
|
||||
|
||||
};
|
||||
void SetCallbacks(Callbacks callbacks);
|
||||
virtual std::string GetDebugString();
|
||||
virtual void SetNetworkType(int type);
|
||||
protected:
|
||||
virtual void ProcessIncomingPacket(NetworkPacket& packet, Endpoint& srcEndpoint);
|
||||
virtual void SendInit();
|
||||
virtual void SendUdpPing(Endpoint& endpoint);
|
||||
virtual void SendRelayPings();
|
||||
virtual void SendPacket(unsigned char* data, size_t len, Endpoint& ep, PendingOutgoingPacket& srcPacket);
|
||||
virtual void WritePacketHeader(uint32_t seq, BufferOutputStream* s, unsigned char type, uint32_t length, PacketSender* sender=NULL);
|
||||
virtual void OnAudioOutputReady();
|
||||
private:
|
||||
int32_t GetCurrentUnixtime();
|
||||
std::vector<std::shared_ptr<Stream>> DeserializeStreams(BufferInputStream& in);
|
||||
void SendRecentPacketsRequest();
|
||||
void SendSpecialReflectorRequest(unsigned char* data, size_t len);
|
||||
void SerializeAndUpdateOutgoingStreams();
|
||||
struct GroupCallParticipant{
|
||||
int32_t userID;
|
||||
unsigned char memberTagHash[32];
|
||||
std::vector<std::shared_ptr<Stream>> streams;
|
||||
AudioLevelMeter* levelMeter;
|
||||
};
|
||||
std::vector<GroupCallParticipant> participants;
|
||||
unsigned char reflectorSelfTag[16];
|
||||
unsigned char reflectorSelfSecret[16];
|
||||
unsigned char reflectorSelfTagHash[32];
|
||||
int32_t userSelfID;
|
||||
Endpoint groupReflector;
|
||||
AudioMixer* audioMixer;
|
||||
AudioLevelMeter selfLevelMeter;
|
||||
Callbacks groupCallbacks;
|
||||
struct PacketIdMapping{
|
||||
uint32_t seq;
|
||||
uint16_t id;
|
||||
double ackTime;
|
||||
};
|
||||
std::vector<PacketIdMapping> recentSentPackets;
|
||||
Mutex sentPacketsMutex;
|
||||
Mutex participantsMutex;
|
||||
int32_t timeDifference;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
816
TMessagesProj/jni/libtgvoip2/VoIPGroupController.cpp
Normal file
816
TMessagesProj/jni/libtgvoip2/VoIPGroupController.cpp
Normal file
|
@ -0,0 +1,816 @@
|
|||
//
|
||||
// libtgvoip is free and unencumbered public domain software.
|
||||
// For more information, see http://unlicense.org or the UNLICENSE file
|
||||
// you should have received with this source code distribution.
|
||||
//
|
||||
|
||||
#include "VoIPController.h"
|
||||
#include "logging.h"
|
||||
#include "VoIPServerConfig.h"
|
||||
#include "PrivateDefines.h"
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
|
||||
using namespace tgvoip;
|
||||
using namespace std;
|
||||
|
||||
VoIPGroupController::VoIPGroupController(int32_t timeDifference){
|
||||
audioMixer=new AudioMixer();
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
userSelfID=0;
|
||||
this->timeDifference=timeDifference;
|
||||
LOGV("Created VoIPGroupController; timeDifference=%d", timeDifference);
|
||||
}
|
||||
|
||||
VoIPGroupController::~VoIPGroupController(){
|
||||
if(audioOutput){
|
||||
audioOutput->Stop();
|
||||
}
|
||||
LOGD("before stop audio mixer");
|
||||
audioMixer->Stop();
|
||||
delete audioMixer;
|
||||
|
||||
for(vector<GroupCallParticipant>::iterator p=participants.begin();p!=participants.end();p++){
|
||||
if(p->levelMeter)
|
||||
delete p->levelMeter;
|
||||
}
|
||||
}
|
||||
|
||||
void VoIPGroupController::SetGroupCallInfo(unsigned char *encryptionKey, unsigned char *reflectorGroupTag, unsigned char *reflectorSelfTag, unsigned char *reflectorSelfSecret, unsigned char* reflectorSelfTagHash, int32_t selfUserID, NetworkAddress reflectorAddress, NetworkAddress reflectorAddressV6, uint16_t reflectorPort){
|
||||
Endpoint e;
|
||||
e.address=reflectorAddress;
|
||||
e.v6address=reflectorAddressV6;
|
||||
e.port=reflectorPort;
|
||||
memcpy(e.peerTag, reflectorGroupTag, 16);
|
||||
e.type=Endpoint::Type::UDP_RELAY;
|
||||
e.id=FOURCC('G','R','P','R');
|
||||
endpoints[e.id]=e;
|
||||
groupReflector=e;
|
||||
currentEndpoint=e.id;
|
||||
|
||||
memcpy(this->encryptionKey, encryptionKey, 256);
|
||||
memcpy(this->reflectorSelfTag, reflectorSelfTag, 16);
|
||||
memcpy(this->reflectorSelfSecret, reflectorSelfSecret, 16);
|
||||
memcpy(this->reflectorSelfTagHash, reflectorSelfTagHash, 16);
|
||||
uint8_t sha256[SHA256_LENGTH];
|
||||
crypto.sha256((uint8_t*) encryptionKey, 256, sha256);
|
||||
memcpy(callID, sha256+(SHA256_LENGTH-16), 16);
|
||||
memcpy(keyFingerprint, sha256+(SHA256_LENGTH-16), 8);
|
||||
this->userSelfID=selfUserID;
|
||||
|
||||
//LOGD("reflectorSelfTag = %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", reflectorSelfTag[0], reflectorSelfTag[1], reflectorSelfTag[2], reflectorSelfTag[3], reflectorSelfTag[4], reflectorSelfTag[5], reflectorSelfTag[6], reflectorSelfTag[7], reflectorSelfTag[8], reflectorSelfTag[9], reflectorSelfTag[10], reflectorSelfTag[11], reflectorSelfTag[12], reflectorSelfTag[13], reflectorSelfTag[14], reflectorSelfTag[15]);
|
||||
//LOGD("reflectorSelfSecret = %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", reflectorSelfSecret[0], reflectorSelfSecret[1], reflectorSelfSecret[2], reflectorSelfSecret[3], reflectorSelfSecret[4], reflectorSelfSecret[5], reflectorSelfSecret[6], reflectorSelfSecret[7], reflectorSelfSecret[8], reflectorSelfSecret[9], reflectorSelfSecret[10], reflectorSelfSecret[11], reflectorSelfSecret[12], reflectorSelfSecret[13], reflectorSelfSecret[14], reflectorSelfSecret[15]);
|
||||
//LOGD("reflectorSelfTagHash = %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", reflectorSelfTagHash[0], reflectorSelfTagHash[1], reflectorSelfTagHash[2], reflectorSelfTagHash[3], reflectorSelfTagHash[4], reflectorSelfTagHash[5], reflectorSelfTagHash[6], reflectorSelfTagHash[7], reflectorSelfTagHash[8], reflectorSelfTagHash[9], reflectorSelfTagHash[10], reflectorSelfTagHash[11], reflectorSelfTagHash[12], reflectorSelfTagHash[13], reflectorSelfTagHash[14], reflectorSelfTagHash[15]);
|
||||
}
|
||||
|
||||
void VoIPGroupController::AddGroupCallParticipant(int32_t userID, unsigned char *memberTagHash, unsigned char* serializedStreams, size_t streamsLength){
|
||||
if(userID==userSelfID)
|
||||
return;
|
||||
if(userSelfID==0)
|
||||
return;
|
||||
//if(streamsLength==0)
|
||||
// return;
|
||||
MutexGuard m(participantsMutex);
|
||||
LOGV("Adding group call user %d, streams length %u", userID, (unsigned int)streamsLength);
|
||||
|
||||
for(vector<GroupCallParticipant>::iterator p=participants.begin();p!=participants.end();++p){
|
||||
if(p->userID==userID){
|
||||
LOGE("user %d already added", userID);
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GroupCallParticipant p;
|
||||
p.userID=userID;
|
||||
memcpy(p.memberTagHash, memberTagHash, sizeof(p.memberTagHash));
|
||||
p.levelMeter=new AudioLevelMeter();
|
||||
|
||||
BufferInputStream ss(serializedStreams, streamsLength);
|
||||
vector<shared_ptr<Stream>> streams=DeserializeStreams(ss);
|
||||
|
||||
unsigned char audioStreamID=0;
|
||||
|
||||
for(vector<shared_ptr<Stream>>::iterator _s=streams.begin();_s!=streams.end();++_s){
|
||||
shared_ptr<Stream>& s=*_s;
|
||||
s->userID=userID;
|
||||
if(s->type==STREAM_TYPE_AUDIO && s->codec==CODEC_OPUS && !audioStreamID){
|
||||
audioStreamID=s->id;
|
||||
s->jitterBuffer=make_shared<JitterBuffer>(nullptr, s->frameDuration);
|
||||
if(s->frameDuration>50)
|
||||
s->jitterBuffer->SetMinPacketCount((uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_initial_delay_60", 2));
|
||||
else if(s->frameDuration>30)
|
||||
s->jitterBuffer->SetMinPacketCount((uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_initial_delay_40", 4));
|
||||
else
|
||||
s->jitterBuffer->SetMinPacketCount((uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_initial_delay_20", 6));
|
||||
s->callbackWrapper=make_shared<CallbackWrapper>();
|
||||
s->decoder=make_shared<OpusDecoder>(s->callbackWrapper, false, false);
|
||||
s->decoder->SetJitterBuffer(s->jitterBuffer);
|
||||
s->decoder->SetFrameDuration(s->frameDuration);
|
||||
s->decoder->SetDTX(true);
|
||||
s->decoder->SetLevelMeter(p.levelMeter);
|
||||
audioMixer->AddInput(s->callbackWrapper);
|
||||
}
|
||||
incomingStreams.push_back(s);
|
||||
}
|
||||
|
||||
if(!audioStreamID){
|
||||
LOGW("User %d has no usable audio stream", userID);
|
||||
}
|
||||
|
||||
p.streams.insert(p.streams.end(), streams.begin(), streams.end());
|
||||
participants.push_back(p);
|
||||
LOGI("Added group call participant %d", userID);
|
||||
}
|
||||
|
||||
void VoIPGroupController::RemoveGroupCallParticipant(int32_t userID){
|
||||
MutexGuard m(participantsMutex);
|
||||
vector<shared_ptr<Stream>>::iterator stm=incomingStreams.begin();
|
||||
while(stm!=incomingStreams.end()){
|
||||
if((*stm)->userID==userID){
|
||||
LOGI("Removed stream %d belonging to user %d", (*stm)->id, userID);
|
||||
audioMixer->RemoveInput((*stm)->callbackWrapper);
|
||||
(*stm)->decoder->Stop();
|
||||
//delete (*stm)->decoder;
|
||||
//delete (*stm)->jitterBuffer;
|
||||
//delete (*stm)->callbackWrapper;
|
||||
stm=incomingStreams.erase(stm);
|
||||
continue;
|
||||
}
|
||||
++stm;
|
||||
}
|
||||
for(vector<GroupCallParticipant>::iterator p=participants.begin();p!=participants.end();++p){
|
||||
if(p->userID==userID){
|
||||
if(p->levelMeter)
|
||||
delete p->levelMeter;
|
||||
participants.erase(p);
|
||||
LOGI("Removed group call participant %d", userID);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vector<shared_ptr<VoIPController::Stream>> VoIPGroupController::DeserializeStreams(BufferInputStream& in){
|
||||
vector<shared_ptr<Stream>> res;
|
||||
try{
|
||||
unsigned char count=in.ReadByte();
|
||||
for(unsigned char i=0;i<count;i++){
|
||||
uint16_t len=(uint16_t) in.ReadInt16();
|
||||
BufferInputStream inner=in.GetPartBuffer(len, true);
|
||||
shared_ptr<Stream> s=make_shared<Stream>();
|
||||
s->id=inner.ReadByte();
|
||||
s->type=inner.ReadByte();
|
||||
s->codec=(uint32_t) inner.ReadInt32();
|
||||
uint32_t flags=(uint32_t) inner.ReadInt32();
|
||||
s->enabled=(flags & STREAM_FLAG_ENABLED)==STREAM_FLAG_ENABLED;
|
||||
s->frameDuration=(uint16_t) inner.ReadInt16();
|
||||
res.push_back(s);
|
||||
}
|
||||
}catch(out_of_range& x){
|
||||
LOGW("Error deserializing streams: %s", x.what());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void VoIPGroupController::SetParticipantStreams(int32_t userID, unsigned char *serializedStreams, size_t length){
|
||||
LOGD("Set participant streams for %d", userID);
|
||||
MutexGuard m(participantsMutex);
|
||||
for(vector<GroupCallParticipant>::iterator p=participants.begin();p!=participants.end();++p){
|
||||
if(p->userID==userID){
|
||||
BufferInputStream in(serializedStreams, length);
|
||||
vector<shared_ptr<Stream>> streams=DeserializeStreams(in);
|
||||
for(vector<shared_ptr<Stream>>::iterator ns=streams.begin();ns!=streams.end();++ns){
|
||||
bool found=false;
|
||||
for(vector<shared_ptr<Stream>>::iterator s=p->streams.begin();s!=p->streams.end();++s){
|
||||
if((*s)->id==(*ns)->id){
|
||||
(*s)->enabled=(*ns)->enabled;
|
||||
if(groupCallbacks.participantAudioStateChanged)
|
||||
groupCallbacks.participantAudioStateChanged(this, userID, (*s)->enabled);
|
||||
found=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!found){
|
||||
LOGW("Tried to add stream %d for user %d but adding/removing streams is not supported", (*ns)->id, userID);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t VoIPGroupController::GetInitialStreams(unsigned char *buf, size_t size){
|
||||
BufferOutputStream s(buf, size);
|
||||
s.WriteByte(1); // streams count
|
||||
|
||||
s.WriteInt16(12); // this object length
|
||||
s.WriteByte(1); // stream id
|
||||
s.WriteByte(STREAM_TYPE_AUDIO);
|
||||
s.WriteInt32(CODEC_OPUS);
|
||||
s.WriteInt32(STREAM_FLAG_ENABLED | STREAM_FLAG_DTX); // flags
|
||||
s.WriteInt16(60); // frame duration
|
||||
|
||||
return s.GetLength();
|
||||
}
|
||||
|
||||
void VoIPGroupController::SendInit(){
|
||||
SendRecentPacketsRequest();
|
||||
}
|
||||
|
||||
void VoIPGroupController::ProcessIncomingPacket(NetworkPacket &packet, Endpoint& srcEndpoint){
|
||||
//LOGD("Received incoming packet from %s:%u, %u bytes", packet.address->ToString().c_str(), packet.port, packet.length);
|
||||
/*if(packet.length<17 || packet.length>2000){
|
||||
LOGW("Received packet has wrong length %d", (int)packet.length);
|
||||
return;
|
||||
}
|
||||
BufferOutputStream sigData(packet.length);
|
||||
sigData.WriteBytes(packet.data, packet.length-16);
|
||||
sigData.WriteBytes(reflectorSelfSecret, 16);
|
||||
unsigned char sig[32];
|
||||
crypto.sha256(sigData.GetBuffer(), sigData.GetLength(), sig);
|
||||
if(memcmp(sig, packet.data+(packet.length-16), 16)!=0){
|
||||
LOGW("Received packet has incorrect signature");
|
||||
return;
|
||||
}
|
||||
|
||||
// reflector special response
|
||||
if(memcmp(packet.data, reflectorSelfTagHash, 16)==0 && packet.length>60){
|
||||
//LOGI("possible reflector special response");
|
||||
unsigned char firstBlock[16];
|
||||
unsigned char iv[16];
|
||||
memcpy(iv, packet.data+16, 16);
|
||||
unsigned char key[32];
|
||||
crypto.sha256(reflectorSelfSecret, 16, key);
|
||||
crypto.aes_cbc_decrypt(packet.data+32, firstBlock, 16, key, iv);
|
||||
BufferInputStream in(firstBlock, 16);
|
||||
in.Seek(8);
|
||||
size_t len=(size_t) in.ReadInt32();
|
||||
int32_t tlid=in.ReadInt32();
|
||||
//LOGD("special response: len=%d, tlid=0x%08X", len, tlid);
|
||||
if(len%4==0 && len+60<=packet.length && packet.length<=1500){
|
||||
lastRecvPacketTime=GetCurrentTime();
|
||||
memcpy(iv, packet.data+16, 16);
|
||||
unsigned char buf[1500];
|
||||
crypto.aes_cbc_decrypt(packet.data+32, buf, len+16, key, iv);
|
||||
try{
|
||||
if(tlid==TLID_UDP_REFLECTOR_LAST_PACKETS_INFO){
|
||||
MutexGuard m(sentPacketsMutex);
|
||||
//LOGV("received udpReflector.lastPacketsInfo");
|
||||
in=BufferInputStream(buf, len+16);
|
||||
in.Seek(16);
|
||||
/*int32_t date=* /in.ReadInt32();
|
||||
/*int64_t queryID=* /in.ReadInt64();
|
||||
int32_t vectorMagic=in.ReadInt32();
|
||||
if(vectorMagic!=TLID_VECTOR){
|
||||
LOGW("last packets info: expected vector, got %08X", vectorMagic);
|
||||
return;
|
||||
}
|
||||
int32_t recvCount=in.ReadInt32();
|
||||
//LOGV("%d received packets", recvCount);
|
||||
for(int i=0;i<recvCount;i++){
|
||||
uint32_t p=(uint32_t) in.ReadInt32();
|
||||
//LOGV("Relay received packet: %08X", p);
|
||||
uint16_t id=(uint16_t) (p & 0xFFFF);
|
||||
//LOGV("ack id %04X", id);
|
||||
for(vector<PacketIdMapping>::iterator pkt=recentSentPackets.begin();pkt!=recentSentPackets.end();++pkt){
|
||||
//LOGV("== sent id %04X", pkt->id);
|
||||
if(pkt->id==id){
|
||||
if(!pkt->ackTime){
|
||||
pkt->ackTime=GetCurrentTime();
|
||||
conctl->PacketAcknowledged(pkt->seq);
|
||||
//LOGV("relay acknowledged packet %u", pkt->seq);
|
||||
if(seqgt(pkt->seq, lastRemoteAckSeq))
|
||||
lastRemoteAckSeq=pkt->seq;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
vectorMagic=in.ReadInt32();
|
||||
if(vectorMagic!=TLID_VECTOR){
|
||||
LOGW("last packets info: expected vector, got %08X", vectorMagic);
|
||||
return;
|
||||
}
|
||||
int32_t sentCount=in.ReadInt32();
|
||||
//LOGV("%d sent packets", sentCount);
|
||||
for(int i=0;i<sentCount;i++){
|
||||
/*int32_t p=* /in.ReadInt32();
|
||||
//LOGV("Sent packet: %08X", p);
|
||||
}
|
||||
if(udpConnectivityState!=UDP_AVAILABLE)
|
||||
udpConnectivityState=UDP_AVAILABLE;
|
||||
if(state!=STATE_ESTABLISHED)
|
||||
SetState(STATE_ESTABLISHED);
|
||||
if(!audioInput){
|
||||
InitializeAudio();
|
||||
if(state!=STATE_FAILED){
|
||||
// audioOutput->Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
}catch(out_of_range& x){
|
||||
LOGE("Error parsing special response: %s", x.what());
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(packet.length<32)
|
||||
return;
|
||||
|
||||
// it's a packet relayed from another participant - find the sender
|
||||
MutexGuard m(participantsMutex);
|
||||
GroupCallParticipant* sender=NULL;
|
||||
for(vector<GroupCallParticipant>::iterator p=participants.begin();p!=participants.end();++p){
|
||||
if(memcmp(packet.data, p->memberTagHash, 16)==0){
|
||||
//LOGV("received data packet from user %d", p->userID);
|
||||
sender=&*p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!sender){
|
||||
LOGV("Received data packet is from unknown user");
|
||||
return;
|
||||
}
|
||||
|
||||
if(memcmp(packet.data+16, keyFingerprint, 8)!=0){
|
||||
LOGW("received packet has wrong key fingerprint");
|
||||
return;
|
||||
}
|
||||
|
||||
BufferInputStream in(packet.data, packet.length-16);
|
||||
in.Seek(16+8); // peer tag + key fingerprint
|
||||
|
||||
unsigned char msgKey[16];
|
||||
in.ReadBytes(msgKey, 16);
|
||||
|
||||
unsigned char decrypted[1500];
|
||||
unsigned char aesKey[32], aesIv[32];
|
||||
KDF2(msgKey, 0, aesKey, aesIv);
|
||||
size_t decryptedLen=in.Remaining()-16;
|
||||
if(decryptedLen>sizeof(decrypted))
|
||||
return;
|
||||
//LOGV("-> MSG KEY: %08x %08x %08x %08x, hashed %u", *reinterpret_cast<int32_t*>(msgKey), *reinterpret_cast<int32_t*>(msgKey+4), *reinterpret_cast<int32_t*>(msgKey+8), *reinterpret_cast<int32_t*>(msgKey+12), decryptedLen-4);
|
||||
uint8_t *decryptOffset = packet.data + in.GetOffset();
|
||||
if ((((intptr_t)decryptOffset) % sizeof(long)) != 0) {
|
||||
LOGE("alignment2 packet.data+in.GetOffset()");
|
||||
}
|
||||
if (decryptedLen % sizeof(long) != 0) {
|
||||
LOGE("alignment2 decryptedLen");
|
||||
}
|
||||
crypto.aes_ige_decrypt(packet.data+in.GetOffset(), decrypted, decryptedLen, aesKey, aesIv);
|
||||
|
||||
in=BufferInputStream(decrypted, decryptedLen);
|
||||
//LOGD("received packet length: %d", in.ReadInt32());
|
||||
|
||||
BufferOutputStream buf(decryptedLen+32);
|
||||
size_t x=0;
|
||||
buf.WriteBytes(encryptionKey+88+x, 32);
|
||||
buf.WriteBytes(decrypted+4, decryptedLen-4);
|
||||
unsigned char msgKeyLarge[32];
|
||||
crypto.sha256(buf.GetBuffer(), buf.GetLength(), msgKeyLarge);
|
||||
|
||||
if(memcmp(msgKey, msgKeyLarge+8, 16)!=0){
|
||||
LOGW("Received packet from user %d has wrong hash", sender->userID);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t innerLen=(uint32_t) in.ReadInt32();
|
||||
if(innerLen>decryptedLen-4){
|
||||
LOGW("Received packet has wrong inner length (%d with total of %u)", (int)innerLen, (unsigned int)decryptedLen);
|
||||
return;
|
||||
}
|
||||
if(decryptedLen-innerLen<12){
|
||||
LOGW("Received packet has too little padding (%u)", (unsigned int)(decryptedLen-innerLen));
|
||||
return;
|
||||
}
|
||||
in=BufferInputStream(decrypted+4, (size_t) innerLen);
|
||||
|
||||
uint32_t tlid=(uint32_t) in.ReadInt32();
|
||||
if(tlid!=TLID_DECRYPTED_AUDIO_BLOCK){
|
||||
LOGW("Received packet has unknown TL ID 0x%08x", tlid);
|
||||
return;
|
||||
}
|
||||
in.Seek(in.GetOffset()+16); // random bytes
|
||||
int32_t flags=in.ReadInt32();
|
||||
if(!(flags & PFLAG_HAS_SEQ) || !(flags & PFLAG_HAS_SENDER_TAG_HASH)){
|
||||
LOGW("Received packet has wrong flags");
|
||||
return;
|
||||
}
|
||||
/*uint32_t seq=(uint32_t) * /in.ReadInt32();
|
||||
unsigned char senderTagHash[16];
|
||||
in.ReadBytes(senderTagHash, 16);
|
||||
if(memcmp(senderTagHash, sender->memberTagHash, 16)!=0){
|
||||
LOGW("Received packet has wrong inner sender tag hash");
|
||||
return;
|
||||
}
|
||||
|
||||
//int32_t oneMoreInnerLengthWhyDoWeEvenNeedThis;
|
||||
if(flags & PFLAG_HAS_DATA){
|
||||
/*oneMoreInnerLengthWhyDoWeEvenNeedThis=* /in.ReadTlLength();
|
||||
}
|
||||
unsigned char type=(unsigned char) ((flags >> 24) & 0xFF);
|
||||
lastRecvPacketTime=GetCurrentTime();
|
||||
|
||||
if(type==PKT_STREAM_DATA || type==PKT_STREAM_DATA_X2 || type==PKT_STREAM_DATA_X3){
|
||||
if(state!=STATE_ESTABLISHED && receivedInitAck)
|
||||
SetState(STATE_ESTABLISHED);
|
||||
int count;
|
||||
switch(type){
|
||||
case PKT_STREAM_DATA_X2:
|
||||
count=2;
|
||||
break;
|
||||
case PKT_STREAM_DATA_X3:
|
||||
count=3;
|
||||
break;
|
||||
case PKT_STREAM_DATA:
|
||||
default:
|
||||
count=1;
|
||||
break;
|
||||
}
|
||||
int i;
|
||||
//if(srcEndpoint->type==Endpoint::Type::UDP_RELAY && srcEndpoint!=peerPreferredRelay){
|
||||
// peerPreferredRelay=srcEndpoint;
|
||||
//}
|
||||
for(i=0;i<count;i++){
|
||||
unsigned char streamID=in.ReadByte();
|
||||
unsigned char sflags=(unsigned char) (streamID & 0xC0);
|
||||
uint16_t sdlen=(uint16_t) (sflags & STREAM_DATA_FLAG_LEN16 ? in.ReadInt16() : in.ReadByte());
|
||||
uint32_t pts=(uint32_t) in.ReadInt32();
|
||||
//LOGD("stream data, pts=%d, len=%d, rem=%d", pts, sdlen, in.Remaining());
|
||||
audioTimestampIn=pts;
|
||||
/*if(!audioOutStarted && audioOutput){
|
||||
audioOutput->Start();
|
||||
audioOutStarted=true;
|
||||
}* /
|
||||
if(in.GetOffset()+sdlen>in.GetLength()){
|
||||
return;
|
||||
}
|
||||
for(vector<shared_ptr<Stream>>::iterator stm=sender->streams.begin();stm!=sender->streams.end();++stm){
|
||||
if((*stm)->id==streamID){
|
||||
if((*stm)->jitterBuffer){
|
||||
(*stm)->jitterBuffer->HandleInput(decrypted+4+in.GetOffset(), sdlen, pts, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(i<count-1)
|
||||
in.Seek(in.GetOffset()+sdlen);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
void VoIPGroupController::SendUdpPing(Endpoint& endpoint){
|
||||
|
||||
}
|
||||
|
||||
void VoIPGroupController::SetNetworkType(int type){
|
||||
networkType=type;
|
||||
UpdateDataSavingState();
|
||||
UpdateAudioBitrateLimit();
|
||||
string itfName=udpSocket->GetLocalInterfaceInfo(NULL, NULL);
|
||||
if(itfName!=activeNetItfName){
|
||||
udpSocket->OnActiveInterfaceChanged();
|
||||
LOGI("Active network interface changed: %s -> %s", activeNetItfName.c_str(), itfName.c_str());
|
||||
bool isFirstChange=activeNetItfName.length()==0;
|
||||
activeNetItfName=itfName;
|
||||
if(isFirstChange)
|
||||
return;
|
||||
udpConnectivityState=UDP_UNKNOWN;
|
||||
udpPingCount=0;
|
||||
lastUdpPingTime=0;
|
||||
if(proxyProtocol==PROXY_SOCKS5)
|
||||
InitUDPProxy();
|
||||
selectCanceller->CancelSelect();
|
||||
}
|
||||
}
|
||||
|
||||
void VoIPGroupController::SendRecentPacketsRequest(){
|
||||
BufferOutputStream out(1024);
|
||||
out.WriteInt32(TLID_UDP_REFLECTOR_REQUEST_PACKETS_INFO); // TL function
|
||||
out.WriteInt32(GetCurrentUnixtime()); // date:int
|
||||
out.WriteInt64(0); // query_id:long
|
||||
out.WriteInt32(64); // recv_num:int
|
||||
out.WriteInt32(0); // sent_num:int
|
||||
SendSpecialReflectorRequest(out.GetBuffer(), out.GetLength());
|
||||
}
|
||||
|
||||
void VoIPGroupController::SendSpecialReflectorRequest(unsigned char *data, size_t len){
|
||||
/*BufferOutputStream out(1024);
|
||||
unsigned char buf[1500];
|
||||
crypto.rand_bytes(buf, 8);
|
||||
out.WriteBytes(buf, 8);
|
||||
out.WriteInt32((int32_t)len);
|
||||
out.WriteBytes(data, len);
|
||||
if(out.GetLength()%16!=0){
|
||||
size_t paddingLen=16-(out.GetLength()%16);
|
||||
crypto.rand_bytes(buf, paddingLen);
|
||||
out.WriteBytes(buf, paddingLen);
|
||||
}
|
||||
unsigned char iv[16];
|
||||
crypto.rand_bytes(iv, 16);
|
||||
unsigned char key[32];
|
||||
crypto.sha256(reflectorSelfSecret, 16, key);
|
||||
unsigned char _iv[16];
|
||||
memcpy(_iv, iv, 16);
|
||||
size_t encryptedLen=out.GetLength();
|
||||
crypto.aes_cbc_encrypt(out.GetBuffer(), buf, encryptedLen, key, _iv);
|
||||
out.Reset();
|
||||
out.WriteBytes(reflectorSelfTag, 16);
|
||||
out.WriteBytes(iv, 16);
|
||||
out.WriteBytes(buf, encryptedLen);
|
||||
out.WriteBytes(reflectorSelfSecret, 16);
|
||||
crypto.sha256(out.GetBuffer(), out.GetLength(), buf);
|
||||
out.Rewind(16);
|
||||
out.WriteBytes(buf, 16);
|
||||
|
||||
NetworkPacket pkt={0};
|
||||
pkt.address=&groupReflector.address;
|
||||
pkt.port=groupReflector.port;
|
||||
pkt.protocol=PROTO_UDP;
|
||||
pkt.data=out.GetBuffer();
|
||||
pkt.length=out.GetLength();
|
||||
ActuallySendPacket(pkt, groupReflector);*/
|
||||
}
|
||||
|
||||
void VoIPGroupController::SendRelayPings(){
|
||||
//LOGV("Send relay pings 2");
|
||||
double currentTime=GetCurrentTime();
|
||||
if(currentTime-groupReflector.lastPingTime>=0.25){
|
||||
SendRecentPacketsRequest();
|
||||
groupReflector.lastPingTime=currentTime;
|
||||
}
|
||||
}
|
||||
|
||||
void VoIPGroupController::OnAudioOutputReady(){
|
||||
encoder->SetDTX(true);
|
||||
audioMixer->SetOutput(audioOutput);
|
||||
audioMixer->SetEchoCanceller(echoCanceller);
|
||||
audioMixer->Start();
|
||||
audioOutput->Start();
|
||||
audioOutStarted=true;
|
||||
encoder->SetLevelMeter(&selfLevelMeter);
|
||||
}
|
||||
|
||||
void VoIPGroupController::WritePacketHeader(uint32_t seq, BufferOutputStream *s, unsigned char type, uint32_t length, PacketSender* source){
|
||||
s->WriteInt32(TLID_DECRYPTED_AUDIO_BLOCK);
|
||||
int64_t randomID;
|
||||
crypto.rand_bytes((uint8_t *) &randomID, 8);
|
||||
s->WriteInt64(randomID);
|
||||
unsigned char randBytes[7];
|
||||
crypto.rand_bytes(randBytes, 7);
|
||||
s->WriteByte(7);
|
||||
s->WriteBytes(randBytes, 7);
|
||||
uint32_t pflags=PFLAG_HAS_SEQ | PFLAG_HAS_SENDER_TAG_HASH;
|
||||
if(length>0)
|
||||
pflags|=PFLAG_HAS_DATA;
|
||||
pflags|=((uint32_t) type) << 24;
|
||||
s->WriteInt32(pflags);
|
||||
|
||||
if(type==PKT_STREAM_DATA || type==PKT_STREAM_DATA_X2 || type==PKT_STREAM_DATA_X3){
|
||||
conctl->PacketSent(seq, length);
|
||||
}
|
||||
|
||||
/*if(pflags & PFLAG_HAS_CALL_ID){
|
||||
s->WriteBytes(callID, 16);
|
||||
}*/
|
||||
//s->WriteInt32(lastRemoteSeq);
|
||||
s->WriteInt32(seq);
|
||||
s->WriteBytes(reflectorSelfTagHash, 16);
|
||||
if(length>0){
|
||||
if(length<=253){
|
||||
s->WriteByte((unsigned char) length);
|
||||
}else{
|
||||
s->WriteByte(254);
|
||||
s->WriteByte((unsigned char) (length & 0xFF));
|
||||
s->WriteByte((unsigned char) ((length >> 8) & 0xFF));
|
||||
s->WriteByte((unsigned char) ((length >> 16) & 0xFF));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VoIPGroupController::SendPacket(unsigned char *data, size_t len, Endpoint& ep, PendingOutgoingPacket& srcPacket){
|
||||
if(stopping)
|
||||
return;
|
||||
if(ep.type==Endpoint::Type::TCP_RELAY && !useTCP)
|
||||
return;
|
||||
BufferOutputStream out(len+128);
|
||||
//LOGV("send group packet %u", len);
|
||||
|
||||
out.WriteBytes(reflectorSelfTag, 16);
|
||||
|
||||
if(len>0){
|
||||
BufferOutputStream inner(len+128);
|
||||
inner.WriteInt32((uint32_t)len);
|
||||
inner.WriteBytes(data, len);
|
||||
size_t padLen=16-inner.GetLength()%16;
|
||||
if(padLen<12)
|
||||
padLen+=16;
|
||||
unsigned char padding[28];
|
||||
crypto.rand_bytes((uint8_t *) padding, padLen);
|
||||
inner.WriteBytes(padding, padLen);
|
||||
assert(inner.GetLength()%16==0);
|
||||
|
||||
unsigned char key[32], iv[32], msgKey[16];
|
||||
out.WriteBytes(keyFingerprint, 8);
|
||||
BufferOutputStream buf(len+32);
|
||||
size_t x=0;
|
||||
buf.WriteBytes(encryptionKey+88+x, 32);
|
||||
buf.WriteBytes(inner.GetBuffer()+4, inner.GetLength()-4);
|
||||
unsigned char msgKeyLarge[32];
|
||||
crypto.sha256(buf.GetBuffer(), buf.GetLength(), msgKeyLarge);
|
||||
memcpy(msgKey, msgKeyLarge+8, 16);
|
||||
KDF2(msgKey, 0, key, iv);
|
||||
out.WriteBytes(msgKey, 16);
|
||||
//LOGV("<- MSG KEY: %08x %08x %08x %08x, hashed %u", *reinterpret_cast<int32_t*>(msgKey), *reinterpret_cast<int32_t*>(msgKey+4), *reinterpret_cast<int32_t*>(msgKey+8), *reinterpret_cast<int32_t*>(msgKey+12), inner.GetLength()-4);
|
||||
|
||||
unsigned char aesOut[MSC_STACK_FALLBACK(inner.GetLength(), 1500)];
|
||||
crypto.aes_ige_encrypt(inner.GetBuffer(), aesOut, inner.GetLength(), key, iv);
|
||||
out.WriteBytes(aesOut, inner.GetLength());
|
||||
}
|
||||
|
||||
// relay signature
|
||||
out.WriteBytes(reflectorSelfSecret, 16);
|
||||
unsigned char sig[32];
|
||||
crypto.sha256(out.GetBuffer(), out.GetLength(), sig);
|
||||
out.Rewind(16);
|
||||
out.WriteBytes(sig, 16);
|
||||
|
||||
if(srcPacket.type==PKT_STREAM_DATA || srcPacket.type==PKT_STREAM_DATA_X2 || srcPacket.type==PKT_STREAM_DATA_X3){
|
||||
PacketIdMapping mapping={srcPacket.seq, *reinterpret_cast<uint16_t*>(sig+14), 0};
|
||||
MutexGuard m(sentPacketsMutex);
|
||||
recentSentPackets.push_back(mapping);
|
||||
//LOGD("sent packet with id: %04X", mapping.id);
|
||||
while(recentSentPackets.size()>64)
|
||||
recentSentPackets.erase(recentSentPackets.begin());
|
||||
}
|
||||
lastSentSeq=srcPacket.seq;
|
||||
|
||||
if(IS_MOBILE_NETWORK(networkType))
|
||||
stats.bytesSentMobile+=(uint64_t)out.GetLength();
|
||||
else
|
||||
stats.bytesSentWifi+=(uint64_t)out.GetLength();
|
||||
|
||||
/*NetworkPacket pkt={0};
|
||||
pkt.address=(NetworkAddress*)&ep.address;
|
||||
pkt.port=ep.port;
|
||||
pkt.length=out.GetLength();
|
||||
pkt.data=out.GetBuffer();
|
||||
pkt.protocol=ep.type==Endpoint::Type::TCP_RELAY ? PROTO_TCP : PROTO_UDP;
|
||||
ActuallySendPacket(pkt, ep);*/
|
||||
}
|
||||
|
||||
void VoIPGroupController::SetCallbacks(VoIPGroupController::Callbacks callbacks){
|
||||
VoIPController::SetCallbacks(callbacks);
|
||||
this->groupCallbacks=callbacks;
|
||||
}
|
||||
|
||||
int32_t VoIPGroupController::GetCurrentUnixtime(){
|
||||
return time(NULL)+timeDifference;
|
||||
}
|
||||
|
||||
float VoIPGroupController::GetParticipantAudioLevel(int32_t userID){
|
||||
if(userID==userSelfID)
|
||||
return selfLevelMeter.GetLevel();
|
||||
MutexGuard m(participantsMutex);
|
||||
for(vector<GroupCallParticipant>::iterator p=participants.begin(); p!=participants.end(); ++p){
|
||||
if(p->userID==userID){
|
||||
return p->levelMeter->GetLevel();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void VoIPGroupController::SetMicMute(bool mute){
|
||||
micMuted=mute;
|
||||
if(audioInput){
|
||||
if(mute)
|
||||
audioInput->Stop();
|
||||
else
|
||||
audioInput->Start();
|
||||
if(!audioInput->IsInitialized()){
|
||||
lastError=ERROR_AUDIO_IO;
|
||||
SetState(STATE_FAILED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
outgoingStreams[0]->enabled=!mute;
|
||||
SerializeAndUpdateOutgoingStreams();
|
||||
}
|
||||
|
||||
void VoIPGroupController::SetParticipantVolume(int32_t userID, float volume){
|
||||
MutexGuard m(participantsMutex);
|
||||
for(vector<GroupCallParticipant>::iterator p=participants.begin();p!=participants.end();++p){
|
||||
if(p->userID==userID){
|
||||
for(vector<shared_ptr<Stream>>::iterator s=p->streams.begin();s!=p->streams.end();++s){
|
||||
if((*s)->type==STREAM_TYPE_AUDIO){
|
||||
if((*s)->decoder){
|
||||
float db;
|
||||
if(volume==0.0f)
|
||||
db=-INFINITY;
|
||||
else if(volume<1.0f)
|
||||
db=-50.0f*(1.0f-volume);
|
||||
else if(volume>1.0f && volume<=2.0f)
|
||||
db=10.0f*(volume-1.0f);
|
||||
else
|
||||
db=0.0f;
|
||||
//LOGV("Setting user %u audio volume to %.2f dB", userID, db);
|
||||
audioMixer->SetInputVolume((*s)->callbackWrapper, db);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VoIPGroupController::SerializeAndUpdateOutgoingStreams(){
|
||||
BufferOutputStream out(1024);
|
||||
out.WriteByte((unsigned char) outgoingStreams.size());
|
||||
|
||||
for(vector<shared_ptr<Stream>>::iterator s=outgoingStreams.begin(); s!=outgoingStreams.end(); ++s){
|
||||
BufferOutputStream o(128);
|
||||
o.WriteByte((*s)->id);
|
||||
o.WriteByte((*s)->type);
|
||||
o.WriteInt32((*s)->codec);
|
||||
o.WriteInt32((unsigned char) (((*s)->enabled ? STREAM_FLAG_ENABLED : 0) | STREAM_FLAG_DTX));
|
||||
o.WriteInt16((*s)->frameDuration);
|
||||
out.WriteInt16((int16_t) o.GetLength());
|
||||
out.WriteBytes(o.GetBuffer(), o.GetLength());
|
||||
}
|
||||
if(groupCallbacks.updateStreams)
|
||||
groupCallbacks.updateStreams(this, out.GetBuffer(), out.GetLength());
|
||||
}
|
||||
|
||||
std::string VoIPGroupController::GetDebugString(){
|
||||
std::string r="Remote endpoints: \n";
|
||||
char buffer[2048];
|
||||
for(pair<const int64_t, Endpoint>& _endpoint:endpoints){
|
||||
Endpoint& endpoint=_endpoint.second;
|
||||
const char* type;
|
||||
switch(endpoint.type){
|
||||
case Endpoint::Type::UDP_P2P_INET:
|
||||
type="UDP_P2P_INET";
|
||||
break;
|
||||
case Endpoint::Type::UDP_P2P_LAN:
|
||||
type="UDP_P2P_LAN";
|
||||
break;
|
||||
case Endpoint::Type::UDP_RELAY:
|
||||
type="UDP_RELAY";
|
||||
break;
|
||||
case Endpoint::Type::TCP_RELAY:
|
||||
type="TCP_RELAY";
|
||||
break;
|
||||
default:
|
||||
type="UNKNOWN";
|
||||
break;
|
||||
}
|
||||
snprintf(buffer, sizeof(buffer), "%s:%u %dms [%s%s]\n", endpoint.address.ToString().c_str(), endpoint.port, (int)(endpoint.averageRTT*1000), type, currentEndpoint==endpoint.id ? ", IN_USE" : "");
|
||||
r+=buffer;
|
||||
}
|
||||
double avgLate[3];
|
||||
shared_ptr<JitterBuffer> jitterBuffer=incomingStreams.size()==1 ? incomingStreams[0]->jitterBuffer : NULL;
|
||||
if(jitterBuffer)
|
||||
jitterBuffer->GetAverageLateCount(avgLate);
|
||||
else
|
||||
memset(avgLate, 0, 3*sizeof(double));
|
||||
snprintf(buffer, sizeof(buffer),
|
||||
"RTT avg/min: %d/%d\n"
|
||||
"Congestion window: %d/%d bytes\n"
|
||||
"Key fingerprint: %02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX\n"
|
||||
"Last sent/ack'd seq: %u/%u\n"
|
||||
"Send/recv losses: %u/%u (%d%%)\n"
|
||||
"Audio bitrate: %d kbit\n"
|
||||
"Bytes sent/recvd: %llu/%llu\n\n",
|
||||
(int)(conctl->GetAverageRTT()*1000), (int)(conctl->GetMinimumRTT()*1000),
|
||||
int(conctl->GetInflightDataSize()), int(conctl->GetCongestionWindow()),
|
||||
keyFingerprint[0],keyFingerprint[1],keyFingerprint[2],keyFingerprint[3],keyFingerprint[4],keyFingerprint[5],keyFingerprint[6],keyFingerprint[7],
|
||||
lastSentSeq, lastRemoteAckSeq,
|
||||
conctl->GetSendLossCount(), recvLossCount, encoder ? encoder->GetPacketLoss() : 0,
|
||||
encoder ? (encoder->GetBitrate()/1000) : 0,
|
||||
(long long unsigned int)(stats.bytesSentMobile+stats.bytesSentWifi),
|
||||
(long long unsigned int)(stats.bytesRecvdMobile+stats.bytesRecvdWifi));
|
||||
|
||||
MutexGuard m(participantsMutex);
|
||||
for(vector<GroupCallParticipant>::iterator p=participants.begin();p!=participants.end();++p){
|
||||
snprintf(buffer, sizeof(buffer), "Participant id: %d\n", p->userID);
|
||||
r+=buffer;
|
||||
for(vector<shared_ptr<Stream>>::iterator stm=p->streams.begin();stm!=p->streams.end();++stm){
|
||||
char* codec=reinterpret_cast<char*>(&(*stm)->codec);
|
||||
snprintf(buffer, sizeof(buffer), "Stream %d (type %d, codec '%c%c%c%c', %sabled)\n",
|
||||
(*stm)->id, (*stm)->type, codec[3], codec[2], codec[1], codec[0], (*stm)->enabled ? "en" : "dis");
|
||||
r+=buffer;
|
||||
if((*stm)->enabled){
|
||||
if((*stm)->jitterBuffer){
|
||||
snprintf(buffer, sizeof(buffer), "Jitter buffer: %d/%.2f\n",
|
||||
(*stm)->jitterBuffer->GetMinPacketCount(), (*stm)->jitterBuffer->GetAverageDelay());
|
||||
r+=buffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
r+="\n";
|
||||
}
|
||||
return r;
|
||||
}
|
70
TMessagesProj/jni/libtgvoip2/VoIPServerConfig.cpp
Normal file
70
TMessagesProj/jni/libtgvoip2/VoIPServerConfig.cpp
Normal file
|
@ -0,0 +1,70 @@
|
|||
//
|
||||
// libtgvoip is free and unencumbered public domain software.
|
||||
// For more information, see http://unlicense.org or the UNLICENSE file
|
||||
// you should have received with this source code distribution.
|
||||
//
|
||||
|
||||
#include "VoIPServerConfig.h"
|
||||
#include <stdlib.h>
|
||||
#include "logging.h"
|
||||
#include <sstream>
|
||||
#include <locale>
|
||||
|
||||
using namespace tgvoip;
|
||||
|
||||
ServerConfig* ServerConfig::sharedInstance=NULL;
|
||||
|
||||
ServerConfig::ServerConfig(){
|
||||
}
|
||||
|
||||
ServerConfig::~ServerConfig(){
|
||||
}
|
||||
|
||||
ServerConfig *ServerConfig::GetSharedInstance(){
|
||||
if(!sharedInstance)
|
||||
sharedInstance=new ServerConfig();
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
bool ServerConfig::GetBoolean(std::string name, bool fallback){
|
||||
MutexGuard sync(mutex);
|
||||
if(ContainsKey(name) && config[name].is_bool())
|
||||
return config[name].bool_value();
|
||||
return fallback;
|
||||
}
|
||||
|
||||
double ServerConfig::GetDouble(std::string name, double fallback){
|
||||
MutexGuard sync(mutex);
|
||||
if(ContainsKey(name) && config[name].is_number())
|
||||
return config[name].number_value();
|
||||
return fallback;
|
||||
}
|
||||
|
||||
int32_t ServerConfig::GetInt(std::string name, int32_t fallback){
|
||||
MutexGuard sync(mutex);
|
||||
if(ContainsKey(name) && config[name].is_number())
|
||||
return config[name].int_value();
|
||||
return fallback;
|
||||
}
|
||||
|
||||
std::string ServerConfig::GetString(std::string name, std::string fallback){
|
||||
MutexGuard sync(mutex);
|
||||
if(ContainsKey(name) && config[name].is_string())
|
||||
return config[name].string_value();
|
||||
return fallback;
|
||||
}
|
||||
|
||||
void ServerConfig::Update(std::string jsonString){
|
||||
MutexGuard sync(mutex);
|
||||
LOGD("=== Updating voip config ===");
|
||||
LOGD("%s", jsonString.c_str());
|
||||
std::string jsonError;
|
||||
config=json11::Json::parse(jsonString, jsonError);
|
||||
if(!jsonError.empty())
|
||||
LOGE("Error parsing server config: %s", jsonError.c_str());
|
||||
}
|
||||
|
||||
|
||||
bool ServerConfig::ContainsKey(std::string key){
|
||||
return config.object_items().find(key)!=config.object_items().end();
|
||||
}
|
37
TMessagesProj/jni/libtgvoip2/VoIPServerConfig.h
Normal file
37
TMessagesProj/jni/libtgvoip2/VoIPServerConfig.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
//
|
||||
// libtgvoip is free and unencumbered public domain software.
|
||||
// For more information, see http://unlicense.org or the UNLICENSE file
|
||||
// you should have received with this source code distribution.
|
||||
//
|
||||
|
||||
#ifndef TGVOIP_VOIPSERVERCONFIG_H
|
||||
#define TGVOIP_VOIPSERVERCONFIG_H
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
#include "threading.h"
|
||||
#include "json11.hpp"
|
||||
|
||||
namespace tgvoip{
|
||||
|
||||
class ServerConfig{
|
||||
public:
|
||||
ServerConfig();
|
||||
~ServerConfig();
|
||||
static ServerConfig* GetSharedInstance();
|
||||
int32_t GetInt(std::string name, int32_t fallback);
|
||||
double GetDouble(std::string name, double fallback);
|
||||
std::string GetString(std::string name, std::string fallback);
|
||||
bool GetBoolean(std::string name, bool fallback);
|
||||
void Update(std::string jsonString);
|
||||
|
||||
private:
|
||||
static ServerConfig* sharedInstance;
|
||||
bool ContainsKey(std::string key);
|
||||
json11::Json config;
|
||||
Mutex mutex;
|
||||
};
|
||||
}
|
||||
|
||||
#endif //TGVOIP_VOIPSERVERCONFIG_H
|
10209
TMessagesProj/jni/libtgvoip2/aclocal.m4
vendored
Normal file
10209
TMessagesProj/jni/libtgvoip2/aclocal.m4
vendored
Normal file
File diff suppressed because it is too large
Load diff
92
TMessagesProj/jni/libtgvoip2/audio/AudioIO.cpp
Normal file
92
TMessagesProj/jni/libtgvoip2/audio/AudioIO.cpp
Normal file
|
@ -0,0 +1,92 @@
|
|||
//
|
||||
// libtgvoip is free and unencumbered public domain software.
|
||||
// For more information, see http://unlicense.org or the UNLICENSE file
|
||||
// you should have received with this source code distribution.
|
||||
//
|
||||
|
||||
|
||||
#include "AudioIO.h"
|
||||
#include "../logging.h"
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#if defined(TGVOIP_USE_CALLBACK_AUDIO_IO)
|
||||
#include "AudioIOCallback.h"
|
||||
#elif defined(__ANDROID__)
|
||||
#include "../os/android/AudioInputAndroid.h"
|
||||
#include "../os/android/AudioOutputAndroid.h"
|
||||
#elif defined(__APPLE__)
|
||||
#include <TargetConditionals.h>
|
||||
#include "../os/darwin/AudioUnitIO.h"
|
||||
#if TARGET_OS_OSX
|
||||
#include "../os/darwin/AudioInputAudioUnitOSX.h"
|
||||
#include "../os/darwin/AudioOutputAudioUnitOSX.h"
|
||||
#endif
|
||||
#elif defined(_WIN32)
|
||||
#ifdef TGVOIP_WINXP_COMPAT
|
||||
#include "../os/windows/AudioInputWave.h"
|
||||
#include "../os/windows/AudioOutputWave.h"
|
||||
#endif
|
||||
#include "../os/windows/AudioInputWASAPI.h"
|
||||
#include "../os/windows/AudioOutputWASAPI.h"
|
||||
#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__gnu_hurd__)
|
||||
#ifndef WITHOUT_ALSA
|
||||
#include "../os/linux/AudioInputALSA.h"
|
||||
#include "../os/linux/AudioOutputALSA.h"
|
||||
#endif
|
||||
#ifndef WITHOUT_PULSE
|
||||
#include "../os/linux/AudioPulse.h"
|
||||
#endif
|
||||
#else
|
||||
#error "Unsupported operating system"
|
||||
#endif
|
||||
|
||||
using namespace tgvoip;
|
||||
using namespace tgvoip::audio;
|
||||
using namespace std;
|
||||
|
||||
AudioIO* AudioIO::Create(std::string inputDevice, std::string outputDevice){
|
||||
#if defined(TGVOIP_USE_CALLBACK_AUDIO_IO)
|
||||
return new AudioIOCallback();
|
||||
#elif defined(__ANDROID__)
|
||||
return new ContextlessAudioIO<AudioInputAndroid, AudioOutputAndroid>();
|
||||
#elif defined(__APPLE__)
|
||||
#if TARGET_OS_OSX
|
||||
if(kCFCoreFoundationVersionNumber<kCFCoreFoundationVersionNumber10_7)
|
||||
return new ContextlessAudioIO<AudioInputAudioUnitLegacy, AudioOutputAudioUnitLegacy>(inputDevice, outputDevice);
|
||||
|
||||
#endif
|
||||
return new AudioUnitIO(inputDevice, outputDevice);
|
||||
#elif defined(_WIN32)
|
||||
#ifdef TGVOIP_WINXP_COMPAT
|
||||
if(LOBYTE(LOWORD(GetVersion()))<6)
|
||||
return new ContextlessAudioIO<AudioInputWave, AudioOutputWave>(inputDevice, outputDevice);
|
||||
#endif
|
||||
return new ContextlessAudioIO<AudioInputWASAPI, AudioOutputWASAPI>(inputDevice, outputDevice);
|
||||
#elif defined(__linux__)
|
||||
#ifndef WITHOUT_ALSA
|
||||
#ifndef WITHOUT_PULSE
|
||||
if(AudioPulse::Load()){
|
||||
AudioIO* io=new AudioPulse(inputDevice, outputDevice);
|
||||
if(!io->Failed() && io->GetInput()->IsInitialized() && io->GetOutput()->IsInitialized())
|
||||
return io;
|
||||
LOGW("PulseAudio available but not working; trying ALSA");
|
||||
delete io;
|
||||
}
|
||||
#endif
|
||||
return new ContextlessAudioIO<AudioInputALSA, AudioOutputALSA>(inputDevice, outputDevice);
|
||||
#else
|
||||
return new AudioPulse(inputDevice, outputDevice);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
bool AudioIO::Failed(){
|
||||
return failed;
|
||||
}
|
||||
|
||||
std::string AudioIO::GetErrorDescription(){
|
||||
return error;
|
||||
}
|
65
TMessagesProj/jni/libtgvoip2/audio/AudioIO.h
Normal file
65
TMessagesProj/jni/libtgvoip2/audio/AudioIO.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
//
|
||||
// libtgvoip is free and unencumbered public domain software.
|
||||
// For more information, see http://unlicense.org or the UNLICENSE file
|
||||
// you should have received with this source code distribution.
|
||||
//
|
||||
|
||||
|
||||
#ifndef LIBTGVOIP_AUDIOIO_H
|
||||
#define LIBTGVOIP_AUDIOIO_H
|
||||
|
||||
#include "AudioInput.h"
|
||||
#include "AudioOutput.h"
|
||||
#include "../utils.h"
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace tgvoip{
|
||||
namespace audio {
|
||||
class AudioIO{
|
||||
public:
|
||||
AudioIO(){};
|
||||
virtual ~AudioIO(){};
|
||||
TGVOIP_DISALLOW_COPY_AND_ASSIGN(AudioIO);
|
||||
static AudioIO* Create(std::string inputDevice, std::string outputDevice);
|
||||
virtual AudioInput* GetInput()=0;
|
||||
virtual AudioOutput* GetOutput()=0;
|
||||
bool Failed();
|
||||
std::string GetErrorDescription();
|
||||
protected:
|
||||
bool failed=false;
|
||||
std::string error;
|
||||
};
|
||||
|
||||
template<class I, class O> class ContextlessAudioIO : public AudioIO{
|
||||
public:
|
||||
ContextlessAudioIO(){
|
||||
input=new I();
|
||||
output=new O();
|
||||
}
|
||||
|
||||
ContextlessAudioIO(std::string inputDeviceID, std::string outputDeviceID){
|
||||
input=new I(inputDeviceID);
|
||||
output=new O(outputDeviceID);
|
||||
}
|
||||
|
||||
virtual ~ContextlessAudioIO(){
|
||||
delete input;
|
||||
delete output;
|
||||
}
|
||||
|
||||
virtual AudioInput* GetInput(){
|
||||
return input;
|
||||
}
|
||||
|
||||
virtual AudioOutput* GetOutput(){
|
||||
return output;
|
||||
}
|
||||
private:
|
||||
I* input;
|
||||
O* output;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif //LIBTGVOIP_AUDIOIO_H
|
121
TMessagesProj/jni/libtgvoip2/audio/AudioIOCallback.cpp
Normal file
121
TMessagesProj/jni/libtgvoip2/audio/AudioIOCallback.cpp
Normal file
|
@ -0,0 +1,121 @@
|
|||
//
|
||||
// libtgvoip is free and unencumbered public domain software.
|
||||
// For more information, see http://unlicense.org or the UNLICENSE file
|
||||
// you should have received with this source code distribution.
|
||||
//
|
||||
|
||||
#include "AudioIOCallback.h"
|
||||
#include "../VoIPController.h"
|
||||
#include "../logging.h"
|
||||
|
||||
using namespace tgvoip;
|
||||
using namespace tgvoip::audio;
|
||||
|
||||
#pragma mark - IO
|
||||
|
||||
AudioIOCallback::AudioIOCallback(){
|
||||
input=new AudioInputCallback();
|
||||
output=new AudioOutputCallback();
|
||||
}
|
||||
|
||||
AudioIOCallback::~AudioIOCallback(){
|
||||
delete input;
|
||||
delete output;
|
||||
}
|
||||
|
||||
AudioInput* AudioIOCallback::GetInput(){
|
||||
return input;
|
||||
}
|
||||
|
||||
AudioOutput* AudioIOCallback::GetOutput(){
|
||||
return output;
|
||||
}
|
||||
|
||||
#pragma mark - Input
|
||||
|
||||
AudioInputCallback::AudioInputCallback(){
|
||||
thread=new Thread(std::bind(&AudioInputCallback::RunThread, this));
|
||||
thread->SetName("AudioInputCallback");
|
||||
}
|
||||
|
||||
AudioInputCallback::~AudioInputCallback(){
|
||||
running=false;
|
||||
thread->Join();
|
||||
delete thread;
|
||||
}
|
||||
|
||||
void AudioInputCallback::Start(){
|
||||
if(!running){
|
||||
running=true;
|
||||
thread->Start();
|
||||
}
|
||||
recording=true;
|
||||
}
|
||||
|
||||
void AudioInputCallback::Stop(){
|
||||
recording=false;
|
||||
}
|
||||
|
||||
void AudioInputCallback::SetDataCallback(std::function<void(int16_t*, size_t)> c){
|
||||
dataCallback=c;
|
||||
}
|
||||
|
||||
void AudioInputCallback::RunThread(){
|
||||
int16_t buf[960];
|
||||
while(running){
|
||||
double t=VoIPController::GetCurrentTime();
|
||||
memset(buf, 0, sizeof(buf));
|
||||
dataCallback(buf, 960);
|
||||
InvokeCallback(reinterpret_cast<unsigned char*>(buf), 960*2);
|
||||
double sl=0.02-(VoIPController::GetCurrentTime()-t);
|
||||
if(sl>0)
|
||||
Thread::Sleep(sl);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Output
|
||||
|
||||
AudioOutputCallback::AudioOutputCallback(){
|
||||
thread=new Thread(std::bind(&AudioOutputCallback::RunThread, this));
|
||||
thread->SetName("AudioOutputCallback");
|
||||
}
|
||||
|
||||
AudioOutputCallback::~AudioOutputCallback(){
|
||||
running=false;
|
||||
thread->Join();
|
||||
delete thread;
|
||||
}
|
||||
|
||||
void AudioOutputCallback::Start(){
|
||||
if(!running){
|
||||
running=true;
|
||||
thread->Start();
|
||||
}
|
||||
playing=true;
|
||||
}
|
||||
|
||||
void AudioOutputCallback::Stop(){
|
||||
playing=false;
|
||||
}
|
||||
|
||||
bool AudioOutputCallback::IsPlaying(){
|
||||
return playing;
|
||||
}
|
||||
|
||||
void AudioOutputCallback::SetDataCallback(std::function<void(int16_t*, size_t)> c){
|
||||
dataCallback=c;
|
||||
}
|
||||
|
||||
void AudioOutputCallback::RunThread(){
|
||||
int16_t buf[960];
|
||||
while(running){
|
||||
double t=VoIPController::GetCurrentTime();
|
||||
InvokeCallback(reinterpret_cast<unsigned char*>(buf), 960*2);
|
||||
dataCallback(buf, 960);
|
||||
double sl=0.02-(VoIPController::GetCurrentTime()-t);
|
||||
if(sl>0)
|
||||
Thread::Sleep(sl);
|
||||
}
|
||||
}
|
||||
|
||||
|
63
TMessagesProj/jni/libtgvoip2/audio/AudioIOCallback.h
Normal file
63
TMessagesProj/jni/libtgvoip2/audio/AudioIOCallback.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
//
|
||||
// libtgvoip is free and unencumbered public domain software.
|
||||
// For more information, see http://unlicense.org or the UNLICENSE file
|
||||
// you should have received with this source code distribution.
|
||||
//
|
||||
|
||||
#ifndef LIBTGVOIP_AUDIO_IO_CALLBACK
|
||||
#define LIBTGVOIP_AUDIO_IO_CALLBACK
|
||||
|
||||
#include "AudioIO.h"
|
||||
#include <functional>
|
||||
#include <atomic>
|
||||
|
||||
#include "../threading.h"
|
||||
|
||||
namespace tgvoip{
|
||||
namespace audio{
|
||||
class AudioInputCallback : public AudioInput{
|
||||
public:
|
||||
AudioInputCallback();
|
||||
virtual ~AudioInputCallback();
|
||||
virtual void Start() override;
|
||||
virtual void Stop() override;
|
||||
void SetDataCallback(std::function<void(int16_t*, size_t)> c);
|
||||
private:
|
||||
void RunThread();
|
||||
std::atomic<bool> running{false};
|
||||
bool recording=false;
|
||||
Thread* thread;
|
||||
std::function<void(int16_t*, size_t)> dataCallback;
|
||||
};
|
||||
|
||||
class AudioOutputCallback : public AudioOutput{
|
||||
public:
|
||||
AudioOutputCallback();
|
||||
virtual ~AudioOutputCallback();
|
||||
virtual void Start() override;
|
||||
virtual void Stop() override;
|
||||
virtual bool IsPlaying() override;
|
||||
void SetDataCallback(std::function<void(int16_t*, size_t)> c);
|
||||
private:
|
||||
void RunThread();
|
||||
std::atomic<bool> running{false};
|
||||
bool playing=false;
|
||||
Thread* thread;
|
||||
std::function<void(int16_t*, size_t)> dataCallback;
|
||||
};
|
||||
|
||||
class AudioIOCallback : public AudioIO{
|
||||
public:
|
||||
AudioIOCallback();
|
||||
virtual ~AudioIOCallback();
|
||||
virtual AudioInput* GetInput() override;
|
||||
virtual AudioOutput* GetOutput() override;
|
||||
private:
|
||||
AudioInputCallback* input;
|
||||
AudioOutputCallback* output;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif /* LIBTGVOIP_AUDIO_IO_CALLBACK */
|
97
TMessagesProj/jni/libtgvoip2/audio/AudioInput.cpp
Normal file
97
TMessagesProj/jni/libtgvoip2/audio/AudioInput.cpp
Normal file
|
@ -0,0 +1,97 @@
|
|||
//
|
||||
// libtgvoip is free and unencumbered public domain software.
|
||||
// For more information, see http://unlicense.org or the UNLICENSE file
|
||||
// you should have received with this source code distribution.
|
||||
//
|
||||
|
||||
#include "AudioInput.h"
|
||||
#include "../logging.h"
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#if defined(TGVOIP_USE_CALLBACK_AUDIO_IO)
|
||||
// nothing
|
||||
#elif defined(__ANDROID__)
|
||||
#include "../os/android/AudioInputAndroid.h"
|
||||
#elif defined(__APPLE__)
|
||||
#include <TargetConditionals.h>
|
||||
#include "../os/darwin/AudioInputAudioUnit.h"
|
||||
#if TARGET_OS_OSX
|
||||
#include "../os/darwin/AudioInputAudioUnitOSX.h"
|
||||
#endif
|
||||
#elif defined(_WIN32)
|
||||
#ifdef TGVOIP_WINXP_COMPAT
|
||||
#include "../os/windows/AudioInputWave.h"
|
||||
#endif
|
||||
#include "../os/windows/AudioInputWASAPI.h"
|
||||
#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__gnu_hurd__)
|
||||
#ifndef WITHOUT_ALSA
|
||||
#include "../os/linux/AudioInputALSA.h"
|
||||
#endif
|
||||
#ifndef WITHOUT_PULSE
|
||||
#include "../os/linux/AudioPulse.h"
|
||||
#endif
|
||||
#else
|
||||
#error "Unsupported operating system"
|
||||
#endif
|
||||
|
||||
using namespace tgvoip;
|
||||
using namespace tgvoip::audio;
|
||||
|
||||
int32_t AudioInput::estimatedDelay=60;
|
||||
|
||||
AudioInput::AudioInput() : currentDevice("default"){
|
||||
failed=false;
|
||||
}
|
||||
|
||||
AudioInput::AudioInput(std::string deviceID) : currentDevice(deviceID){
|
||||
failed=false;
|
||||
}
|
||||
|
||||
|
||||
AudioInput::~AudioInput(){
|
||||
|
||||
}
|
||||
|
||||
bool AudioInput::IsInitialized(){
|
||||
return !failed;
|
||||
}
|
||||
|
||||
void AudioInput::EnumerateDevices(std::vector<AudioInputDevice>& devs){
|
||||
#if defined(TGVOIP_USE_CALLBACK_AUDIO_IO)
|
||||
// not supported
|
||||
#elif defined(__APPLE__) && TARGET_OS_OSX
|
||||
AudioInputAudioUnitLegacy::EnumerateDevices(devs);
|
||||
#elif defined(_WIN32)
|
||||
#ifdef TGVOIP_WINXP_COMPAT
|
||||
if(LOBYTE(LOWORD(GetVersion()))<6){
|
||||
AudioInputWave::EnumerateDevices(devs);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
AudioInputWASAPI::EnumerateDevices(devs);
|
||||
#elif defined(__linux__) && !defined(__ANDROID__)
|
||||
#if !defined(WITHOUT_PULSE) && !defined(WITHOUT_ALSA)
|
||||
if(!AudioInputPulse::EnumerateDevices(devs))
|
||||
AudioInputALSA::EnumerateDevices(devs);
|
||||
#elif defined(WITHOUT_PULSE)
|
||||
AudioInputALSA::EnumerateDevices(devs);
|
||||
#else
|
||||
AudioInputPulse::EnumerateDevices(devs);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string AudioInput::GetCurrentDevice(){
|
||||
return currentDevice;
|
||||
}
|
||||
|
||||
void AudioInput::SetCurrentDevice(std::string deviceID){
|
||||
|
||||
}
|
||||
|
||||
int32_t AudioInput::GetEstimatedDelay(){
|
||||
return estimatedDelay;
|
||||
}
|
41
TMessagesProj/jni/libtgvoip2/audio/AudioInput.h
Normal file
41
TMessagesProj/jni/libtgvoip2/audio/AudioInput.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
//
|
||||
// libtgvoip is free and unencumbered public domain software.
|
||||
// For more information, see http://unlicense.org or the UNLICENSE file
|
||||
// you should have received with this source code distribution.
|
||||
//
|
||||
|
||||
#ifndef LIBTGVOIP_AUDIOINPUT_H
|
||||
#define LIBTGVOIP_AUDIOINPUT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "../MediaStreamItf.h"
|
||||
|
||||
namespace tgvoip{
|
||||
|
||||
class AudioInputDevice;
|
||||
class AudioOutputDevice;
|
||||
|
||||
namespace audio{
|
||||
class AudioInput : public MediaStreamItf{
|
||||
public:
|
||||
AudioInput();
|
||||
AudioInput(std::string deviceID);
|
||||
virtual ~AudioInput();
|
||||
|
||||
bool IsInitialized();
|
||||
virtual std::string GetCurrentDevice();
|
||||
virtual void SetCurrentDevice(std::string deviceID);
|
||||
//static AudioInput* Create(std::string deviceID, void* platformSpecific);
|
||||
static void EnumerateDevices(std::vector<AudioInputDevice>& devs);
|
||||
static int32_t GetEstimatedDelay();
|
||||
|
||||
protected:
|
||||
std::string currentDevice;
|
||||
bool failed;
|
||||
static int32_t estimatedDelay;
|
||||
};
|
||||
}}
|
||||
|
||||
#endif //LIBTGVOIP_AUDIOINPUT_H
|
109
TMessagesProj/jni/libtgvoip2/audio/AudioOutput.cpp
Normal file
109
TMessagesProj/jni/libtgvoip2/audio/AudioOutput.cpp
Normal file
|
@ -0,0 +1,109 @@
|
|||
//
|
||||
// libtgvoip is free and unencumbered public domain software.
|
||||
// For more information, see http://unlicense.org or the UNLICENSE file
|
||||
// you should have received with this source code distribution.
|
||||
//
|
||||
|
||||
#include "AudioOutput.h"
|
||||
#include "../logging.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#if defined(TGVOIP_USE_CALLBACK_AUDIO_IO)
|
||||
// nothing
|
||||
#elif defined(__ANDROID__)
|
||||
#include "../os/android/AudioOutputOpenSLES.h"
|
||||
#include "../os/android/AudioOutputAndroid.h"
|
||||
#include <sys/system_properties.h>
|
||||
#elif defined(__APPLE__)
|
||||
#include <TargetConditionals.h>
|
||||
#include "../os/darwin/AudioOutputAudioUnit.h"
|
||||
#if TARGET_OS_OSX
|
||||
#include "../os/darwin/AudioOutputAudioUnitOSX.h"
|
||||
#endif
|
||||
#elif defined(_WIN32)
|
||||
#ifdef TGVOIP_WINXP_COMPAT
|
||||
#include "../os/windows/AudioOutputWave.h"
|
||||
#endif
|
||||
#include "../os/windows/AudioOutputWASAPI.h"
|
||||
#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__gnu_hurd__)
|
||||
#ifndef WITHOUT_ALSA
|
||||
#include "../os/linux/AudioOutputALSA.h"
|
||||
#endif
|
||||
#ifndef WITHOUT_PULSE
|
||||
#include "../os/linux/AudioOutputPulse.h"
|
||||
#include "../os/linux/AudioPulse.h"
|
||||
#endif
|
||||
#else
|
||||
#error "Unsupported operating system"
|
||||
#endif
|
||||
|
||||
using namespace tgvoip;
|
||||
using namespace tgvoip::audio;
|
||||
|
||||
int32_t AudioOutput::estimatedDelay=60;
|
||||
|
||||
AudioOutput::AudioOutput() : currentDevice("default"){
|
||||
failed=false;
|
||||
}
|
||||
|
||||
AudioOutput::AudioOutput(std::string deviceID) : currentDevice(deviceID){
|
||||
failed=false;
|
||||
}
|
||||
|
||||
AudioOutput::~AudioOutput(){
|
||||
|
||||
}
|
||||
|
||||
|
||||
int32_t AudioOutput::GetEstimatedDelay(){
|
||||
#if defined(__ANDROID__)
|
||||
char sdkNum[PROP_VALUE_MAX];
|
||||
__system_property_get("ro.build.version.sdk", sdkNum);
|
||||
int systemVersion=atoi(sdkNum);
|
||||
return systemVersion<21 ? 150 : 50;
|
||||
#endif
|
||||
return estimatedDelay;
|
||||
}
|
||||
|
||||
|
||||
void AudioOutput::EnumerateDevices(std::vector<AudioOutputDevice>& devs){
|
||||
#if defined(TGVOIP_USE_CALLBACK_AUDIO_IO)
|
||||
// not supported
|
||||
#elif defined(__APPLE__) && TARGET_OS_OSX
|
||||
AudioOutputAudioUnitLegacy::EnumerateDevices(devs);
|
||||
#elif defined(_WIN32)
|
||||
#ifdef TGVOIP_WINXP_COMPAT
|
||||
if(LOBYTE(LOWORD(GetVersion()))<6){
|
||||
AudioOutputWave::EnumerateDevices(devs);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
AudioOutputWASAPI::EnumerateDevices(devs);
|
||||
#elif defined(__linux__) && !defined(__ANDROID__)
|
||||
#if !defined(WITHOUT_PULSE) && !defined(WITHOUT_ALSA)
|
||||
if(!AudioOutputPulse::EnumerateDevices(devs))
|
||||
AudioOutputALSA::EnumerateDevices(devs);
|
||||
#elif defined(WITHOUT_PULSE)
|
||||
AudioOutputALSA::EnumerateDevices(devs);
|
||||
#else
|
||||
AudioOutputPulse::EnumerateDevices(devs);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
std::string AudioOutput::GetCurrentDevice(){
|
||||
return currentDevice;
|
||||
}
|
||||
|
||||
void AudioOutput::SetCurrentDevice(std::string deviceID){
|
||||
|
||||
}
|
||||
|
||||
bool AudioOutput::IsInitialized(){
|
||||
return !failed;
|
||||
}
|
42
TMessagesProj/jni/libtgvoip2/audio/AudioOutput.h
Normal file
42
TMessagesProj/jni/libtgvoip2/audio/AudioOutput.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
//
|
||||
// libtgvoip is free and unencumbered public domain software.
|
||||
// For more information, see http://unlicense.org or the UNLICENSE file
|
||||
// you should have received with this source code distribution.
|
||||
//
|
||||
|
||||
#ifndef LIBTGVOIP_AUDIOOUTPUT_H
|
||||
#define LIBTGVOIP_AUDIOOUTPUT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include "../MediaStreamItf.h"
|
||||
|
||||
namespace tgvoip{
|
||||
|
||||
class AudioInputDevice;
|
||||
class AudioOutputDevice;
|
||||
|
||||
namespace audio{
|
||||
class AudioOutput : public MediaStreamItf{
|
||||
public:
|
||||
AudioOutput();
|
||||
AudioOutput(std::string deviceID);
|
||||
virtual ~AudioOutput();
|
||||
virtual bool IsPlaying()=0;
|
||||
static int32_t GetEstimatedDelay();
|
||||
virtual std::string GetCurrentDevice();
|
||||
virtual void SetCurrentDevice(std::string deviceID);
|
||||
//static std::unique_ptr<AudioOutput> Create(std::string deviceID, void* platformSpecific);
|
||||
static void EnumerateDevices(std::vector<AudioOutputDevice>& devs);
|
||||
bool IsInitialized();
|
||||
|
||||
protected:
|
||||
std::string currentDevice;
|
||||
bool failed;
|
||||
static int32_t estimatedDelay;
|
||||
};
|
||||
}}
|
||||
|
||||
#endif //LIBTGVOIP_AUDIOOUTPUT_H
|
123
TMessagesProj/jni/libtgvoip2/audio/Resampler.cpp
Normal file
123
TMessagesProj/jni/libtgvoip2/audio/Resampler.cpp
Normal file
|
@ -0,0 +1,123 @@
|
|||
//
|
||||
// Created by Grishka on 01.04.17.
|
||||
//
|
||||
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include "Resampler.h"
|
||||
|
||||
using namespace tgvoip::audio;
|
||||
static constexpr int16_t hann[960] = {
|
||||
0x0000, 0x0000, 0x0000, 0x0001, 0x0001, 0x0002, 0x0003, 0x0004, 0x0006, 0x0007, 0x0009, 0x000B, 0x000D, 0x000F, 0x0011, 0x0014, 0x0016, 0x0019, 0x001C, 0x0020,
|
||||
0x0023, 0x0027, 0x002A, 0x002E, 0x0033, 0x0037, 0x003B, 0x0040, 0x0045, 0x004A, 0x004F, 0x0054, 0x005A, 0x0060, 0x0065, 0x006B, 0x0072, 0x0078, 0x007F, 0x0085,
|
||||
0x008C, 0x0093, 0x009B, 0x00A2, 0x00AA, 0x00B2, 0x00B9, 0x00C2, 0x00CA, 0x00D2, 0x00DB, 0x00E4, 0x00ED, 0x00F6, 0x00FF, 0x0109, 0x0113, 0x011C, 0x0127, 0x0131,
|
||||
0x013B, 0x0146, 0x0150, 0x015B, 0x0166, 0x0172, 0x017D, 0x0189, 0x0194, 0x01A0, 0x01AC, 0x01B9, 0x01C5, 0x01D2, 0x01DF, 0x01EC, 0x01F9, 0x0206, 0x0213, 0x0221,
|
||||
0x022F, 0x023D, 0x024B, 0x0259, 0x0268, 0x0276, 0x0285, 0x0294, 0x02A3, 0x02B3, 0x02C2, 0x02D2, 0x02E2, 0x02F2, 0x0302, 0x0312, 0x0323, 0x0333, 0x0344, 0x0355,
|
||||
0x0366, 0x0378, 0x0389, 0x039B, 0x03AD, 0x03BF, 0x03D1, 0x03E3, 0x03F6, 0x0408, 0x041B, 0x042E, 0x0441, 0x0455, 0x0468, 0x047C, 0x0490, 0x04A4, 0x04B8, 0x04CC,
|
||||
0x04E0, 0x04F5, 0x050A, 0x051F, 0x0534, 0x0549, 0x055F, 0x0574, 0x058A, 0x05A0, 0x05B6, 0x05CC, 0x05E2, 0x05F9, 0x0610, 0x0627, 0x063E, 0x0655, 0x066C, 0x0684,
|
||||
0x069B, 0x06B3, 0x06CB, 0x06E3, 0x06FC, 0x0714, 0x072D, 0x0745, 0x075E, 0x0777, 0x0791, 0x07AA, 0x07C3, 0x07DD, 0x07F7, 0x0811, 0x082B, 0x0845, 0x0860, 0x087A,
|
||||
0x0895, 0x08B0, 0x08CB, 0x08E6, 0x0902, 0x091D, 0x0939, 0x0955, 0x0971, 0x098D, 0x09A9, 0x09C6, 0x09E2, 0x09FF, 0x0A1C, 0x0A39, 0x0A56, 0x0A73, 0x0A91, 0x0AAE,
|
||||
0x0ACC, 0x0AEA, 0x0B08, 0x0B26, 0x0B44, 0x0B63, 0x0B81, 0x0BA0, 0x0BBF, 0x0BDE, 0x0BFD, 0x0C1D, 0x0C3C, 0x0C5C, 0x0C7B, 0x0C9B, 0x0CBB, 0x0CDC, 0x0CFC, 0x0D1C,
|
||||
0x0D3D, 0x0D5E, 0x0D7F, 0x0DA0, 0x0DC1, 0x0DE2, 0x0E04, 0x0E25, 0x0E47, 0x0E69, 0x0E8B, 0x0EAD, 0x0ECF, 0x0EF1, 0x0F14, 0x0F37, 0x0F59, 0x0F7C, 0x0F9F, 0x0FC2,
|
||||
0x0FE6, 0x1009, 0x102D, 0x1051, 0x1074, 0x1098, 0x10BC, 0x10E1, 0x1105, 0x112A, 0x114E, 0x1173, 0x1198, 0x11BD, 0x11E2, 0x1207, 0x122D, 0x1252, 0x1278, 0x129D,
|
||||
0x12C3, 0x12E9, 0x130F, 0x1336, 0x135C, 0x1383, 0x13A9, 0x13D0, 0x13F7, 0x141E, 0x1445, 0x146C, 0x1494, 0x14BB, 0x14E3, 0x150A, 0x1532, 0x155A, 0x1582, 0x15AA,
|
||||
0x15D3, 0x15FB, 0x1623, 0x164C, 0x1675, 0x169E, 0x16C7, 0x16F0, 0x1719, 0x1742, 0x176C, 0x1795, 0x17BF, 0x17E9, 0x1813, 0x183D, 0x1867, 0x1891, 0x18BB, 0x18E6,
|
||||
0x1910, 0x193B, 0x1965, 0x1990, 0x19BB, 0x19E6, 0x1A11, 0x1A3D, 0x1A68, 0x1A93, 0x1ABF, 0x1AEB, 0x1B17, 0x1B42, 0x1B6E, 0x1B9A, 0x1BC7, 0x1BF3, 0x1C1F, 0x1C4C,
|
||||
0x1C78, 0x1CA5, 0x1CD2, 0x1CFF, 0x1D2C, 0x1D59, 0x1D86, 0x1DB3, 0x1DE0, 0x1E0E, 0x1E3B, 0x1E69, 0x1E97, 0x1EC4, 0x1EF2, 0x1F20, 0x1F4E, 0x1F7C, 0x1FAB, 0x1FD9,
|
||||
0x2007, 0x2036, 0x2065, 0x2093, 0x20C2, 0x20F1, 0x2120, 0x214F, 0x217E, 0x21AD, 0x21DD, 0x220C, 0x223B, 0x226B, 0x229A, 0x22CA, 0x22FA, 0x232A, 0x235A, 0x238A,
|
||||
0x23BA, 0x23EA, 0x241A, 0x244B, 0x247B, 0x24AB, 0x24DC, 0x250D, 0x253D, 0x256E, 0x259F, 0x25D0, 0x2601, 0x2632, 0x2663, 0x2694, 0x26C5, 0x26F7, 0x2728, 0x275A,
|
||||
0x278B, 0x27BD, 0x27EE, 0x2820, 0x2852, 0x2884, 0x28B6, 0x28E8, 0x291A, 0x294C, 0x297E, 0x29B0, 0x29E3, 0x2A15, 0x2A47, 0x2A7A, 0x2AAC, 0x2ADF, 0x2B12, 0x2B44,
|
||||
0x2B77, 0x2BAA, 0x2BDD, 0x2C10, 0x2C43, 0x2C76, 0x2CA9, 0x2CDC, 0x2D0F, 0x2D43, 0x2D76, 0x2DA9, 0x2DDD, 0x2E10, 0x2E44, 0x2E77, 0x2EAB, 0x2EDF, 0x2F12, 0x2F46,
|
||||
0x2F7A, 0x2FAE, 0x2FE2, 0x3016, 0x304A, 0x307E, 0x30B2, 0x30E6, 0x311A, 0x314E, 0x3182, 0x31B7, 0x31EB, 0x321F, 0x3254, 0x3288, 0x32BD, 0x32F1, 0x3326, 0x335A,
|
||||
0x338F, 0x33C3, 0x33F8, 0x342D, 0x3461, 0x3496, 0x34CB, 0x3500, 0x3535, 0x356A, 0x359F, 0x35D4, 0x3608, 0x363D, 0x3673, 0x36A8, 0x36DD, 0x3712, 0x3747, 0x377C,
|
||||
0x37B1, 0x37E6, 0x381C, 0x3851, 0x3886, 0x38BB, 0x38F1, 0x3926, 0x395B, 0x3991, 0x39C6, 0x39FC, 0x3A31, 0x3A66, 0x3A9C, 0x3AD1, 0x3B07, 0x3B3C, 0x3B72, 0x3BA7,
|
||||
0x3BDD, 0x3C12, 0x3C48, 0x3C7D, 0x3CB3, 0x3CE9, 0x3D1E, 0x3D54, 0x3D89, 0x3DBF, 0x3DF5, 0x3E2A, 0x3E60, 0x3E95, 0x3ECB, 0x3F01, 0x3F36, 0x3F6C, 0x3FA2, 0x3FD7,
|
||||
0x400D, 0x4043, 0x4078, 0x40AE, 0x40E3, 0x4119, 0x414F, 0x4184, 0x41BA, 0x41F0, 0x4225, 0x425B, 0x4290, 0x42C6, 0x42FC, 0x4331, 0x4367, 0x439C, 0x43D2, 0x4407,
|
||||
0x443D, 0x4472, 0x44A8, 0x44DD, 0x4513, 0x4548, 0x457E, 0x45B3, 0x45E9, 0x461E, 0x4654, 0x4689, 0x46BE, 0x46F4, 0x4729, 0x475E, 0x4793, 0x47C9, 0x47FE, 0x4833,
|
||||
0x4868, 0x489E, 0x48D3, 0x4908, 0x493D, 0x4972, 0x49A7, 0x49DC, 0x4A11, 0x4A46, 0x4A7B, 0x4AB0, 0x4AE5, 0x4B1A, 0x4B4E, 0x4B83, 0x4BB8, 0x4BED, 0x4C21, 0x4C56,
|
||||
0x4C8B, 0x4CBF, 0x4CF4, 0x4D28, 0x4D5D, 0x4D91, 0x4DC6, 0x4DFA, 0x4E2E, 0x4E63, 0x4E97, 0x4ECB, 0x4EFF, 0x4F33, 0x4F67, 0x4F9B, 0x4FCF, 0x5003, 0x5037, 0x506B,
|
||||
0x509F, 0x50D3, 0x5106, 0x513A, 0x516E, 0x51A1, 0x51D5, 0x5208, 0x523C, 0x526F, 0x52A3, 0x52D6, 0x5309, 0x533C, 0x536F, 0x53A3, 0x53D6, 0x5409, 0x543B, 0x546E,
|
||||
0x54A1, 0x54D4, 0x5507, 0x5539, 0x556C, 0x559E, 0x55D1, 0x5603, 0x5636, 0x5668, 0x569A, 0x56CC, 0x56FE, 0x5730, 0x5762, 0x5794, 0x57C6, 0x57F8, 0x5829, 0x585B,
|
||||
0x588D, 0x58BE, 0x58F0, 0x5921, 0x5952, 0x5984, 0x59B5, 0x59E6, 0x5A17, 0x5A48, 0x5A79, 0x5AA9, 0x5ADA, 0x5B0B, 0x5B3B, 0x5B6C, 0x5B9C, 0x5BCD, 0x5BFD, 0x5C2D,
|
||||
0x5C5D, 0x5C8D, 0x5CBD, 0x5CED, 0x5D1D, 0x5D4D, 0x5D7C, 0x5DAC, 0x5DDB, 0x5E0B, 0x5E3A, 0x5E69, 0x5E99, 0x5EC8, 0x5EF7, 0x5F26, 0x5F54, 0x5F83, 0x5FB2, 0x5FE0,
|
||||
0x600F, 0x603D, 0x606B, 0x609A, 0x60C8, 0x60F6, 0x6124, 0x6152, 0x617F, 0x61AD, 0x61DB, 0x6208, 0x6235, 0x6263, 0x6290, 0x62BD, 0x62EA, 0x6317, 0x6344, 0x6370,
|
||||
0x639D, 0x63CA, 0x63F6, 0x6422, 0x644E, 0x647B, 0x64A7, 0x64D3, 0x64FE, 0x652A, 0x6556, 0x6581, 0x65AD, 0x65D8, 0x6603, 0x662E, 0x6659, 0x6684, 0x66AF, 0x66DA,
|
||||
0x6704, 0x672F, 0x6759, 0x6783, 0x67AD, 0x67D7, 0x6801, 0x682B, 0x6855, 0x687E, 0x68A8, 0x68D1, 0x68FB, 0x6924, 0x694D, 0x6976, 0x699F, 0x69C7, 0x69F0, 0x6A18,
|
||||
0x6A41, 0x6A69, 0x6A91, 0x6AB9, 0x6AE1, 0x6B09, 0x6B30, 0x6B58, 0x6B7F, 0x6BA6, 0x6BCE, 0x6BF5, 0x6C1C, 0x6C42, 0x6C69, 0x6C90, 0x6CB6, 0x6CDC, 0x6D03, 0x6D29,
|
||||
0x6D4F, 0x6D74, 0x6D9A, 0x6DC0, 0x6DE5, 0x6E0A, 0x6E30, 0x6E55, 0x6E7A, 0x6E9E, 0x6EC3, 0x6EE8, 0x6F0C, 0x6F30, 0x6F55, 0x6F79, 0x6F9D, 0x6FC0, 0x6FE4, 0x7008,
|
||||
0x702B, 0x704E, 0x7071, 0x7094, 0x70B7, 0x70DA, 0x70FC, 0x711F, 0x7141, 0x7163, 0x7185, 0x71A7, 0x71C9, 0x71EB, 0x720C, 0x722E, 0x724F, 0x7270, 0x7291, 0x72B2,
|
||||
0x72D2, 0x72F3, 0x7313, 0x7333, 0x7354, 0x7374, 0x7393, 0x73B3, 0x73D3, 0x73F2, 0x7411, 0x7430, 0x744F, 0x746E, 0x748D, 0x74AB, 0x74CA, 0x74E8, 0x7506, 0x7524,
|
||||
0x7542, 0x7560, 0x757D, 0x759B, 0x75B8, 0x75D5, 0x75F2, 0x760F, 0x762B, 0x7648, 0x7664, 0x7680, 0x769C, 0x76B8, 0x76D4, 0x76F0, 0x770B, 0x7726, 0x7741, 0x775C,
|
||||
0x7777, 0x7792, 0x77AC, 0x77C7, 0x77E1, 0x77FB, 0x7815, 0x782F, 0x7848, 0x7862, 0x787B, 0x7894, 0x78AD, 0x78C6, 0x78DF, 0x78F7, 0x7910, 0x7928, 0x7940, 0x7958,
|
||||
0x7970, 0x7987, 0x799F, 0x79B6, 0x79CD, 0x79E4, 0x79FB, 0x7A11, 0x7A28, 0x7A3E, 0x7A54, 0x7A6A, 0x7A80, 0x7A96, 0x7AAB, 0x7AC1, 0x7AD6, 0x7AEB, 0x7B00, 0x7B14,
|
||||
0x7B29, 0x7B3D, 0x7B51, 0x7B65, 0x7B79, 0x7B8D, 0x7BA1, 0x7BB4, 0x7BC7, 0x7BDA, 0x7BED, 0x7C00, 0x7C13, 0x7C25, 0x7C37, 0x7C49, 0x7C5B, 0x7C6D, 0x7C7F, 0x7C90,
|
||||
0x7CA1, 0x7CB2, 0x7CC3, 0x7CD4, 0x7CE5, 0x7CF5, 0x7D05, 0x7D15, 0x7D25, 0x7D35, 0x7D45, 0x7D54, 0x7D63, 0x7D72, 0x7D81, 0x7D90, 0x7D9F, 0x7DAD, 0x7DBB, 0x7DC9,
|
||||
0x7DD7, 0x7DE5, 0x7DF2, 0x7E00, 0x7E0D, 0x7E1A, 0x7E27, 0x7E34, 0x7E40, 0x7E4C, 0x7E59, 0x7E65, 0x7E71, 0x7E7C, 0x7E88, 0x7E93, 0x7E9E, 0x7EA9, 0x7EB4, 0x7EBF,
|
||||
0x7EC9, 0x7ED3, 0x7EDE, 0x7EE7, 0x7EF1, 0x7EFB, 0x7F04, 0x7F0E, 0x7F17, 0x7F20, 0x7F28, 0x7F31, 0x7F39, 0x7F41, 0x7F4A, 0x7F51, 0x7F59, 0x7F61, 0x7F68, 0x7F6F,
|
||||
0x7F76, 0x7F7D, 0x7F84, 0x7F8A, 0x7F90, 0x7F97, 0x7F9D, 0x7FA2, 0x7FA8, 0x7FAD, 0x7FB3, 0x7FB8, 0x7FBD, 0x7FC1, 0x7FC6, 0x7FCA, 0x7FCF, 0x7FD3, 0x7FD6, 0x7FDA,
|
||||
0x7FDE, 0x7FE1, 0x7FE4, 0x7FE7, 0x7FEA, 0x7FED, 0x7FEF, 0x7FF1, 0x7FF3, 0x7FF5, 0x7FF7, 0x7FF9, 0x7FFA, 0x7FFB, 0x7FFC, 0x7FFD, 0x7FFE, 0x7FFE, 0x7FFF, 0x7FFF
|
||||
};
|
||||
|
||||
#define MIN(a, b) (((a)<(b)) ? (a) : (b))
|
||||
|
||||
size_t Resampler::Convert48To44(int16_t* from, int16_t* to, size_t fromLen, size_t toLen) {
|
||||
size_t outLen = fromLen * 147 / 160;
|
||||
if (toLen < outLen)
|
||||
outLen = toLen;
|
||||
for (unsigned int offset = 0; offset < outLen; offset++) {
|
||||
float offsetf = offset * 160.0f / 147.0f;
|
||||
float factor = offsetf - floorf(offsetf);
|
||||
to[offset] = static_cast<int16_t>(from[static_cast<size_t>(floorf(offsetf))] * (1 - factor) +
|
||||
from[static_cast<size_t>(ceilf(offsetf))] * factor);
|
||||
}
|
||||
return outLen;
|
||||
}
|
||||
|
||||
size_t Resampler::Convert44To48(int16_t* from, int16_t* to, size_t fromLen, size_t toLen) {
|
||||
size_t outLen = fromLen * 160 / 147;
|
||||
if (toLen < outLen)
|
||||
outLen = toLen;
|
||||
unsigned int offset;
|
||||
for (offset = 0; offset < outLen; offset++) {
|
||||
float offsetf = offset * 147.0f / 160.0f;
|
||||
float factor = offsetf - floorf(offsetf);
|
||||
to[offset] = static_cast<int16_t>(from[static_cast<size_t>(floorf(offsetf))] * (1 - factor) +
|
||||
from[static_cast<size_t>(ceilf(offsetf))] * factor);
|
||||
}
|
||||
return outLen;
|
||||
}
|
||||
|
||||
|
||||
size_t Resampler::Convert(int16_t* from, int16_t* to, size_t fromLen, size_t toLen, size_t num, size_t denom) {
|
||||
size_t outLen = fromLen * num / denom;
|
||||
if (toLen < outLen)
|
||||
outLen = toLen;
|
||||
unsigned int offset;
|
||||
for (offset = 0; offset < outLen; offset++) {
|
||||
float offsetf = offset * static_cast<float>(denom) / static_cast<float>(num);
|
||||
float factor = offsetf - floorf(offsetf);
|
||||
to[offset] = static_cast<int16_t>(from[static_cast<size_t>(floorf(offsetf))] * (1 - factor) +
|
||||
from[static_cast<size_t>(ceilf(offsetf))] * factor);
|
||||
}
|
||||
return outLen;
|
||||
}
|
||||
|
||||
void Resampler::Rescale60To80(int16_t* in, int16_t* out) {
|
||||
std::memcpy(out, in, 960 * 2);
|
||||
std::memcpy(out + 960 * 3, in + 960 * 2, 960 * 2);
|
||||
for (int i = 0; i < 960; i++) {
|
||||
out[960 + i] = static_cast<int16_t>(((static_cast<int32_t>(in[960 + i]) * hann[959 - i]) >> 15) +
|
||||
((static_cast<int32_t>(in[480 + i]) * hann[i]) >> 15));
|
||||
out[1920 + i] = static_cast<int16_t>(((static_cast<int32_t>(in[960 + 480 + i]) * hann[959 - i]) >> 15) +
|
||||
((static_cast<int32_t>(in[480 + 480 + i]) * hann[i]) >> 15));
|
||||
}
|
||||
}
|
||||
|
||||
void Resampler::Rescale60To40(int16_t* in, int16_t* out) {
|
||||
for (int i = 0; i < 960; i++) {
|
||||
out[i] = static_cast<int16_t>(((static_cast<int32_t>(in[i]) * hann[959 - i]) >> 15) +
|
||||
((static_cast<int32_t>(in[480 + i]) * hann[i]) >> 15));
|
||||
out[960 + i] = static_cast<int16_t>(((static_cast<int32_t>(in[1920 + i]) * hann[i]) >> 15) +
|
||||
((static_cast<int32_t>(in[1440 + i]) * hann[959 - i]) >> 15));
|
||||
}
|
||||
}
|
24
TMessagesProj/jni/libtgvoip2/audio/Resampler.h
Normal file
24
TMessagesProj/jni/libtgvoip2/audio/Resampler.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
//
|
||||
// Created by Grishka on 01.04.17.
|
||||
//
|
||||
|
||||
#ifndef LIBTGVOIP_RESAMPLER_H
|
||||
#define LIBTGVOIP_RESAMPLER_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace tgvoip {
|
||||
namespace audio {
|
||||
class Resampler {
|
||||
public:
|
||||
static size_t Convert48To44(int16_t* from, int16_t* to, size_t fromLen, size_t toLen);
|
||||
static size_t Convert44To48(int16_t* from, int16_t* to, size_t fromLen, size_t toLen);
|
||||
static size_t Convert(int16_t* from, int16_t* to, size_t fromLen, size_t toLen, size_t num, size_t denom);
|
||||
static void Rescale60To80(int16_t* in, int16_t* out);
|
||||
static void Rescale60To40(int16_t* in, int16_t* out);
|
||||
};
|
||||
} // namespace audio
|
||||
} // namespace tgvoip
|
||||
|
||||
#endif //LIBTGVOIP_RESAMPLER_H
|
|
@ -0,0 +1,405 @@
|
|||
#include <jni.h>
|
||||
#include <TgVoip.h>
|
||||
#include <os/android/AudioOutputOpenSLES.h>
|
||||
#include <os/android/AudioInputOpenSLES.h>
|
||||
#include <os/android/JNIUtilities.h>
|
||||
#include "org_telegram_messenger_voip_TgVoip.h"
|
||||
|
||||
using namespace tgvoip;
|
||||
|
||||
extern "C" int tgvoipOnJniLoad(JavaVM *vm, JNIEnv *env) {
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
#pragma mark - Helpers
|
||||
|
||||
class JavaObject {
|
||||
private:
|
||||
JNIEnv *env;
|
||||
jobject obj;
|
||||
jclass clazz;
|
||||
|
||||
public:
|
||||
JavaObject(JNIEnv *env, jobject obj) : JavaObject(env, obj, env->GetObjectClass(obj)) {
|
||||
}
|
||||
|
||||
JavaObject(JNIEnv *env, jobject obj, jclass clazz) {
|
||||
this->env = env;
|
||||
this->obj = obj;
|
||||
this->clazz = clazz;
|
||||
}
|
||||
|
||||
jint getIntField(const char *name) {
|
||||
return env->GetIntField(obj, env->GetFieldID(clazz, name, "I"));
|
||||
}
|
||||
|
||||
jlong getLongField(const char *name) {
|
||||
return env->GetLongField(obj, env->GetFieldID(clazz, name, "J"));
|
||||
}
|
||||
|
||||
jboolean getBooleanField(const char *name) {
|
||||
return env->GetBooleanField(obj, env->GetFieldID(clazz, name, "Z"));
|
||||
}
|
||||
|
||||
jdouble getDoubleField(const char *name) {
|
||||
return env->GetDoubleField(obj, env->GetFieldID(clazz, name, "D"));
|
||||
}
|
||||
|
||||
jbyteArray getByteArrayField(const char *name) {
|
||||
return (jbyteArray) env->GetObjectField(obj, env->GetFieldID(clazz, name, "[B"));
|
||||
}
|
||||
|
||||
jstring getStringField(const char *name) {
|
||||
return (jstring) env->GetObjectField(obj, env->GetFieldID(clazz, name, "Ljava/lang/String;"));
|
||||
}
|
||||
};
|
||||
|
||||
struct InstanceHolder {
|
||||
TgVoip *nativeInstance;
|
||||
jobject javaInstance;
|
||||
};
|
||||
|
||||
jlong getInstanceHolderId(JNIEnv *env, jobject obj) {
|
||||
return env->GetLongField(obj, env->GetFieldID(env->GetObjectClass(obj), "nativeInstanceId", "J"));
|
||||
}
|
||||
|
||||
InstanceHolder *getInstanceHolder(JNIEnv *env, jobject obj) {
|
||||
return reinterpret_cast<InstanceHolder *>(getInstanceHolderId(env, obj));
|
||||
}
|
||||
|
||||
TgVoip *getTgVoip(JNIEnv *env, jobject obj) {
|
||||
return getInstanceHolder(env, obj)->nativeInstance;
|
||||
}
|
||||
|
||||
jint throwNewJavaException(JNIEnv *env, const char *className, const char *message) {
|
||||
return env->ThrowNew(env->FindClass(className), message);
|
||||
}
|
||||
|
||||
jint throwNewJavaIllegalArgumentException(JNIEnv *env, const char *message) {
|
||||
return throwNewJavaException(env, "java/lang/IllegalStateException", message);
|
||||
}
|
||||
|
||||
jbyteArray copyVectorToJavaByteArray(JNIEnv *env, const std::vector<uint8_t> &bytes) {
|
||||
unsigned int size = bytes.size();
|
||||
jbyteArray bytesArray = env->NewByteArray(size);
|
||||
env->SetByteArrayRegion(bytesArray, 0, size, (jbyte *) bytes.data());
|
||||
return bytesArray;
|
||||
}
|
||||
|
||||
void readTgVoipPersistentState(const char *filePath, TgVoipPersistentState &tgVoipPersistentState) {
|
||||
FILE *persistentStateFile = fopen(filePath, "r");
|
||||
if (persistentStateFile) {
|
||||
fseek(persistentStateFile, 0, SEEK_END);
|
||||
auto len = static_cast<size_t>(ftell(persistentStateFile));
|
||||
fseek(persistentStateFile, 0, SEEK_SET);
|
||||
if (len < 1024 * 512 && len > 0) {
|
||||
auto *buffer = static_cast<uint8_t *>(malloc(len));
|
||||
fread(buffer, 1, len, persistentStateFile);
|
||||
tgVoipPersistentState.value = std::vector<uint8_t>(buffer, buffer + len);
|
||||
free(buffer);
|
||||
}
|
||||
fclose(persistentStateFile);
|
||||
}
|
||||
}
|
||||
|
||||
void saveTgVoipPersistentState(const char *filePath, const TgVoipPersistentState &tgVoipPersistentState) {
|
||||
FILE *persistentStateFile = fopen(filePath, "w");
|
||||
if (persistentStateFile) {
|
||||
fwrite(tgVoipPersistentState.value.data(), 1, tgVoipPersistentState.value.size(), persistentStateFile);
|
||||
fclose(persistentStateFile);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Mappers
|
||||
|
||||
TgVoipNetworkType parseTgVoipNetworkType(jint networkType) {
|
||||
switch (networkType) {
|
||||
case org_telegram_messenger_voip_TgVoip_NET_TYPE_GPRS:
|
||||
return TgVoipNetworkType::Gprs;
|
||||
case org_telegram_messenger_voip_TgVoip_NET_TYPE_EDGE:
|
||||
return TgVoipNetworkType::Edge;
|
||||
case org_telegram_messenger_voip_TgVoip_NET_TYPE_3G:
|
||||
return TgVoipNetworkType::ThirdGeneration;
|
||||
case org_telegram_messenger_voip_TgVoip_NET_TYPE_HSPA:
|
||||
return TgVoipNetworkType::Hspa;
|
||||
case org_telegram_messenger_voip_TgVoip_NET_TYPE_LTE:
|
||||
return TgVoipNetworkType::Lte;
|
||||
case org_telegram_messenger_voip_TgVoip_NET_TYPE_WIFI:
|
||||
return TgVoipNetworkType::WiFi;
|
||||
case org_telegram_messenger_voip_TgVoip_NET_TYPE_ETHERNET:
|
||||
return TgVoipNetworkType::Ethernet;
|
||||
case org_telegram_messenger_voip_TgVoip_NET_TYPE_OTHER_HIGH_SPEED:
|
||||
return TgVoipNetworkType::OtherHighSpeed;
|
||||
case org_telegram_messenger_voip_TgVoip_NET_TYPE_OTHER_LOW_SPEED:
|
||||
return TgVoipNetworkType::OtherLowSpeed;
|
||||
case org_telegram_messenger_voip_TgVoip_NET_TYPE_DIALUP:
|
||||
return TgVoipNetworkType::Dialup;
|
||||
case org_telegram_messenger_voip_TgVoip_NET_TYPE_OTHER_MOBILE:
|
||||
return TgVoipNetworkType::OtherMobile;
|
||||
default:
|
||||
return TgVoipNetworkType::Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
TgVoipDataSaving parseTgVoipDataSaving(JNIEnv *env, jint dataSaving) {
|
||||
switch (dataSaving) {
|
||||
case org_telegram_messenger_voip_TgVoip_DATA_SAVING_NEVER:
|
||||
return TgVoipDataSaving::Never;
|
||||
case org_telegram_messenger_voip_TgVoip_DATA_SAVING_MOBILE:
|
||||
return TgVoipDataSaving::Mobile;
|
||||
case org_telegram_messenger_voip_TgVoip_DATA_SAVING_ALWAYS:
|
||||
return TgVoipDataSaving::Always;
|
||||
case org_telegram_messenger_voip_TgVoip_DATA_SAVING_ROAMING:
|
||||
throwNewJavaIllegalArgumentException(env, "DATA_SAVING_ROAMING is not supported");
|
||||
return TgVoipDataSaving::Never;
|
||||
default:
|
||||
throwNewJavaIllegalArgumentException(env, "Unknown data saving constant: " + dataSaving);
|
||||
return TgVoipDataSaving::Never;
|
||||
}
|
||||
}
|
||||
|
||||
void parseTgVoipConfig(JNIEnv *env, jobject config, TgVoipConfig &tgVoipConfig) {
|
||||
JavaObject configObject(env, config);
|
||||
tgVoipConfig.initializationTimeout = configObject.getDoubleField("initializationTimeout");
|
||||
tgVoipConfig.receiveTimeout = configObject.getDoubleField("receiveTimeout");
|
||||
tgVoipConfig.dataSaving = parseTgVoipDataSaving(env, configObject.getIntField("dataSaving"));
|
||||
tgVoipConfig.enableP2P = configObject.getBooleanField("enableP2p") == JNI_TRUE;
|
||||
tgVoipConfig.enableAEC = configObject.getBooleanField("enableAec") == JNI_TRUE;
|
||||
tgVoipConfig.enableNS = configObject.getBooleanField("enableNs") == JNI_TRUE;
|
||||
tgVoipConfig.enableAGC = configObject.getBooleanField("enableAgc") == JNI_TRUE;
|
||||
tgVoipConfig.enableCallUpgrade = configObject.getBooleanField("enableCallUpgrade") == JNI_TRUE;
|
||||
tgVoipConfig.logPath = jni::JavaStringToStdString(env, configObject.getStringField("logPath"));
|
||||
tgVoipConfig.maxApiLayer = configObject.getIntField("maxApiLayer");
|
||||
}
|
||||
|
||||
TgVoipEndpointType parseTgVoipEndpointType(JNIEnv *env, jint endpointType) {
|
||||
switch (endpointType) {
|
||||
case org_telegram_messenger_voip_TgVoip_ENDPOINT_TYPE_INET:
|
||||
return TgVoipEndpointType::Inet;
|
||||
case org_telegram_messenger_voip_TgVoip_ENDPOINT_TYPE_LAN:
|
||||
return TgVoipEndpointType::Lan;
|
||||
case org_telegram_messenger_voip_TgVoip_ENDPOINT_TYPE_TCP_RELAY:
|
||||
return TgVoipEndpointType::TcpRelay;
|
||||
case org_telegram_messenger_voip_TgVoip_ENDPOINT_TYPE_UDP_RELAY:
|
||||
return TgVoipEndpointType::UdpRelay;
|
||||
default:
|
||||
throwNewJavaIllegalArgumentException(env, std::string("Unknown endpoint type: ").append(std::to_string(endpointType)).c_str());
|
||||
return TgVoipEndpointType::UdpRelay;
|
||||
}
|
||||
}
|
||||
|
||||
void parseTgVoipEndpoint(JNIEnv *env, jobject endpoint, TgVoipEndpoint &tgVoipEndpoint) {
|
||||
JavaObject endpointObject(env, endpoint);
|
||||
tgVoipEndpoint.endpointId = endpointObject.getLongField("id");
|
||||
tgVoipEndpoint.host = {
|
||||
.ipv4 = jni::JavaStringToStdString(env, endpointObject.getStringField("ipv4")),
|
||||
.ipv6 = jni::JavaStringToStdString(env, endpointObject.getStringField("ipv6"))
|
||||
};
|
||||
tgVoipEndpoint.port = static_cast<uint16_t>(endpointObject.getIntField("port"));
|
||||
tgVoipEndpoint.type = parseTgVoipEndpointType(env, endpointObject.getIntField("type"));
|
||||
jbyteArray peerTag = endpointObject.getByteArrayField("peerTag");
|
||||
if (peerTag && env->GetArrayLength(peerTag)) {
|
||||
jbyte *peerTagBytes = env->GetByteArrayElements(peerTag, nullptr);
|
||||
memcpy(tgVoipEndpoint.peerTag, peerTagBytes, 16);
|
||||
env->ReleaseByteArrayElements(peerTag, peerTagBytes, JNI_ABORT);
|
||||
}
|
||||
}
|
||||
|
||||
void parseTgVoipEndpoints(JNIEnv *env, jobjectArray endpoints, std::vector<TgVoipEndpoint> &tgVoipEndpoints) {
|
||||
for (int i = 0, size = env->GetArrayLength(endpoints); i < size; i++) {
|
||||
TgVoipEndpoint tgVoipEndpoint;
|
||||
parseTgVoipEndpoint(env, env->GetObjectArrayElement(endpoints, i), tgVoipEndpoint);
|
||||
tgVoipEndpoints.push_back(tgVoipEndpoint);
|
||||
}
|
||||
}
|
||||
|
||||
void parseTgVoipEncryptionKey(JNIEnv *env, jobject encryptionKey, TgVoipEncryptionKey &tgVoipEncryptionKey) {
|
||||
JavaObject encryptionKeyObject(env, encryptionKey);
|
||||
tgVoipEncryptionKey.isOutgoing = encryptionKeyObject.getBooleanField("isOutgoing") == JNI_TRUE;
|
||||
jbyteArray valueByteArray = encryptionKeyObject.getByteArrayField("value");
|
||||
auto *valueBytes = (uint8_t *) env->GetByteArrayElements(valueByteArray, nullptr);
|
||||
tgVoipEncryptionKey.value = std::vector<uint8_t>(valueBytes, valueBytes + env->GetArrayLength(valueByteArray));
|
||||
env->ReleaseByteArrayElements(valueByteArray, (jbyte *) valueBytes, JNI_ABORT);
|
||||
}
|
||||
|
||||
void parseTgVoipProxy(JNIEnv *env, jobject proxy, std::unique_ptr<TgVoipProxy> &tgVoipProxy) {
|
||||
if (!env->IsSameObject(proxy, nullptr)) {
|
||||
JavaObject proxyObject(env, proxy);
|
||||
tgVoipProxy = std::unique_ptr<TgVoipProxy>(new TgVoipProxy);
|
||||
tgVoipProxy->host = jni::JavaStringToStdString(env, proxyObject.getStringField("host"));
|
||||
tgVoipProxy->port = static_cast<uint16_t>(proxyObject.getIntField("port"));
|
||||
tgVoipProxy->login = jni::JavaStringToStdString(env, proxyObject.getStringField("login"));
|
||||
tgVoipProxy->password = jni::JavaStringToStdString(env, proxyObject.getStringField("password"));
|
||||
} else {
|
||||
tgVoipProxy = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
jint asJavaState(const TgVoipState &tgVoipState) {
|
||||
switch (tgVoipState) {
|
||||
case TgVoipState::WaitInit:
|
||||
return org_telegram_messenger_voip_TgVoip_STATE_WAIT_INIT;
|
||||
case TgVoipState::WaitInitAck:
|
||||
return org_telegram_messenger_voip_TgVoip_STATE_WAIT_INIT_ACK;
|
||||
case TgVoipState::Estabilished:
|
||||
return org_telegram_messenger_voip_TgVoip_STATE_ESTABLISHED;
|
||||
case TgVoipState::Failed:
|
||||
return org_telegram_messenger_voip_TgVoip_STATE_FAILED;
|
||||
case TgVoipState::Reconnecting:
|
||||
return org_telegram_messenger_voip_TgVoip_STATE_RECONNECTING;
|
||||
}
|
||||
}
|
||||
|
||||
jobject asJavaTrafficStats(JNIEnv *env, const TgVoipTrafficStats &trafficStats) {
|
||||
jclass clazz = env->FindClass("org/telegram/messenger/voip/TgVoip$TrafficStats");
|
||||
jmethodID initMethodId = env->GetMethodID(clazz, "<init>", "(JJJJ)V");
|
||||
return env->NewObject(clazz, initMethodId, trafficStats.bytesSentWifi, trafficStats.bytesReceivedWifi, trafficStats.bytesSentMobile, trafficStats.bytesReceivedMobile);
|
||||
}
|
||||
|
||||
jobject asJavaFinalState(JNIEnv *env, const TgVoipFinalState &tgVoipFinalState) {
|
||||
jbyteArray persistentState = copyVectorToJavaByteArray(env, tgVoipFinalState.persistentState.value);
|
||||
jstring debugLog = env->NewStringUTF(tgVoipFinalState.debugLog.c_str());
|
||||
jobject trafficStats = asJavaTrafficStats(env, tgVoipFinalState.trafficStats);
|
||||
auto isRatingSuggested = static_cast<jboolean>(tgVoipFinalState.isRatingSuggested);
|
||||
jclass finalStateClass = env->FindClass("org/telegram/messenger/voip/TgVoip$FinalState");
|
||||
jmethodID finalStateInitMethodId = env->GetMethodID(finalStateClass, "<init>", "([BLjava/lang/String;Lorg/telegram/messenger/voip/TgVoip$TrafficStats;Z)V");
|
||||
return env->NewObject(finalStateClass, finalStateInitMethodId, persistentState, debugLog, trafficStats, isRatingSuggested);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
#pragma mark - Static JNI Methods
|
||||
|
||||
JNIEXPORT jlong JNICALL Java_org_telegram_messenger_voip_NativeTgVoipDelegate_makeNativeInstance(JNIEnv *env, jobject obj, jobject instanceObj, jobject config, jstring persistentStateFilePath, jobjectArray endpoints, jobject proxy, jint networkType, jobject encryptionKey) {
|
||||
// reading persistent state
|
||||
TgVoipPersistentState tgVoipPersistentState;
|
||||
readTgVoipPersistentState(jni::JavaStringToStdString(env, persistentStateFilePath).c_str(), tgVoipPersistentState);
|
||||
|
||||
// parsing config
|
||||
TgVoipConfig tgVoipConfig;
|
||||
parseTgVoipConfig(env, config, tgVoipConfig);
|
||||
|
||||
// parsing endpoints
|
||||
std::vector<TgVoipEndpoint> tgVoipEndpoints;
|
||||
parseTgVoipEndpoints(env, endpoints, tgVoipEndpoints);
|
||||
|
||||
// parsing proxy
|
||||
std::unique_ptr<TgVoipProxy> tgVoipProxy;
|
||||
parseTgVoipProxy(env, proxy, tgVoipProxy);
|
||||
|
||||
// parse encryption key
|
||||
TgVoipEncryptionKey tgVoipEncryptionKey;
|
||||
parseTgVoipEncryptionKey(env, encryptionKey, tgVoipEncryptionKey);
|
||||
|
||||
TgVoip *tgVoip = TgVoip::makeInstance(tgVoipConfig, tgVoipPersistentState, tgVoipEndpoints, tgVoipProxy, parseTgVoipNetworkType(networkType), tgVoipEncryptionKey);
|
||||
|
||||
if (env->ExceptionCheck() == JNI_TRUE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
jobject globalRef = env->NewGlobalRef(instanceObj);
|
||||
|
||||
tgVoip->setOnStateUpdated([globalRef](TgVoipState tgVoipState) {
|
||||
jint state = asJavaState(tgVoipState);
|
||||
jni::DoWithJNI([globalRef, state](JNIEnv *env) {
|
||||
env->CallVoidMethod(globalRef, env->GetMethodID(env->GetObjectClass(globalRef), "onStateUpdated", "(I)V"), state);
|
||||
});
|
||||
});
|
||||
|
||||
tgVoip->setOnSignalBarsUpdated([globalRef](int signalBars) {
|
||||
jni::DoWithJNI([globalRef, signalBars](JNIEnv *env) {
|
||||
env->CallVoidMethod(globalRef, env->GetMethodID(env->GetObjectClass(globalRef), "onSignalBarsUpdated", "(I)V"), signalBars);
|
||||
});
|
||||
});
|
||||
|
||||
auto *instance = new InstanceHolder;
|
||||
instance->nativeInstance = tgVoip;
|
||||
instance->javaInstance = globalRef;
|
||||
return reinterpret_cast<jlong>(instance);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_telegram_messenger_voip_NativeTgVoipDelegate_setGlobalServerConfig(JNIEnv *env, jobject obj, jstring serverConfigJson) {
|
||||
TgVoip::setGlobalServerConfig(jni::JavaStringToStdString(env, serverConfigJson));
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_org_telegram_messenger_voip_NativeTgVoipDelegate_getConnectionMaxLayer(JNIEnv *env, jobject obj) {
|
||||
return TgVoip::getConnectionMaxLayer();
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_org_telegram_messenger_voip_NativeTgVoipDelegate_getVersion(JNIEnv *env, jobject obj) {
|
||||
return env->NewStringUTF(TgVoip::getVersion().c_str());
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_telegram_messenger_voip_NativeTgVoipDelegate_setBufferSize(JNIEnv *env, jobject obj, jint size) {
|
||||
tgvoip::audio::AudioOutputOpenSLES::nativeBufferSize = (unsigned int) size;
|
||||
tgvoip::audio::AudioInputOpenSLES::nativeBufferSize = (unsigned int) size;
|
||||
}
|
||||
|
||||
#pragma mark - Virtual JNI Methods
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_telegram_messenger_voip_NativeTgVoipInstance_setNetworkType(JNIEnv *env, jobject obj, jint networkType) {
|
||||
getTgVoip(env, obj)->setNetworkType(parseTgVoipNetworkType(networkType));
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_telegram_messenger_voip_NativeTgVoipInstance_setMuteMicrophone(JNIEnv *env, jobject obj, jboolean muteMicrophone) {
|
||||
getTgVoip(env, obj)->setMuteMicrophone(muteMicrophone);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_telegram_messenger_voip_NativeTgVoipInstance_setAudioOutputGainControlEnabled(JNIEnv *env, jobject obj, jboolean enabled) {
|
||||
getTgVoip(env, obj)->setAudioOutputGainControlEnabled(enabled);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_telegram_messenger_voip_NativeTgVoipInstance_setEchoCancellationStrength(JNIEnv *env, jobject obj, jint strength) {
|
||||
getTgVoip(env, obj)->setEchoCancellationStrength(strength);
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_org_telegram_messenger_voip_NativeTgVoipInstance_getLastError(JNIEnv *env, jobject obj) {
|
||||
return env->NewStringUTF(getTgVoip(env, obj)->getLastError().c_str());
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_org_telegram_messenger_voip_NativeTgVoipInstance_getDebugInfo(JNIEnv *env, jobject obj) {
|
||||
return env->NewStringUTF(getTgVoip(env, obj)->getDebugInfo().c_str());
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_org_telegram_messenger_voip_NativeTgVoipInstance_getPreferredRelayId(JNIEnv *env, jobject obj) {
|
||||
return getTgVoip(env, obj)->getPreferredRelayId();
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_org_telegram_messenger_voip_NativeTgVoipInstance_getTrafficStats(JNIEnv *env, jobject obj) {
|
||||
return asJavaTrafficStats(env, getTgVoip(env, obj)->getTrafficStats());
|
||||
}
|
||||
|
||||
JNIEXPORT jbyteArray JNICALL
|
||||
Java_org_telegram_messenger_voip_NativeTgVoipInstance_getPersistentState(JNIEnv *env, jobject obj) {
|
||||
return copyVectorToJavaByteArray(env, getTgVoip(env, obj)->getPersistentState().value);
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_org_telegram_messenger_voip_NativeTgVoipInstance_stop(JNIEnv *env, jobject obj) {
|
||||
InstanceHolder *instance = getInstanceHolder(env, obj);
|
||||
TgVoipFinalState tgVoipFinalState = instance->nativeInstance->stop();
|
||||
|
||||
// saving persistent state
|
||||
const std::string &path = jni::JavaStringToStdString(env, JavaObject(env, obj).getStringField("persistentStateFilePath"));
|
||||
saveTgVoipPersistentState(path.c_str(), tgVoipFinalState.persistentState);
|
||||
|
||||
// clean
|
||||
env->DeleteGlobalRef(instance->javaInstance);
|
||||
delete instance->nativeInstance;
|
||||
delete instance;
|
||||
|
||||
return asJavaFinalState(env, tgVoipFinalState);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
#include <jni.h>
|
||||
|
||||
#ifndef _Included_org_telegram_messenger_voip_TgVoip
|
||||
#define _Included_org_telegram_messenger_voip_TgVoip
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#undef org_telegram_messenger_voip_TgVoip_NET_TYPE_UNKNOWN
|
||||
#define org_telegram_messenger_voip_TgVoip_NET_TYPE_UNKNOWN 0L
|
||||
#undef org_telegram_messenger_voip_TgVoip_NET_TYPE_GPRS
|
||||
#define org_telegram_messenger_voip_TgVoip_NET_TYPE_GPRS 1L
|
||||
#undef org_telegram_messenger_voip_TgVoip_NET_TYPE_EDGE
|
||||
#define org_telegram_messenger_voip_TgVoip_NET_TYPE_EDGE 2L
|
||||
#undef org_telegram_messenger_voip_TgVoip_NET_TYPE_3G
|
||||
#define org_telegram_messenger_voip_TgVoip_NET_TYPE_3G 3L
|
||||
#undef org_telegram_messenger_voip_TgVoip_NET_TYPE_HSPA
|
||||
#define org_telegram_messenger_voip_TgVoip_NET_TYPE_HSPA 4L
|
||||
#undef org_telegram_messenger_voip_TgVoip_NET_TYPE_LTE
|
||||
#define org_telegram_messenger_voip_TgVoip_NET_TYPE_LTE 5L
|
||||
#undef org_telegram_messenger_voip_TgVoip_NET_TYPE_WIFI
|
||||
#define org_telegram_messenger_voip_TgVoip_NET_TYPE_WIFI 6L
|
||||
#undef org_telegram_messenger_voip_TgVoip_NET_TYPE_ETHERNET
|
||||
#define org_telegram_messenger_voip_TgVoip_NET_TYPE_ETHERNET 7L
|
||||
#undef org_telegram_messenger_voip_TgVoip_NET_TYPE_OTHER_HIGH_SPEED
|
||||
#define org_telegram_messenger_voip_TgVoip_NET_TYPE_OTHER_HIGH_SPEED 8L
|
||||
#undef org_telegram_messenger_voip_TgVoip_NET_TYPE_OTHER_LOW_SPEED
|
||||
#define org_telegram_messenger_voip_TgVoip_NET_TYPE_OTHER_LOW_SPEED 9L
|
||||
#undef org_telegram_messenger_voip_TgVoip_NET_TYPE_DIALUP
|
||||
#define org_telegram_messenger_voip_TgVoip_NET_TYPE_DIALUP 10L
|
||||
#undef org_telegram_messenger_voip_TgVoip_NET_TYPE_OTHER_MOBILE
|
||||
#define org_telegram_messenger_voip_TgVoip_NET_TYPE_OTHER_MOBILE 11L
|
||||
#undef org_telegram_messenger_voip_TgVoip_ENDPOINT_TYPE_INET
|
||||
#define org_telegram_messenger_voip_TgVoip_ENDPOINT_TYPE_INET 0L
|
||||
#undef org_telegram_messenger_voip_TgVoip_ENDPOINT_TYPE_LAN
|
||||
#define org_telegram_messenger_voip_TgVoip_ENDPOINT_TYPE_LAN 1L
|
||||
#undef org_telegram_messenger_voip_TgVoip_ENDPOINT_TYPE_UDP_RELAY
|
||||
#define org_telegram_messenger_voip_TgVoip_ENDPOINT_TYPE_UDP_RELAY 2L
|
||||
#undef org_telegram_messenger_voip_TgVoip_ENDPOINT_TYPE_TCP_RELAY
|
||||
#define org_telegram_messenger_voip_TgVoip_ENDPOINT_TYPE_TCP_RELAY 3L
|
||||
#undef org_telegram_messenger_voip_TgVoip_STATE_WAIT_INIT
|
||||
#define org_telegram_messenger_voip_TgVoip_STATE_WAIT_INIT 1L
|
||||
#undef org_telegram_messenger_voip_TgVoip_STATE_WAIT_INIT_ACK
|
||||
#define org_telegram_messenger_voip_TgVoip_STATE_WAIT_INIT_ACK 2L
|
||||
#undef org_telegram_messenger_voip_TgVoip_STATE_ESTABLISHED
|
||||
#define org_telegram_messenger_voip_TgVoip_STATE_ESTABLISHED 3L
|
||||
#undef org_telegram_messenger_voip_TgVoip_STATE_FAILED
|
||||
#define org_telegram_messenger_voip_TgVoip_STATE_FAILED 4L
|
||||
#undef org_telegram_messenger_voip_TgVoip_STATE_RECONNECTING
|
||||
#define org_telegram_messenger_voip_TgVoip_STATE_RECONNECTING 5L
|
||||
#undef org_telegram_messenger_voip_TgVoip_DATA_SAVING_NEVER
|
||||
#define org_telegram_messenger_voip_TgVoip_DATA_SAVING_NEVER 0L
|
||||
#undef org_telegram_messenger_voip_TgVoip_DATA_SAVING_MOBILE
|
||||
#define org_telegram_messenger_voip_TgVoip_DATA_SAVING_MOBILE 1L
|
||||
#undef org_telegram_messenger_voip_TgVoip_DATA_SAVING_ALWAYS
|
||||
#define org_telegram_messenger_voip_TgVoip_DATA_SAVING_ALWAYS 2L
|
||||
#undef org_telegram_messenger_voip_TgVoip_DATA_SAVING_ROAMING
|
||||
#define org_telegram_messenger_voip_TgVoip_DATA_SAVING_ROAMING 3L
|
||||
#undef org_telegram_messenger_voip_TgVoip_PEER_CAP_GROUP_CALLS
|
||||
#define org_telegram_messenger_voip_TgVoip_PEER_CAP_GROUP_CALLS 1L
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
760
TMessagesProj/jni/libtgvoip2/client/android/tg_voip_jni.cpp
Normal file
760
TMessagesProj/jni/libtgvoip2/client/android/tg_voip_jni.cpp
Normal file
|
@ -0,0 +1,760 @@
|
|||
//
|
||||
// libtgvoip is free and unencumbered public domain software.
|
||||
// For more information, see http://unlicense.org or the UNLICENSE file
|
||||
// you should have received with this source code distribution.
|
||||
//
|
||||
|
||||
#include <jni.h>
|
||||
#include <string.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "../../VoIPServerConfig.h"
|
||||
#include "../../VoIPController.h"
|
||||
#include "../../os/android/AudioOutputOpenSLES.h"
|
||||
#include "../../os/android/AudioInputOpenSLES.h"
|
||||
#include "../../os/android/AudioInputAndroid.h"
|
||||
#include "../../os/android/AudioOutputAndroid.h"
|
||||
#include "../../os/android/VideoSourceAndroid.h"
|
||||
#include "../../os/android/VideoRendererAndroid.h"
|
||||
#include "../../audio/Resampler.h"
|
||||
#include "../../os/android/JNIUtilities.h"
|
||||
#include "../../PrivateDefines.h"
|
||||
#include "../../logging.h"
|
||||
|
||||
#ifdef TGVOIP_HAS_CONFIG
|
||||
#include <tgvoip_config.h>
|
||||
#endif
|
||||
|
||||
JavaVM* sharedJVM;
|
||||
jfieldID audioRecordInstanceFld=NULL;
|
||||
jfieldID audioTrackInstanceFld=NULL;
|
||||
jmethodID setStateMethod=NULL;
|
||||
jmethodID setSignalBarsMethod=NULL;
|
||||
jmethodID setSelfStreamsMethod=NULL;
|
||||
jmethodID setParticipantAudioEnabledMethod=NULL;
|
||||
jmethodID groupCallKeyReceivedMethod=NULL;
|
||||
jmethodID groupCallKeySentMethod=NULL;
|
||||
jmethodID callUpgradeRequestReceivedMethod=NULL;
|
||||
jclass jniUtilitiesClass=NULL;
|
||||
|
||||
struct ImplDataAndroid{
|
||||
jobject javaObject;
|
||||
std::string persistentStateFile="";
|
||||
};
|
||||
|
||||
#ifndef TGVOIP_PACKAGE_PATH
|
||||
#define TGVOIP_PACKAGE_PATH "org/telegram/messenger/voip"
|
||||
#endif
|
||||
|
||||
#ifndef TGVOIP_PEER_TAG_VARIABLE_NAME
|
||||
#define TGVOIP_PEER_TAG_VARIABLE_NAME "peer_tag"
|
||||
#endif
|
||||
|
||||
#ifndef TGVOIP_ENDPOINT_CLASS
|
||||
#define TGVOIP_ENDPOINT_CLASS "org/telegram/tgnet/TLRPC$TL_phoneConnection"
|
||||
#endif
|
||||
|
||||
using namespace tgvoip;
|
||||
using namespace tgvoip::audio;
|
||||
|
||||
namespace tgvoip {
|
||||
#pragma mark - Callbacks
|
||||
|
||||
void updateConnectionState(VoIPController *cntrlr, int state){
|
||||
ImplDataAndroid *impl=(ImplDataAndroid *) cntrlr->implData;
|
||||
jni::AttachAndCallVoidMethod(setStateMethod, impl->javaObject, state);
|
||||
}
|
||||
|
||||
void updateSignalBarCount(VoIPController *cntrlr, int count){
|
||||
ImplDataAndroid *impl=(ImplDataAndroid *) cntrlr->implData;
|
||||
jni::AttachAndCallVoidMethod(setSignalBarsMethod, impl->javaObject, count);
|
||||
}
|
||||
|
||||
void updateGroupCallStreams(VoIPGroupController *cntrlr, unsigned char *streams, size_t len){
|
||||
ImplDataAndroid *impl=(ImplDataAndroid *) cntrlr->implData;
|
||||
if(!impl->javaObject)
|
||||
return;
|
||||
jni::DoWithJNI([streams, len, &impl](JNIEnv* env){
|
||||
if(setSelfStreamsMethod){
|
||||
jbyteArray jstreams=env->NewByteArray(static_cast<jsize>(len));
|
||||
jbyte *el=env->GetByteArrayElements(jstreams, NULL);
|
||||
memcpy(el, streams, len);
|
||||
env->ReleaseByteArrayElements(jstreams, el, 0);
|
||||
env->CallVoidMethod(impl->javaObject, setSelfStreamsMethod, jstreams);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void groupCallKeyReceived(VoIPController *cntrlr, const unsigned char *key){
|
||||
ImplDataAndroid *impl=(ImplDataAndroid *) cntrlr->implData;
|
||||
if(!impl->javaObject)
|
||||
return;
|
||||
jni::DoWithJNI([key, &impl](JNIEnv* env){
|
||||
if(groupCallKeyReceivedMethod){
|
||||
jbyteArray jkey=env->NewByteArray(256);
|
||||
jbyte *el=env->GetByteArrayElements(jkey, NULL);
|
||||
memcpy(el, key, 256);
|
||||
env->ReleaseByteArrayElements(jkey, el, 0);
|
||||
env->CallVoidMethod(impl->javaObject, groupCallKeyReceivedMethod, jkey);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void groupCallKeySent(VoIPController *cntrlr){
|
||||
ImplDataAndroid *impl=(ImplDataAndroid *) cntrlr->implData;
|
||||
jni::AttachAndCallVoidMethod(groupCallKeySentMethod, impl->javaObject);
|
||||
}
|
||||
|
||||
void callUpgradeRequestReceived(VoIPController* cntrlr){
|
||||
ImplDataAndroid *impl=(ImplDataAndroid *) cntrlr->implData;
|
||||
jni::AttachAndCallVoidMethod(callUpgradeRequestReceivedMethod, impl->javaObject);
|
||||
}
|
||||
|
||||
void updateParticipantAudioState(VoIPGroupController *cntrlr, int32_t userID, bool enabled){
|
||||
ImplDataAndroid *impl=(ImplDataAndroid *) cntrlr->implData;
|
||||
jni::AttachAndCallVoidMethod(setParticipantAudioEnabledMethod, impl->javaObject, userID, enabled);
|
||||
}
|
||||
|
||||
#pragma mark - VoIPController
|
||||
|
||||
uint32_t AndroidCodecToFOURCC(std::string mime){
|
||||
if(mime=="video/avc")
|
||||
return CODEC_AVC;
|
||||
else if(mime=="video/hevc")
|
||||
return CODEC_HEVC;
|
||||
else if(mime=="video/x-vnd.on2.vp8")
|
||||
return CODEC_VP8;
|
||||
else if(mime=="video/x-vnd.on2.vp9")
|
||||
return CODEC_VP9;
|
||||
return 0;
|
||||
}
|
||||
|
||||
jlong VoIPController_nativeInit(JNIEnv* env, jobject thiz, jstring persistentStateFile) {
|
||||
ImplDataAndroid* impl=new ImplDataAndroid();
|
||||
impl->javaObject=env->NewGlobalRef(thiz);
|
||||
if(persistentStateFile){
|
||||
impl->persistentStateFile=jni::JavaStringToStdString(env, persistentStateFile);
|
||||
}
|
||||
VoIPController* cntrlr=new VoIPController();
|
||||
cntrlr->implData=impl;
|
||||
VoIPController::Callbacks callbacks;
|
||||
callbacks.connectionStateChanged=updateConnectionState;
|
||||
callbacks.signalBarCountChanged=updateSignalBarCount;
|
||||
callbacks.groupCallKeyReceived=groupCallKeyReceived;
|
||||
callbacks.groupCallKeySent=groupCallKeySent;
|
||||
callbacks.upgradeToGroupCallRequested=callUpgradeRequestReceived;
|
||||
cntrlr->SetCallbacks(callbacks);
|
||||
if(!impl->persistentStateFile.empty()){
|
||||
FILE* f=fopen(impl->persistentStateFile.c_str(), "r");
|
||||
if(f){
|
||||
fseek(f, 0, SEEK_END);
|
||||
size_t len=static_cast<size_t>(ftell(f));
|
||||
fseek(f, 0, SEEK_SET);
|
||||
if(len<1024*512 && len>0){
|
||||
char *fbuf=static_cast<char *>(malloc(len));
|
||||
fread(fbuf, 1, len, f);
|
||||
std::vector<uint8_t> state(fbuf, fbuf+len);
|
||||
free(fbuf);
|
||||
cntrlr->SetPersistentState(state);
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
#ifndef TGVOIP_NO_VIDEO
|
||||
if(video::VideoRendererAndroid::availableDecoders.empty() || video::VideoSourceAndroid::availableEncoders.empty()){
|
||||
video::VideoRendererAndroid::availableDecoders.clear();
|
||||
video::VideoSourceAndroid::availableEncoders.clear();
|
||||
jmethodID getCodecsMethod=env->GetStaticMethodID(jniUtilitiesClass, "getSupportedVideoCodecs", "()[[Ljava/lang/String;");
|
||||
jobjectArray codecs=static_cast<jobjectArray>(env->CallStaticObjectMethod(jniUtilitiesClass, getCodecsMethod));
|
||||
jobjectArray encoders=static_cast<jobjectArray>(env->GetObjectArrayElement(codecs, 0));
|
||||
jobjectArray decoders=static_cast<jobjectArray>(env->GetObjectArrayElement(codecs, 1));
|
||||
for(jsize i=0;i<env->GetArrayLength(encoders);i++){
|
||||
std::string codec=jni::JavaStringToStdString(env, static_cast<jstring>(env->GetObjectArrayElement(encoders, i)));
|
||||
uint32_t id=AndroidCodecToFOURCC(codec);
|
||||
if(id)
|
||||
video::VideoSourceAndroid::availableEncoders.push_back(id);
|
||||
}
|
||||
for(jsize i=0;i<env->GetArrayLength(decoders);i++){
|
||||
std::string codec=jni::JavaStringToStdString(env, static_cast<jstring>(env->GetObjectArrayElement(decoders, i)));
|
||||
uint32_t id=AndroidCodecToFOURCC(codec);
|
||||
if(id)
|
||||
video::VideoRendererAndroid::availableDecoders.push_back(id);
|
||||
}
|
||||
jmethodID getMaxResolutionMethod=env->GetStaticMethodID(jniUtilitiesClass, "getMaxVideoResolution", "()I");
|
||||
video::VideoRendererAndroid::maxResolution=env->CallStaticIntMethod(jniUtilitiesClass, getMaxResolutionMethod);
|
||||
}
|
||||
#endif
|
||||
return (jlong)(intptr_t)cntrlr;
|
||||
}
|
||||
|
||||
void VoIPController_nativeStart(JNIEnv* env, jobject thiz, jlong inst){
|
||||
((VoIPController*)(intptr_t)inst)->Start();
|
||||
}
|
||||
|
||||
void VoIPController_nativeConnect(JNIEnv* env, jobject thiz, jlong inst){
|
||||
((VoIPController*)(intptr_t)inst)->Connect();
|
||||
}
|
||||
|
||||
void VoIPController_nativeSetProxy(JNIEnv* env, jobject thiz, jlong inst, jstring _address, jint port, jstring _username, jstring _password){
|
||||
((VoIPController*)(intptr_t)inst)->SetProxy(PROXY_SOCKS5, jni::JavaStringToStdString(env, _address), (uint16_t)port, jni::JavaStringToStdString(env, _username), jni::JavaStringToStdString(env, _password));
|
||||
}
|
||||
|
||||
void VoIPController_nativeSetEncryptionKey(JNIEnv* env, jobject thiz, jlong inst, jbyteArray key, jboolean isOutgoing){
|
||||
jbyte* akey=env->GetByteArrayElements(key, NULL);
|
||||
((VoIPController*)(intptr_t)inst)->SetEncryptionKey((char *) akey, isOutgoing);
|
||||
env->ReleaseByteArrayElements(key, akey, JNI_ABORT);
|
||||
}
|
||||
|
||||
void VoIPController_nativeSetRemoteEndpoints(JNIEnv* env, jobject thiz, jlong inst, jobjectArray endpoints, jboolean allowP2p, jboolean tcp, jint connectionMaxLayer){
|
||||
size_t len=(size_t) env->GetArrayLength(endpoints);
|
||||
std::vector<Endpoint> eps;
|
||||
/*public String ip;
|
||||
public String ipv6;
|
||||
public int port;
|
||||
public byte[] peer_tag;*/
|
||||
jclass epClass=env->GetObjectClass(env->GetObjectArrayElement(endpoints, 0));
|
||||
jfieldID ipFld=env->GetFieldID(epClass, "ip", "Ljava/lang/String;");
|
||||
jfieldID ipv6Fld=env->GetFieldID(epClass, "ipv6", "Ljava/lang/String;");
|
||||
jfieldID portFld=env->GetFieldID(epClass, "port", "I");
|
||||
jfieldID peerTagFld=env->GetFieldID(epClass, TGVOIP_PEER_TAG_VARIABLE_NAME, "[B");
|
||||
jfieldID idFld=env->GetFieldID(epClass, "id", "J");
|
||||
for(unsigned int i=0;i<len;i++){
|
||||
jobject endpoint=env->GetObjectArrayElement(endpoints, i);
|
||||
jstring ip=(jstring) env->GetObjectField(endpoint, ipFld);
|
||||
jstring ipv6=(jstring) env->GetObjectField(endpoint, ipv6Fld);
|
||||
jint port=env->GetIntField(endpoint, portFld);
|
||||
jlong id=env->GetLongField(endpoint, idFld);
|
||||
jbyteArray peerTag=(jbyteArray) env->GetObjectField(endpoint, peerTagFld);
|
||||
IPv4Address v4addr(jni::JavaStringToStdString(env, ip));
|
||||
IPv6Address v6addr("::0");
|
||||
if(ipv6 && env->GetStringLength(ipv6)){
|
||||
v6addr=IPv6Address(jni::JavaStringToStdString(env, ipv6));
|
||||
}
|
||||
unsigned char pTag[16];
|
||||
if(peerTag && env->GetArrayLength(peerTag)){
|
||||
jbyte* peerTagBytes=env->GetByteArrayElements(peerTag, NULL);
|
||||
memcpy(pTag, peerTagBytes, 16);
|
||||
env->ReleaseByteArrayElements(peerTag, peerTagBytes, JNI_ABORT);
|
||||
}
|
||||
eps.push_back(Endpoint((int64_t)id, (uint16_t)port, v4addr, v6addr, tcp ? Endpoint::Type::TCP_RELAY : Endpoint::Type::UDP_RELAY, pTag));
|
||||
}
|
||||
((VoIPController*)(intptr_t)inst)->SetRemoteEndpoints(eps, allowP2p, connectionMaxLayer);
|
||||
}
|
||||
|
||||
void VoIPController_nativeSetNativeBufferSize(JNIEnv* env, jclass thiz, jint size){
|
||||
AudioOutputOpenSLES::nativeBufferSize=(unsigned int) size;
|
||||
AudioInputOpenSLES::nativeBufferSize=(unsigned int) size;
|
||||
}
|
||||
|
||||
void VoIPController_nativeRelease(JNIEnv* env, jobject thiz, jlong inst){
|
||||
//env->DeleteGlobalRef(AudioInputAndroid::jniClass);
|
||||
|
||||
VoIPController* ctlr=((VoIPController*)(intptr_t)inst);
|
||||
ImplDataAndroid* impl=(ImplDataAndroid*)ctlr->implData;
|
||||
ctlr->Stop();
|
||||
std::vector<uint8_t> state=ctlr->GetPersistentState();
|
||||
delete ctlr;
|
||||
env->DeleteGlobalRef(impl->javaObject);
|
||||
if(!impl->persistentStateFile.empty()){
|
||||
FILE* f=fopen(impl->persistentStateFile.c_str(), "w");
|
||||
if(f){
|
||||
fwrite(state.data(), 1, state.size(), f);
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
delete impl;
|
||||
}
|
||||
|
||||
jstring VoIPController_nativeGetDebugString(JNIEnv* env, jobject thiz, jlong inst){
|
||||
std::string str=((VoIPController*)(intptr_t)inst)->GetDebugString();
|
||||
return env->NewStringUTF(str.c_str());
|
||||
}
|
||||
|
||||
void VoIPController_nativeSetNetworkType(JNIEnv* env, jobject thiz, jlong inst, jint type){
|
||||
((VoIPController*)(intptr_t)inst)->SetNetworkType(type);
|
||||
}
|
||||
|
||||
void VoIPController_nativeSetMicMute(JNIEnv* env, jobject thiz, jlong inst, jboolean mute){
|
||||
((VoIPController*)(intptr_t)inst)->SetMicMute(mute);
|
||||
}
|
||||
|
||||
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){
|
||||
VoIPController::Config cfg;
|
||||
cfg.initTimeout=initTimeout;
|
||||
cfg.recvTimeout=recvTimeout;
|
||||
cfg.dataSaving=dataSavingMode;
|
||||
cfg.enableAEC=enableAEC;
|
||||
cfg.enableNS=enableNS;
|
||||
cfg.enableAGC=enableAGC;
|
||||
cfg.enableCallUpgrade=false;
|
||||
cfg.logPacketStats=logPacketStats;
|
||||
if(logFilePath){
|
||||
cfg.logFilePath=jni::JavaStringToStdString(env, logFilePath);
|
||||
}
|
||||
if(statsDumpPath){
|
||||
cfg.statsDumpFilePath=jni::JavaStringToStdString(env, statsDumpPath);
|
||||
}
|
||||
|
||||
#ifndef TGVOIP_NO_VIDEO
|
||||
cfg.enableVideoReceive=cfg.enableVideoSend=true;
|
||||
#endif
|
||||
|
||||
((VoIPController*)(intptr_t)inst)->SetConfig(cfg);
|
||||
}
|
||||
|
||||
void VoIPController_nativeDebugCtl(JNIEnv* env, jobject thiz, jlong inst, jint request, jint param){
|
||||
((VoIPController*)(intptr_t)inst)->DebugCtl(request, param);
|
||||
}
|
||||
|
||||
jstring VoIPController_nativeGetVersion(JNIEnv* env, jclass clasz){
|
||||
return env->NewStringUTF(VoIPController::GetVersion());
|
||||
}
|
||||
|
||||
jlong VoIPController_nativeGetPreferredRelayID(JNIEnv* env, jclass clasz, jlong inst){
|
||||
return ((VoIPController*)(intptr_t)inst)->GetPreferredRelayID();
|
||||
}
|
||||
|
||||
jint VoIPController_nativeGetLastError(JNIEnv* env, jclass clasz, jlong inst){
|
||||
return ((VoIPController*)(intptr_t)inst)->GetLastError();
|
||||
}
|
||||
|
||||
void VoIPController_nativeGetStats(JNIEnv* env, jclass clasz, jlong inst, jobject stats){
|
||||
VoIPController::TrafficStats _stats;
|
||||
((VoIPController*)(intptr_t)inst)->GetStats(&_stats);
|
||||
jclass cls=env->GetObjectClass(stats);
|
||||
env->SetLongField(stats, env->GetFieldID(cls, "bytesSentWifi", "J"), _stats.bytesSentWifi);
|
||||
env->SetLongField(stats, env->GetFieldID(cls, "bytesSentMobile", "J"), _stats.bytesSentMobile);
|
||||
env->SetLongField(stats, env->GetFieldID(cls, "bytesRecvdWifi", "J"), _stats.bytesRecvdWifi);
|
||||
env->SetLongField(stats, env->GetFieldID(cls, "bytesRecvdMobile", "J"), _stats.bytesRecvdMobile);
|
||||
}
|
||||
|
||||
jstring VoIPController_nativeGetDebugLog(JNIEnv* env, jobject thiz, jlong inst){
|
||||
VoIPController* ctlr=((VoIPController*)(intptr_t)inst);
|
||||
std::string log=ctlr->GetDebugLog();
|
||||
return env->NewStringUTF(log.c_str());
|
||||
}
|
||||
|
||||
void VoIPController_nativeSetAudioOutputGainControlEnabled(JNIEnv* env, jclass clasz, jlong inst, jboolean enabled){
|
||||
((VoIPController*)(intptr_t)inst)->SetAudioOutputGainControlEnabled(enabled);
|
||||
}
|
||||
|
||||
void VoIPController_nativeSetEchoCancellationStrength(JNIEnv* env, jclass cls, jlong inst, jint strength){
|
||||
((VoIPController*)(intptr_t)inst)->SetEchoCancellationStrength(strength);
|
||||
}
|
||||
|
||||
jint VoIPController_nativeGetPeerCapabilities(JNIEnv* env, jclass cls, jlong inst){
|
||||
return ((VoIPController*)(intptr_t)inst)->GetPeerCapabilities();
|
||||
}
|
||||
|
||||
void VoIPController_nativeSendGroupCallKey(JNIEnv* env, jclass cls, jlong inst, jbyteArray _key){
|
||||
jbyte* key=env->GetByteArrayElements(_key, NULL);
|
||||
((VoIPController*)(intptr_t)inst)->SendGroupCallKey((unsigned char *) key);
|
||||
env->ReleaseByteArrayElements(_key, key, JNI_ABORT);
|
||||
}
|
||||
|
||||
void VoIPController_nativeRequestCallUpgrade(JNIEnv* env, jclass cls, jlong inst){
|
||||
((VoIPController*)(intptr_t)inst)->RequestCallUpgrade();
|
||||
}
|
||||
|
||||
void VoIPController_nativeSetVideoSource(JNIEnv* env, jobject thiz, jlong inst, jlong source){
|
||||
((VoIPController*)(intptr_t)inst)->SetVideoSource((video::VideoSource*)(intptr_t)source);
|
||||
}
|
||||
|
||||
void VoIPController_nativeSetVideoRenderer(JNIEnv* env, jobject thiz, jlong inst, jlong renderer){
|
||||
((VoIPController*)(intptr_t)inst)->SetVideoRenderer((video::VideoRenderer*)(intptr_t)renderer);
|
||||
}
|
||||
|
||||
jboolean VoIPController_nativeNeedRate(JNIEnv* env, jclass cls, jlong inst){
|
||||
return static_cast<jboolean>(((VoIPController*)(intptr_t)inst)->NeedRate());
|
||||
}
|
||||
|
||||
jint VoIPController_getConnectionMaxLayer(JNIEnv* env, jclass cls){
|
||||
return VoIPController::GetConnectionMaxLayer();
|
||||
}
|
||||
|
||||
#pragma mark - AudioRecordJNI
|
||||
|
||||
void AudioRecordJNI_nativeCallback(JNIEnv* env, jobject thiz, jobject buffer){
|
||||
jlong inst=env->GetLongField(thiz, audioRecordInstanceFld);
|
||||
AudioInputAndroid* in=(AudioInputAndroid*)(intptr_t)inst;
|
||||
in->HandleCallback(env, buffer);
|
||||
}
|
||||
|
||||
#pragma mark - AudioTrackJNI
|
||||
|
||||
void AudioTrackJNI_nativeCallback(JNIEnv* env, jobject thiz, jbyteArray buffer){
|
||||
jlong inst=env->GetLongField(thiz, audioTrackInstanceFld);
|
||||
AudioOutputAndroid* in=(AudioOutputAndroid*)(intptr_t)inst;
|
||||
in->HandleCallback(env, buffer);
|
||||
}
|
||||
|
||||
#pragma mark - VoIPServerConfig
|
||||
|
||||
void VoIPServerConfig_nativeSetConfig(JNIEnv* env, jclass clasz, jstring jsonString){
|
||||
ServerConfig::GetSharedInstance()->Update(jni::JavaStringToStdString(env, jsonString));
|
||||
}
|
||||
|
||||
#pragma mark - Resampler
|
||||
|
||||
jint Resampler_convert44to48(JNIEnv* env, jclass cls, jobject from, jobject to){
|
||||
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));
|
||||
}
|
||||
|
||||
jint Resampler_convert48to44(JNIEnv* env, jclass cls, jobject from, jobject to){
|
||||
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));
|
||||
}
|
||||
|
||||
#pragma mark - VoIPGroupController
|
||||
|
||||
#ifndef TGVOIP_NO_GROUP_CALLS
|
||||
jlong VoIPGroupController_nativeInit(JNIEnv* env, jobject thiz, jint timeDifference){
|
||||
ImplDataAndroid* impl=(ImplDataAndroid*) malloc(sizeof(ImplDataAndroid));
|
||||
impl->javaObject=env->NewGlobalRef(thiz);
|
||||
VoIPGroupController* cntrlr=new VoIPGroupController(timeDifference);
|
||||
cntrlr->implData=impl;
|
||||
|
||||
VoIPGroupController::Callbacks callbacks;
|
||||
callbacks.connectionStateChanged=updateConnectionState;
|
||||
callbacks.updateStreams=updateGroupCallStreams;
|
||||
callbacks.participantAudioStateChanged=updateParticipantAudioState;
|
||||
callbacks.signalBarCountChanged=NULL;
|
||||
cntrlr->SetCallbacks(callbacks);
|
||||
|
||||
return (jlong)(intptr_t)cntrlr;
|
||||
}
|
||||
|
||||
void VoIPGroupController_nativeSetGroupCallInfo(JNIEnv* env, jclass cls, jlong inst, jbyteArray _encryptionKey, jbyteArray _reflectorGroupTag, jbyteArray _reflectorSelfTag, jbyteArray _reflectorSelfSecret, jbyteArray _reflectorSelfTagHash, jint selfUserID, jstring reflectorAddress, jstring reflectorAddressV6, jint reflectorPort){
|
||||
VoIPGroupController* ctlr=((VoIPGroupController*)(intptr_t)inst);
|
||||
jbyte* encryptionKey=env->GetByteArrayElements(_encryptionKey, NULL);
|
||||
jbyte* reflectorGroupTag=env->GetByteArrayElements(_reflectorGroupTag, NULL);
|
||||
jbyte* reflectorSelfTag=env->GetByteArrayElements(_reflectorSelfTag, NULL);
|
||||
jbyte* reflectorSelfSecret=env->GetByteArrayElements(_reflectorSelfSecret, NULL);
|
||||
jbyte* reflectorSelfTagHash=env->GetByteArrayElements(_reflectorSelfTagHash, NULL);
|
||||
|
||||
|
||||
const char* ipChars=env->GetStringUTFChars(reflectorAddress, NULL);
|
||||
std::string ipLiteral(ipChars);
|
||||
NetworkAddress v4addr=NetworkAddress::IPv4(ipLiteral);
|
||||
NetworkAddress v6addr=NetworkAddress::Empty();
|
||||
env->ReleaseStringUTFChars(reflectorAddress, ipChars);
|
||||
if(reflectorAddressV6 && env->GetStringLength(reflectorAddressV6)){
|
||||
const char* ipv6Chars=env->GetStringUTFChars(reflectorAddressV6, NULL);
|
||||
v6addr=NetworkAddress::IPv6(ipv6Chars);
|
||||
env->ReleaseStringUTFChars(reflectorAddressV6, ipv6Chars);
|
||||
}
|
||||
ctlr->SetGroupCallInfo((unsigned char *) encryptionKey, (unsigned char *) reflectorGroupTag, (unsigned char *) reflectorSelfTag, (unsigned char *) reflectorSelfSecret, (unsigned char*) reflectorSelfTagHash, selfUserID, v4addr, v6addr, (uint16_t)reflectorPort);
|
||||
|
||||
env->ReleaseByteArrayElements(_encryptionKey, encryptionKey, JNI_ABORT);
|
||||
env->ReleaseByteArrayElements(_reflectorGroupTag, reflectorGroupTag, JNI_ABORT);
|
||||
env->ReleaseByteArrayElements(_reflectorSelfTag, reflectorSelfTag, JNI_ABORT);
|
||||
env->ReleaseByteArrayElements(_reflectorSelfSecret, reflectorSelfSecret, JNI_ABORT);
|
||||
env->ReleaseByteArrayElements(_reflectorSelfTagHash, reflectorSelfTagHash, JNI_ABORT);
|
||||
}
|
||||
|
||||
void VoIPGroupController_nativeAddGroupCallParticipant(JNIEnv* env, jclass cls, jlong inst, jint userID, jbyteArray _memberTagHash, jbyteArray _streams){
|
||||
VoIPGroupController* ctlr=((VoIPGroupController*)(intptr_t)inst);
|
||||
jbyte* memberTagHash=env->GetByteArrayElements(_memberTagHash, NULL);
|
||||
jbyte* streams=_streams ? env->GetByteArrayElements(_streams, NULL) : NULL;
|
||||
|
||||
ctlr->AddGroupCallParticipant(userID, (unsigned char *) memberTagHash, (unsigned char *) streams, (size_t) env->GetArrayLength(_streams));
|
||||
|
||||
env->ReleaseByteArrayElements(_memberTagHash, memberTagHash, JNI_ABORT);
|
||||
if(_streams)
|
||||
env->ReleaseByteArrayElements(_streams, streams, JNI_ABORT);
|
||||
|
||||
}
|
||||
|
||||
void VoIPGroupController_nativeRemoveGroupCallParticipant(JNIEnv* env, jclass cls, jlong inst, jint userID){
|
||||
VoIPGroupController* ctlr=((VoIPGroupController*)(intptr_t)inst);
|
||||
ctlr->RemoveGroupCallParticipant(userID);
|
||||
}
|
||||
|
||||
jfloat VoIPGroupController_nativeGetParticipantAudioLevel(JNIEnv* env, jclass cls, jlong inst, jint userID){
|
||||
return ((VoIPGroupController*)(intptr_t)inst)->GetParticipantAudioLevel(userID);
|
||||
}
|
||||
|
||||
void VoIPGroupController_nativeSetParticipantVolume(JNIEnv* env, jclass cls, jlong inst, jint userID, jfloat volume){
|
||||
((VoIPGroupController*)(intptr_t)inst)->SetParticipantVolume(userID, volume);
|
||||
}
|
||||
|
||||
jbyteArray VoIPGroupController_getInitialStreams(JNIEnv* env, jclass cls){
|
||||
unsigned char buf[1024];
|
||||
size_t len=VoIPGroupController::GetInitialStreams(buf, sizeof(buf));
|
||||
jbyteArray arr=env->NewByteArray(len);
|
||||
jbyte* arrElems=env->GetByteArrayElements(arr, NULL);
|
||||
memcpy(arrElems, buf, len);
|
||||
env->ReleaseByteArrayElements(arr, arrElems, 0);
|
||||
return arr;
|
||||
}
|
||||
|
||||
void VoIPGroupController_nativeSetParticipantStreams(JNIEnv* env, jclass cls, jlong inst, jint userID, jbyteArray _streams){
|
||||
jbyte* streams=env->GetByteArrayElements(_streams, NULL);
|
||||
|
||||
((VoIPGroupController*)(intptr_t)inst)->SetParticipantStreams(userID, (unsigned char *) streams, (size_t) env->GetArrayLength(_streams));
|
||||
|
||||
env->ReleaseByteArrayElements(_streams, streams, JNI_ABORT);
|
||||
}
|
||||
#endif
|
||||
|
||||
#pragma mark - VideoSource
|
||||
|
||||
jlong VideoSource_nativeInit(JNIEnv* env, jobject thiz){
|
||||
return (jlong)(intptr_t)new video::VideoSourceAndroid(env->NewGlobalRef(thiz));
|
||||
}
|
||||
|
||||
void VideoSource_nativeRelease(JNIEnv* env, jobject thiz, jlong inst){
|
||||
delete (video::VideoSource*)(intptr_t)inst;
|
||||
}
|
||||
|
||||
void VideoSource_nativeSetVideoStreamParameters(JNIEnv* env, jobject thiz, jlong inst, jobjectArray _csd, jint width, jint height){
|
||||
std::vector<Buffer> csd;
|
||||
if(_csd){
|
||||
for(int i=0; i<env->GetArrayLength(_csd); i++){
|
||||
jobject _buf=env->GetObjectArrayElement(_csd, i);
|
||||
size_t len=static_cast<size_t>(env->GetDirectBufferCapacity(_buf));
|
||||
Buffer buf(len);
|
||||
buf.CopyFrom(env->GetDirectBufferAddress(_buf), 0, len);
|
||||
csd.push_back(std::move(buf));
|
||||
}
|
||||
}
|
||||
((video::VideoSourceAndroid*)(intptr_t)inst)->SetStreamParameters(std::move(csd), width, height);
|
||||
}
|
||||
|
||||
void VideoSource_nativeSendFrame(JNIEnv* env, jobject thiz, jlong inst, jobject buffer, jint offset, jint length, jint flags){
|
||||
//size_t bufsize=(size_t)env->GetDirectBufferCapacity(buffer);
|
||||
Buffer buf(static_cast<size_t>(length));
|
||||
buf.CopyFrom(((char*)env->GetDirectBufferAddress(buffer))+offset, 0, static_cast<size_t>(length));
|
||||
((video::VideoSourceAndroid*)(intptr_t)inst)->SendFrame(std::move(buf), static_cast<uint32_t>(flags));
|
||||
}
|
||||
|
||||
void VideoSource_nativeSetRotation(JNIEnv* env, jobject thiz, jlong inst, jint rotation){
|
||||
((video::VideoSourceAndroid*)(intptr_t)inst)->SetRotation((unsigned int)rotation);
|
||||
}
|
||||
|
||||
void VideoSource_nativeSetPaused(JNIEnv* env, jobject thiz, jlong inst, jboolean paused){
|
||||
((video::VideoSourceAndroid*)(intptr_t)inst)->SetStreamPaused((bool)paused);
|
||||
}
|
||||
|
||||
#pragma mark - VideoRenderer
|
||||
|
||||
jlong VideoRenderer_nativeInit(JNIEnv* env, jobject thiz){
|
||||
return (jlong)(intptr_t)new video::VideoRendererAndroid(env->NewGlobalRef(thiz));
|
||||
}
|
||||
|
||||
#pragma mark - VLog
|
||||
|
||||
template<int level> void VLog_log(JNIEnv* env, jclass cls, jstring jmsg){
|
||||
const char* format="[java] %s";
|
||||
std::string msg=jni::JavaStringToStdString(env, jmsg);
|
||||
switch(level){
|
||||
case 0:
|
||||
LOGV(format, msg.c_str());
|
||||
break;
|
||||
case 1:
|
||||
LOGD(format, msg.c_str());
|
||||
break;
|
||||
case 2:
|
||||
LOGI(format, msg.c_str());
|
||||
break;
|
||||
case 3:
|
||||
LOGW(format, msg.c_str());
|
||||
break;
|
||||
case 4:
|
||||
LOGE(format, msg.c_str());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" int tgvoipOnJniLoad(JavaVM *vm, JNIEnv *env);
|
||||
|
||||
extern "C" jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
JNIEnv *env = 0;
|
||||
srand(time(NULL));
|
||||
|
||||
if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tgvoipOnJniLoad(vm, env) != JNI_TRUE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
jclass controller=env->FindClass(TGVOIP_PACKAGE_PATH "/VoIPController");
|
||||
jclass groupController=env->FindClass(TGVOIP_PACKAGE_PATH "/VoIPGroupController");
|
||||
if(env->ExceptionCheck()){
|
||||
env->ExceptionClear(); // is returning NULL from FindClass not enough?
|
||||
}
|
||||
jclass audioRecordJNI=env->FindClass(TGVOIP_PACKAGE_PATH "/AudioRecordJNI");
|
||||
jclass audioTrackJNI=env->FindClass(TGVOIP_PACKAGE_PATH "/AudioTrackJNI");
|
||||
jclass serverConfig=env->FindClass(TGVOIP_PACKAGE_PATH "/VoIPServerConfig");
|
||||
jclass resampler=env->FindClass(TGVOIP_PACKAGE_PATH "/Resampler");
|
||||
jclass videoSource=env->FindClass(TGVOIP_PACKAGE_PATH "/VideoSource");
|
||||
if(env->ExceptionCheck()){
|
||||
env->ExceptionClear(); // is returning NULL from FindClass not enough?
|
||||
}
|
||||
jclass videoRenderer=env->FindClass(TGVOIP_PACKAGE_PATH "/VideoRenderer");
|
||||
if(env->ExceptionCheck()){
|
||||
env->ExceptionClear(); // is returning NULL from FindClass not enough?
|
||||
}
|
||||
jclass vlog=env->FindClass(TGVOIP_PACKAGE_PATH "/VLog");
|
||||
if(env->ExceptionCheck()){
|
||||
env->ExceptionClear();
|
||||
}
|
||||
assert(controller && audioRecordJNI && audioTrackJNI && serverConfig && resampler);
|
||||
|
||||
audioRecordInstanceFld=env->GetFieldID(audioRecordJNI, "nativeInst", "J");
|
||||
audioTrackInstanceFld=env->GetFieldID(audioTrackJNI, "nativeInst", "J");
|
||||
|
||||
env->GetJavaVM(&sharedJVM);
|
||||
if(!AudioInputAndroid::jniClass){
|
||||
jclass cls=env->FindClass(TGVOIP_PACKAGE_PATH "/AudioRecordJNI");
|
||||
AudioInputAndroid::jniClass=(jclass) env->NewGlobalRef(cls);
|
||||
AudioInputAndroid::initMethod=env->GetMethodID(cls, "init", "(IIII)V");
|
||||
AudioInputAndroid::releaseMethod=env->GetMethodID(cls, "release", "()V");
|
||||
AudioInputAndroid::startMethod=env->GetMethodID(cls, "start", "()Z");
|
||||
AudioInputAndroid::stopMethod=env->GetMethodID(cls, "stop", "()V");
|
||||
AudioInputAndroid::getEnabledEffectsMaskMethod=env->GetMethodID(cls, "getEnabledEffectsMask", "()I");
|
||||
|
||||
cls=env->FindClass(TGVOIP_PACKAGE_PATH "/AudioTrackJNI");
|
||||
AudioOutputAndroid::jniClass=(jclass) env->NewGlobalRef(cls);
|
||||
AudioOutputAndroid::initMethod=env->GetMethodID(cls, "init", "(IIII)V");
|
||||
AudioOutputAndroid::releaseMethod=env->GetMethodID(cls, "release", "()V");
|
||||
AudioOutputAndroid::startMethod=env->GetMethodID(cls, "start", "()V");
|
||||
AudioOutputAndroid::stopMethod=env->GetMethodID(cls, "stop", "()V");
|
||||
|
||||
if(videoRenderer){
|
||||
video::VideoRendererAndroid::decodeAndDisplayMethod=env->GetMethodID(videoRenderer, "decodeAndDisplay", "(Ljava/nio/ByteBuffer;IJ)V");
|
||||
video::VideoRendererAndroid::resetMethod=env->GetMethodID(videoRenderer, "reset", "(Ljava/lang/String;II[[B)V");
|
||||
video::VideoRendererAndroid::setStreamEnabledMethod=env->GetMethodID(videoRenderer, "setStreamEnabled", "(ZZ)V");
|
||||
video::VideoRendererAndroid::setRotationMethod=env->GetMethodID(videoRenderer, "setRotation", "(I)V");
|
||||
}
|
||||
}
|
||||
|
||||
setStateMethod=env->GetMethodID(controller, "handleStateChange", "(I)V");
|
||||
setSignalBarsMethod=env->GetMethodID(controller, "handleSignalBarsChange", "(I)V");
|
||||
groupCallKeyReceivedMethod=env->GetMethodID(controller, "groupCallKeyReceived", "([B)V");
|
||||
groupCallKeySentMethod=env->GetMethodID(controller, "groupCallKeySent", "()V");
|
||||
callUpgradeRequestReceivedMethod=env->GetMethodID(controller, "callUpgradeRequestReceived", "()V");
|
||||
|
||||
if(!jniUtilitiesClass)
|
||||
jniUtilitiesClass=(jclass) env->NewGlobalRef(env->FindClass(TGVOIP_PACKAGE_PATH "/JNIUtilities"));
|
||||
|
||||
// VoIPController
|
||||
JNINativeMethod controllerMethods[]={
|
||||
{"nativeInit", "(Ljava/lang/String;)J", (void*)&tgvoip::VoIPController_nativeInit},
|
||||
{"nativeStart", "(J)V", (void*)&tgvoip::VoIPController_nativeStart},
|
||||
{"nativeConnect", "(J)V", (void*)&tgvoip::VoIPController_nativeConnect},
|
||||
{"nativeSetProxy", "(JLjava/lang/String;ILjava/lang/String;Ljava/lang/String;)V", (void*)&tgvoip::VoIPController_nativeSetProxy},
|
||||
{"nativeSetEncryptionKey", "(J[BZ)V", (void*)&tgvoip::VoIPController_nativeSetEncryptionKey},
|
||||
{"nativeSetRemoteEndpoints", "(J[L" TGVOIP_ENDPOINT_CLASS ";ZZI)V", (void*)&tgvoip::VoIPController_nativeSetRemoteEndpoints},
|
||||
{"nativeSetNativeBufferSize", "(I)V", (void*)&tgvoip::VoIPController_nativeSetNativeBufferSize},
|
||||
{"nativeRelease", "(J)V", (void*)&tgvoip::VoIPController_nativeRelease},
|
||||
{"nativeGetDebugString", "(J)Ljava/lang/String;", (void*)&tgvoip::VoIPController_nativeGetDebugString},
|
||||
{"nativeSetNetworkType", "(JI)V", (void*)&tgvoip::VoIPController_nativeSetNetworkType},
|
||||
{"nativeSetMicMute", "(JZ)V", (void*)&tgvoip::VoIPController_nativeSetMicMute},
|
||||
{"nativeSetConfig", "(JDDIZZZLjava/lang/String;Ljava/lang/String;Z)V", (void*)&tgvoip::VoIPController_nativeSetConfig},
|
||||
{"nativeDebugCtl", "(JII)V", (void*)&tgvoip::VoIPController_nativeDebugCtl},
|
||||
{"nativeGetVersion", "()Ljava/lang/String;", (void*)&tgvoip::VoIPController_nativeGetVersion},
|
||||
{"nativeGetPreferredRelayID", "(J)J", (void*)&tgvoip::VoIPController_nativeGetPreferredRelayID},
|
||||
{"nativeGetLastError", "(J)I", (void*)&tgvoip::VoIPController_nativeGetLastError},
|
||||
{"nativeGetStats", "(JL" TGVOIP_PACKAGE_PATH "/VoIPController$Stats;)V", (void*)&tgvoip::VoIPController_nativeGetStats},
|
||||
{"nativeGetDebugLog", "(J)Ljava/lang/String;", (void*)&tgvoip::VoIPController_nativeGetDebugLog},
|
||||
{"nativeSetAudioOutputGainControlEnabled", "(JZ)V", (void*)&tgvoip::VoIPController_nativeSetAudioOutputGainControlEnabled},
|
||||
{"nativeSetEchoCancellationStrength", "(JI)V", (void*)&tgvoip::VoIPController_nativeSetEchoCancellationStrength},
|
||||
{"nativeGetPeerCapabilities", "(J)I", (void*)&tgvoip::VoIPController_nativeGetPeerCapabilities},
|
||||
{"nativeSendGroupCallKey", "(J[B)V", (void*)&tgvoip::VoIPController_nativeSendGroupCallKey},
|
||||
{"nativeRequestCallUpgrade", "(J)V", (void*)&tgvoip::VoIPController_nativeRequestCallUpgrade},
|
||||
{"nativeNeedRate", "(J)Z", (void*)&tgvoip::VoIPController_nativeNeedRate},
|
||||
{"getConnectionMaxLayer", "()I", (void*)&tgvoip::VoIPController_getConnectionMaxLayer}
|
||||
#ifndef TGVOIP_NO_VIDEO
|
||||
,{"nativeSetVideoSource", "(JJ)V", (void*)&tgvoip::VoIPController_nativeSetVideoSource},
|
||||
{"nativeSetVideoRenderer", "(JJ)V", (void*)&tgvoip::VoIPController_nativeSetVideoRenderer}
|
||||
#endif
|
||||
};
|
||||
env->RegisterNatives(controller, controllerMethods, sizeof(controllerMethods)/sizeof(JNINativeMethod));
|
||||
|
||||
// VoIPGroupController
|
||||
#ifndef TGVOIP_NO_GROUP_CALLS
|
||||
if(groupController){
|
||||
setStateMethod=env->GetMethodID(groupController, "handleStateChange", "(I)V");
|
||||
setParticipantAudioEnabledMethod=env->GetMethodID(groupController, "setParticipantAudioEnabled", "(IZ)V");
|
||||
setSelfStreamsMethod=env->GetMethodID(groupController, "setSelfStreams", "([B)V");
|
||||
|
||||
JNINativeMethod groupControllerMethods[]={
|
||||
{"nativeInit", "(I)J", (void*)&tgvoip::VoIPGroupController_nativeInit},
|
||||
{"nativeSetGroupCallInfo", "(J[B[B[B[B[BILjava/lang/String;Ljava/lang/String;I)V", (void*)&tgvoip::VoIPGroupController_nativeSetGroupCallInfo},
|
||||
{"nativeAddGroupCallParticipant", "(JI[B[B)V", (void*)&tgvoip::VoIPGroupController_nativeAddGroupCallParticipant},
|
||||
{"nativeRemoveGroupCallParticipant", "(JI)V", (void*)&tgvoip::VoIPGroupController_nativeRemoveGroupCallParticipant},
|
||||
{"nativeGetParticipantAudioLevel", "(JI)F", (void*)&tgvoip::VoIPGroupController_nativeGetParticipantAudioLevel},
|
||||
{"nativeSetParticipantVolume", "(JIF)V", (void*)&tgvoip::VoIPGroupController_nativeSetParticipantVolume},
|
||||
{"getInitialStreams", "()[B", (void*)&tgvoip::VoIPGroupController_getInitialStreams},
|
||||
{"nativeSetParticipantStreams", "(JI[B)V", (void*)&tgvoip::VoIPGroupController_nativeSetParticipantStreams}
|
||||
};
|
||||
env->RegisterNatives(groupController, groupControllerMethods, sizeof(groupControllerMethods)/sizeof(JNINativeMethod));
|
||||
}
|
||||
#endif
|
||||
|
||||
// AudioRecordJNI
|
||||
JNINativeMethod audioRecordMethods[]={
|
||||
{"nativeCallback", "(Ljava/nio/ByteBuffer;)V", (void*)&tgvoip::AudioRecordJNI_nativeCallback}
|
||||
};
|
||||
env->RegisterNatives(audioRecordJNI, audioRecordMethods, sizeof(audioRecordMethods)/sizeof(JNINativeMethod));
|
||||
|
||||
// AudioTrackJNI
|
||||
JNINativeMethod audioTrackMethods[]={
|
||||
{"nativeCallback", "([B)V", (void*)&tgvoip::AudioTrackJNI_nativeCallback}
|
||||
};
|
||||
env->RegisterNatives(audioTrackJNI, audioTrackMethods, sizeof(audioTrackMethods)/sizeof(JNINativeMethod));
|
||||
|
||||
// VoIPServerConfig
|
||||
JNINativeMethod serverConfigMethods[]={
|
||||
{"nativeSetConfig", "(Ljava/lang/String;)V", (void*)&tgvoip::VoIPServerConfig_nativeSetConfig}
|
||||
};
|
||||
env->RegisterNatives(serverConfig, serverConfigMethods, sizeof(serverConfigMethods)/sizeof(JNINativeMethod));
|
||||
|
||||
// Resampler
|
||||
JNINativeMethod resamplerMethods[]={
|
||||
{"convert44to48", "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;)I", (void*)&tgvoip::Resampler_convert44to48},
|
||||
{"convert48to44", "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;)I", (void*)&tgvoip::Resampler_convert48to44}
|
||||
};
|
||||
env->RegisterNatives(resampler, resamplerMethods, sizeof(resamplerMethods)/sizeof(JNINativeMethod));
|
||||
|
||||
if(videoSource){
|
||||
// VideoSource
|
||||
JNINativeMethod videoSourceMethods[]={
|
||||
{"nativeInit", "()J", (void *) &tgvoip::VideoSource_nativeInit},
|
||||
{"nativeRelease", "(J)V", (void *) &tgvoip::VideoSource_nativeRelease},
|
||||
{"nativeSetVideoStreamParameters", "(J[Ljava/nio/ByteBuffer;II)V", (void *) &tgvoip::VideoSource_nativeSetVideoStreamParameters},
|
||||
{"nativeSendFrame", "(JLjava/nio/ByteBuffer;III)V", (void *) &tgvoip::VideoSource_nativeSendFrame},
|
||||
{"nativeSetRotation", "(JI)V", (void*)&tgvoip::VideoSource_nativeSetRotation},
|
||||
{"nativeSetPaused", "(JZ)V", (void*)&tgvoip::VideoSource_nativeSetPaused}
|
||||
};
|
||||
env->RegisterNatives(videoSource, videoSourceMethods, sizeof(videoSourceMethods)/sizeof(JNINativeMethod));
|
||||
}
|
||||
|
||||
if(videoRenderer){
|
||||
// VideoRenderer
|
||||
JNINativeMethod videoRendererMethods[]={
|
||||
{"nativeInit", "()J", (void *) &tgvoip::VideoRenderer_nativeInit}
|
||||
};
|
||||
env->RegisterNatives(videoRenderer, videoRendererMethods, sizeof(videoRendererMethods)/sizeof(JNINativeMethod));
|
||||
}
|
||||
|
||||
if(vlog){
|
||||
// VLog
|
||||
JNINativeMethod vlogMethods[]={
|
||||
{"v", "(Ljava/lang/String;)V", (void *) &tgvoip::VLog_log<0>},
|
||||
{"d", "(Ljava/lang/String;)V", (void *) &tgvoip::VLog_log<1>},
|
||||
{"i", "(Ljava/lang/String;)V", (void *) &tgvoip::VLog_log<2>},
|
||||
{"w", "(Ljava/lang/String;)V", (void *) &tgvoip::VLog_log<3>},
|
||||
{"e", "(Ljava/lang/String;)V", (void *) &tgvoip::VLog_log<4>}
|
||||
};
|
||||
env->RegisterNatives(vlog, vlogMethods, sizeof(vlogMethods)/sizeof(JNINativeMethod));
|
||||
}
|
||||
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
18
TMessagesProj/jni/libtgvoip2/client/android/tg_voip_jni.h
Normal file
18
TMessagesProj/jni/libtgvoip2/client/android/tg_voip_jni.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// Created by Grishka on 14.08.2018.
|
||||
//
|
||||
|
||||
#ifndef TELEGRAM_TG_VOIP_JNI_H
|
||||
#define TELEGRAM_TG_VOIP_JNI_H
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"{
|
||||
#endif
|
||||
void tgvoipRegisterNatives(JNIEnv* env);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //TELEGRAM_TG_VOIP_JNI_H
|
348
TMessagesProj/jni/libtgvoip2/compile
Normal file
348
TMessagesProj/jni/libtgvoip2/compile
Normal file
|
@ -0,0 +1,348 @@
|
|||
#! /bin/sh
|
||||
# Wrapper for compilers which do not understand '-c -o'.
|
||||
|
||||
scriptversion=2018-03-07.03; # UTC
|
||||
|
||||
# Copyright (C) 1999-2018 Free Software Foundation, Inc.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# This file is maintained in Automake, please report
|
||||
# bugs to <bug-automake@gnu.org> or send patches to
|
||||
# <automake-patches@gnu.org>.
|
||||
|
||||
nl='
|
||||
'
|
||||
|
||||
# We need space, tab and new line, in precisely that order. Quoting is
|
||||
# there to prevent tools from complaining about whitespace usage.
|
||||
IFS=" "" $nl"
|
||||
|
||||
file_conv=
|
||||
|
||||
# func_file_conv build_file lazy
|
||||
# Convert a $build file to $host form and store it in $file
|
||||
# Currently only supports Windows hosts. If the determined conversion
|
||||
# type is listed in (the comma separated) LAZY, no conversion will
|
||||
# take place.
|
||||
func_file_conv ()
|
||||
{
|
||||
file=$1
|
||||
case $file in
|
||||
/ | /[!/]*) # absolute file, and not a UNC file
|
||||
if test -z "$file_conv"; then
|
||||
# lazily determine how to convert abs files
|
||||
case `uname -s` in
|
||||
MINGW*)
|
||||
file_conv=mingw
|
||||
;;
|
||||
CYGWIN*)
|
||||
file_conv=cygwin
|
||||
;;
|
||||
*)
|
||||
file_conv=wine
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
case $file_conv/,$2, in
|
||||
*,$file_conv,*)
|
||||
;;
|
||||
mingw/*)
|
||||
file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
|
||||
;;
|
||||
cygwin/*)
|
||||
file=`cygpath -m "$file" || echo "$file"`
|
||||
;;
|
||||
wine/*)
|
||||
file=`winepath -w "$file" || echo "$file"`
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# func_cl_dashL linkdir
|
||||
# Make cl look for libraries in LINKDIR
|
||||
func_cl_dashL ()
|
||||
{
|
||||
func_file_conv "$1"
|
||||
if test -z "$lib_path"; then
|
||||
lib_path=$file
|
||||
else
|
||||
lib_path="$lib_path;$file"
|
||||
fi
|
||||
linker_opts="$linker_opts -LIBPATH:$file"
|
||||
}
|
||||
|
||||
# func_cl_dashl library
|
||||
# Do a library search-path lookup for cl
|
||||
func_cl_dashl ()
|
||||
{
|
||||
lib=$1
|
||||
found=no
|
||||
save_IFS=$IFS
|
||||
IFS=';'
|
||||
for dir in $lib_path $LIB
|
||||
do
|
||||
IFS=$save_IFS
|
||||
if $shared && test -f "$dir/$lib.dll.lib"; then
|
||||
found=yes
|
||||
lib=$dir/$lib.dll.lib
|
||||
break
|
||||
fi
|
||||
if test -f "$dir/$lib.lib"; then
|
||||
found=yes
|
||||
lib=$dir/$lib.lib
|
||||
break
|
||||
fi
|
||||
if test -f "$dir/lib$lib.a"; then
|
||||
found=yes
|
||||
lib=$dir/lib$lib.a
|
||||
break
|
||||
fi
|
||||
done
|
||||
IFS=$save_IFS
|
||||
|
||||
if test "$found" != yes; then
|
||||
lib=$lib.lib
|
||||
fi
|
||||
}
|
||||
|
||||
# func_cl_wrapper cl arg...
|
||||
# Adjust compile command to suit cl
|
||||
func_cl_wrapper ()
|
||||
{
|
||||
# Assume a capable shell
|
||||
lib_path=
|
||||
shared=:
|
||||
linker_opts=
|
||||
for arg
|
||||
do
|
||||
if test -n "$eat"; then
|
||||
eat=
|
||||
else
|
||||
case $1 in
|
||||
-o)
|
||||
# configure might choose to run compile as 'compile cc -o foo foo.c'.
|
||||
eat=1
|
||||
case $2 in
|
||||
*.o | *.[oO][bB][jJ])
|
||||
func_file_conv "$2"
|
||||
set x "$@" -Fo"$file"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
func_file_conv "$2"
|
||||
set x "$@" -Fe"$file"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
-I)
|
||||
eat=1
|
||||
func_file_conv "$2" mingw
|
||||
set x "$@" -I"$file"
|
||||
shift
|
||||
;;
|
||||
-I*)
|
||||
func_file_conv "${1#-I}" mingw
|
||||
set x "$@" -I"$file"
|
||||
shift
|
||||
;;
|
||||
-l)
|
||||
eat=1
|
||||
func_cl_dashl "$2"
|
||||
set x "$@" "$lib"
|
||||
shift
|
||||
;;
|
||||
-l*)
|
||||
func_cl_dashl "${1#-l}"
|
||||
set x "$@" "$lib"
|
||||
shift
|
||||
;;
|
||||
-L)
|
||||
eat=1
|
||||
func_cl_dashL "$2"
|
||||
;;
|
||||
-L*)
|
||||
func_cl_dashL "${1#-L}"
|
||||
;;
|
||||
-static)
|
||||
shared=false
|
||||
;;
|
||||
-Wl,*)
|
||||
arg=${1#-Wl,}
|
||||
save_ifs="$IFS"; IFS=','
|
||||
for flag in $arg; do
|
||||
IFS="$save_ifs"
|
||||
linker_opts="$linker_opts $flag"
|
||||
done
|
||||
IFS="$save_ifs"
|
||||
;;
|
||||
-Xlinker)
|
||||
eat=1
|
||||
linker_opts="$linker_opts $2"
|
||||
;;
|
||||
-*)
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
*.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
|
||||
func_file_conv "$1"
|
||||
set x "$@" -Tp"$file"
|
||||
shift
|
||||
;;
|
||||
*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
|
||||
func_file_conv "$1" mingw
|
||||
set x "$@" "$file"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
shift
|
||||
done
|
||||
if test -n "$linker_opts"; then
|
||||
linker_opts="-link$linker_opts"
|
||||
fi
|
||||
exec "$@" $linker_opts
|
||||
exit 1
|
||||
}
|
||||
|
||||
eat=
|
||||
|
||||
case $1 in
|
||||
'')
|
||||
echo "$0: No command. Try '$0 --help' for more information." 1>&2
|
||||
exit 1;
|
||||
;;
|
||||
-h | --h*)
|
||||
cat <<\EOF
|
||||
Usage: compile [--help] [--version] PROGRAM [ARGS]
|
||||
|
||||
Wrapper for compilers which do not understand '-c -o'.
|
||||
Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
|
||||
arguments, and rename the output as expected.
|
||||
|
||||
If you are trying to build a whole package this is not the
|
||||
right script to run: please start by reading the file 'INSTALL'.
|
||||
|
||||
Report bugs to <bug-automake@gnu.org>.
|
||||
EOF
|
||||
exit $?
|
||||
;;
|
||||
-v | --v*)
|
||||
echo "compile $scriptversion"
|
||||
exit $?
|
||||
;;
|
||||
cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \
|
||||
icl | *[/\\]icl | icl.exe | *[/\\]icl.exe )
|
||||
func_cl_wrapper "$@" # Doesn't return...
|
||||
;;
|
||||
esac
|
||||
|
||||
ofile=
|
||||
cfile=
|
||||
|
||||
for arg
|
||||
do
|
||||
if test -n "$eat"; then
|
||||
eat=
|
||||
else
|
||||
case $1 in
|
||||
-o)
|
||||
# configure might choose to run compile as 'compile cc -o foo foo.c'.
|
||||
# So we strip '-o arg' only if arg is an object.
|
||||
eat=1
|
||||
case $2 in
|
||||
*.o | *.obj)
|
||||
ofile=$2
|
||||
;;
|
||||
*)
|
||||
set x "$@" -o "$2"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*.c)
|
||||
cfile=$1
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
shift
|
||||
done
|
||||
|
||||
if test -z "$ofile" || test -z "$cfile"; then
|
||||
# If no '-o' option was seen then we might have been invoked from a
|
||||
# pattern rule where we don't need one. That is ok -- this is a
|
||||
# normal compilation that the losing compiler can handle. If no
|
||||
# '.c' file was seen then we are probably linking. That is also
|
||||
# ok.
|
||||
exec "$@"
|
||||
fi
|
||||
|
||||
# Name of file we expect compiler to create.
|
||||
cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
|
||||
|
||||
# Create the lock directory.
|
||||
# Note: use '[/\\:.-]' here to ensure that we don't use the same name
|
||||
# that we are using for the .o file. Also, base the name on the expected
|
||||
# object file name, since that is what matters with a parallel build.
|
||||
lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
|
||||
while true; do
|
||||
if mkdir "$lockdir" >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
# FIXME: race condition here if user kills between mkdir and trap.
|
||||
trap "rmdir '$lockdir'; exit 1" 1 2 15
|
||||
|
||||
# Run the compile.
|
||||
"$@"
|
||||
ret=$?
|
||||
|
||||
if test -f "$cofile"; then
|
||||
test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
|
||||
elif test -f "${cofile}bj"; then
|
||||
test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
|
||||
fi
|
||||
|
||||
rmdir "$lockdir"
|
||||
exit $ret
|
||||
|
||||
# Local Variables:
|
||||
# mode: shell-script
|
||||
# sh-indentation: 2
|
||||
# eval: (add-hook 'before-save-hook 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC0"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
1476
TMessagesProj/jni/libtgvoip2/config.guess
vendored
Normal file
1476
TMessagesProj/jni/libtgvoip2/config.guess
vendored
Normal file
File diff suppressed because it is too large
Load diff
265
TMessagesProj/jni/libtgvoip2/config.h.in
Normal file
265
TMessagesProj/jni/libtgvoip2/config.h.in
Normal file
|
@ -0,0 +1,265 @@
|
|||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
|
||||
systems. This function is required for `alloca.c' support on those systems.
|
||||
*/
|
||||
#undef CRAY_STACKSEG_END
|
||||
|
||||
/* Define to 1 if using `alloca.c'. */
|
||||
#undef C_ALLOCA
|
||||
|
||||
/* Define to 1 if you have `alloca', as a function or macro. */
|
||||
#undef HAVE_ALLOCA
|
||||
|
||||
/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
|
||||
*/
|
||||
#undef HAVE_ALLOCA_H
|
||||
|
||||
/* Define to 1 if you have the <arpa/inet.h> header file. */
|
||||
#undef HAVE_ARPA_INET_H
|
||||
|
||||
/* Define to 1 if you have the `clock_gettime' function. */
|
||||
#undef HAVE_CLOCK_GETTIME
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#undef HAVE_DLFCN_H
|
||||
|
||||
/* Define to 1 if you have the <float.h> header file. */
|
||||
#undef HAVE_FLOAT_H
|
||||
|
||||
/* Define to 1 if you have the `floor' function. */
|
||||
#undef HAVE_FLOOR
|
||||
|
||||
/* Define to 1 if you have the `gettimeofday' function. */
|
||||
#undef HAVE_GETTIMEOFDAY
|
||||
|
||||
/* Define to 1 if you have the `inet_ntoa' function. */
|
||||
#undef HAVE_INET_NTOA
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the `crypto' library (-lcrypto). */
|
||||
#undef HAVE_LIBCRYPTO
|
||||
|
||||
/* Define to 1 if you have the `dl' library (-ldl). */
|
||||
#undef HAVE_LIBDL
|
||||
|
||||
/* Define to 1 if you have the `m' library (-lm). */
|
||||
#undef HAVE_LIBM
|
||||
|
||||
/* Define to 1 if you have the `opus' library (-lopus). */
|
||||
#undef HAVE_LIBOPUS
|
||||
|
||||
/* Define to 1 if you have the `pthread' library (-lpthread). */
|
||||
#undef HAVE_LIBPTHREAD
|
||||
|
||||
/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
|
||||
to 0 otherwise. */
|
||||
#undef HAVE_MALLOC
|
||||
|
||||
/* Define to 1 if you have the <malloc.h> header file. */
|
||||
#undef HAVE_MALLOC_H
|
||||
|
||||
/* Define to 1 if you have the `memmove' function. */
|
||||
#undef HAVE_MEMMOVE
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the `memset' function. */
|
||||
#undef HAVE_MEMSET
|
||||
|
||||
/* Define to 1 if you have the <netdb.h> header file. */
|
||||
#undef HAVE_NETDB_H
|
||||
|
||||
/* Define to 1 if you have the <netinet/in.h> header file. */
|
||||
#undef HAVE_NETINET_IN_H
|
||||
|
||||
/* Define to 1 if the system has the type `ptrdiff_t'. */
|
||||
#undef HAVE_PTRDIFF_T
|
||||
|
||||
/* Define to 1 if your system has a GNU libc compatible `realloc' function,
|
||||
and to 0 otherwise. */
|
||||
#undef HAVE_REALLOC
|
||||
|
||||
/* Define to 1 if you have the `select' function. */
|
||||
#undef HAVE_SELECT
|
||||
|
||||
/* Define to 1 if you have the `socket' function. */
|
||||
#undef HAVE_SOCKET
|
||||
|
||||
/* Define to 1 if you have the `sqrt' function. */
|
||||
#undef HAVE_SQRT
|
||||
|
||||
/* Define to 1 if you have the <stddef.h> header file. */
|
||||
#undef HAVE_STDDEF_H
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the `strcasecmp' function. */
|
||||
#undef HAVE_STRCASECMP
|
||||
|
||||
/* Define to 1 if you have the `strchr' function. */
|
||||
#undef HAVE_STRCHR
|
||||
|
||||
/* Define to 1 if you have the `strerror' function. */
|
||||
#undef HAVE_STRERROR
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the `strncasecmp' function. */
|
||||
#undef HAVE_STRNCASECMP
|
||||
|
||||
/* Define to 1 if you have the `strstr' function. */
|
||||
#undef HAVE_STRSTR
|
||||
|
||||
/* Define to 1 if you have the `strtol' function. */
|
||||
#undef HAVE_STRTOL
|
||||
|
||||
/* Define to 1 if you have the `strtoul' function. */
|
||||
#undef HAVE_STRTOUL
|
||||
|
||||
/* Define to 1 if you have the <sys/ioctl.h> header file. */
|
||||
#undef HAVE_SYS_IOCTL_H
|
||||
|
||||
/* Define to 1 if you have the <sys/socket.h> header file. */
|
||||
#undef HAVE_SYS_SOCKET_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/time.h> header file. */
|
||||
#undef HAVE_SYS_TIME_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the `uname' function. */
|
||||
#undef HAVE_UNAME
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Define to 1 if you have the <wchar.h> header file. */
|
||||
#undef HAVE_WCHAR_H
|
||||
|
||||
/* Define to 1 if the system has the type `_Bool'. */
|
||||
#undef HAVE__BOOL
|
||||
|
||||
/* Define to the sub-directory where libtool stores uninstalled libraries. */
|
||||
#undef LT_OBJDIR
|
||||
|
||||
/* Name of package */
|
||||
#undef PACKAGE
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#undef PACKAGE_URL
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* If using the C implementation of alloca, define if you know the
|
||||
direction of stack growth for your system; otherwise it will be
|
||||
automatically deduced at runtime.
|
||||
STACK_DIRECTION > 0 => grows toward higher addresses
|
||||
STACK_DIRECTION < 0 => grows toward lower addresses
|
||||
STACK_DIRECTION = 0 => direction of growth unknown */
|
||||
#undef STACK_DIRECTION
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Version number of package */
|
||||
#undef VERSION
|
||||
|
||||
/* Define to disable ALSA support */
|
||||
#undef WITHOUT_ALSA
|
||||
|
||||
/* Define to disable PulseAudio support */
|
||||
#undef WITHOUT_PULSE
|
||||
|
||||
/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>,
|
||||
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
|
||||
#define below would cause a syntax error. */
|
||||
#undef _UINT32_T
|
||||
|
||||
/* Define for Solaris 2.5.1 so the uint64_t typedef from <sys/synch.h>,
|
||||
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
|
||||
#define below would cause a syntax error. */
|
||||
#undef _UINT64_T
|
||||
|
||||
/* Define for Solaris 2.5.1 so the uint8_t typedef from <sys/synch.h>,
|
||||
<pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the
|
||||
#define below would cause a syntax error. */
|
||||
#undef _UINT8_T
|
||||
|
||||
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
calls it, or to nothing if 'inline' is not supported under any name. */
|
||||
#ifndef __cplusplus
|
||||
#undef inline
|
||||
#endif
|
||||
|
||||
/* Define to the type of a signed integer type of width exactly 16 bits if
|
||||
such a type exists and the standard includes do not define it. */
|
||||
#undef int16_t
|
||||
|
||||
/* Define to the type of a signed integer type of width exactly 32 bits if
|
||||
such a type exists and the standard includes do not define it. */
|
||||
#undef int32_t
|
||||
|
||||
/* Define to the type of a signed integer type of width exactly 64 bits if
|
||||
such a type exists and the standard includes do not define it. */
|
||||
#undef int64_t
|
||||
|
||||
/* Define to the type of a signed integer type of width exactly 8 bits if such
|
||||
a type exists and the standard includes do not define it. */
|
||||
#undef int8_t
|
||||
|
||||
/* Define to rpl_malloc if the replacement function should be used. */
|
||||
#undef malloc
|
||||
|
||||
/* Define to rpl_realloc if the replacement function should be used. */
|
||||
#undef realloc
|
||||
|
||||
/* Define to `unsigned int' if <sys/types.h> does not define. */
|
||||
#undef size_t
|
||||
|
||||
/* Define to `int' if <sys/types.h> does not define. */
|
||||
#undef ssize_t
|
||||
|
||||
/* Define to the type of an unsigned integer type of width exactly 16 bits if
|
||||
such a type exists and the standard includes do not define it. */
|
||||
#undef uint16_t
|
||||
|
||||
/* Define to the type of an unsigned integer type of width exactly 32 bits if
|
||||
such a type exists and the standard includes do not define it. */
|
||||
#undef uint32_t
|
||||
|
||||
/* Define to the type of an unsigned integer type of width exactly 64 bits if
|
||||
such a type exists and the standard includes do not define it. */
|
||||
#undef uint64_t
|
||||
|
||||
/* Define to the type of an unsigned integer type of width exactly 8 bits if
|
||||
such a type exists and the standard includes do not define it. */
|
||||
#undef uint8_t
|
1801
TMessagesProj/jni/libtgvoip2/config.sub
vendored
Normal file
1801
TMessagesProj/jni/libtgvoip2/config.sub
vendored
Normal file
File diff suppressed because it is too large
Load diff
21185
TMessagesProj/jni/libtgvoip2/configure
vendored
Normal file
21185
TMessagesProj/jni/libtgvoip2/configure
vendored
Normal file
File diff suppressed because it is too large
Load diff
125
TMessagesProj/jni/libtgvoip2/configure.ac
Normal file
125
TMessagesProj/jni/libtgvoip2/configure.ac
Normal file
|
@ -0,0 +1,125 @@
|
|||
# -*- Autoconf -*-
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
# Define version information
|
||||
m4_define([libtgvoip_major_version], 2)
|
||||
m4_define([libtgvoip_minor_version], 4)
|
||||
m4_define([libtgvoip_patch_version], 4)
|
||||
m4_define([libtgvoip_version],[libtgvoip_major_version.libtgvoip_minor_version.libtgvoip_patch_version])
|
||||
|
||||
AC_PREREQ([2.69])
|
||||
AC_INIT([libtgvoip], [libtgvoip_version], [https://github.com/grishka/libtgvoip/issues])
|
||||
AC_CONFIG_SRCDIR([config.h.in])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AM_INIT_AUTOMAKE([subdir-objects])
|
||||
AM_SILENT_RULES([yes])
|
||||
LT_INIT
|
||||
|
||||
PKG_INSTALLDIR
|
||||
|
||||
# Checks for programs.
|
||||
AC_PROG_CXX
|
||||
AC_PROG_CC
|
||||
AC_PROG_OBJCXX
|
||||
AM_PROG_AS
|
||||
AC_PROG_RANLIB
|
||||
|
||||
# Checks for libraries.
|
||||
AC_CHECK_LIB([crypto], [SHA1], [], [AC_MSG_FAILURE([libssl-dev is required but not found])])
|
||||
AC_CHECK_LIB([m], [floorf])
|
||||
AC_CHECK_LIB([opus], [opus_decoder_create], [], [AC_MSG_FAILURE([libopus-dev is required but not found])])
|
||||
AC_CHECK_LIB([pthread], [pthread_create])
|
||||
|
||||
AC_CANONICAL_HOST
|
||||
|
||||
AC_SUBST(LIBTGVOIP_MAJOR_VERSION, libtgvoip_major_version)
|
||||
AC_SUBST(LIBTGVOIP_MINOR_VERSION, libtgvoip_minor_version)
|
||||
AC_SUBST(LIBTGVOIP_PATCH_VERSION, libtgvoip_patch_version)
|
||||
|
||||
AS_CASE([$host_cpu],
|
||||
[i?86], [cpu_x86=yes],
|
||||
[x86_64], [cpu_x86=yes],
|
||||
[arm*], [cpu_arm=yes],
|
||||
[AS_ECHO("!! WARNING: libtgvoip wasn't tested with your CPU architecture ($host_cpu)")]
|
||||
)
|
||||
AS_CASE([$host_cpu],
|
||||
[armv7*], [cpu_armv7=yes]
|
||||
)
|
||||
AS_ECHO("Detected CPU: $host_cpu")
|
||||
AM_CONDITIONAL(TARGET_CPU_X86, test "x$cpu_x86" == xyes)
|
||||
AM_CONDITIONAL(TARGET_CPU_ARM, test "x$cpu_arm" == xyes)
|
||||
AM_CONDITIONAL(TARGET_CPU_ARMV7, test "x$cpu_armv7" == xyes)
|
||||
AS_ECHO("Detected OS: $host_os")
|
||||
|
||||
AS_CASE([$host_os],
|
||||
[darwin*], [os_osx=yes]
|
||||
)
|
||||
AM_CONDITIONAL(TARGET_OS_OSX, test "x$os_osx" == xyes)
|
||||
|
||||
AC_ARG_ENABLE([audio-callback], [AS_HELP_STRING([--enable-audio-callback], [enable callback-based audio I/O])], [], [enable_audio_callback=no])
|
||||
AM_CONDITIONAL(ENABLE_AUDIO_CALLBACK, test "x$enable_audio_callback" == xyes)
|
||||
|
||||
AS_IF([test "x$os_osx" != xyes && test "x$enable_audio_callback" != xyes], [ # Linux
|
||||
AC_CHECK_LIB([dl], [dlopen])
|
||||
|
||||
AC_ARG_WITH([pulse], [AS_HELP_STRING([--without-pulse], [disable PulseAudio support])], [], [with_pulse=yes])
|
||||
AC_ARG_WITH([alsa], [AS_HELP_STRING([--without-alsa], [disable ALSA support])], [], [with_alsa=yes])
|
||||
|
||||
AS_IF([test "x$with_pulse" == xno && test "x$with_alsa" == xno], [
|
||||
AC_MSG_FAILURE([You can only disable either ALSA or PulseAudio, not both]);
|
||||
])
|
||||
|
||||
AS_IF([test "x$with_pulse" != xno], [
|
||||
AC_CHECK_LIB([pulse], [pa_context_new], [
|
||||
AS_ECHO_N( ) # what is the proper way to check for a library without linking it?
|
||||
], [
|
||||
AC_MSG_FAILURE([libpulse-dev is required during build, but you don't have it installed. Use --without-pulse to disable PulseAudio support.])
|
||||
])
|
||||
], [
|
||||
AC_DEFINE([WITHOUT_PULSE], [1], [Define to disable PulseAudio support])
|
||||
])
|
||||
|
||||
AS_IF([test "x$with_alsa" != xno], [
|
||||
AC_CHECK_LIB([asound], [snd_pcm_open], [
|
||||
AS_ECHO_N( ) # what is the proper way to check for a library without linking it?
|
||||
], [
|
||||
AC_MSG_FAILURE([libasound-dev is required during build, but you don't have it installed. Use --without-alsa to disable ALSA support.])
|
||||
])
|
||||
], [
|
||||
AC_DEFINE([WITHOUT_ALSA], [1], [Define to disable ALSA support])
|
||||
])
|
||||
]);
|
||||
|
||||
AM_CONDITIONAL(WITH_PULSE, test "x$with_pulse" == xyes)
|
||||
AM_CONDITIONAL(WITH_ALSA, test "x$with_alsa" == xyes)
|
||||
|
||||
AC_ARG_ENABLE([dsp], [AS_HELP_STRING([--disable-dsp], [disable signal processing (echo cancellation, noise suppression, and automatic gain control)])], [], [enable_dsp=yes])
|
||||
AM_CONDITIONAL(ENABLE_DSP, test "x$enable_dsp" == xyes)
|
||||
|
||||
# Checks for header files.
|
||||
AC_FUNC_ALLOCA
|
||||
AC_CHECK_HEADERS([arpa/inet.h float.h malloc.h netdb.h netinet/in.h stddef.h stdint.h stdlib.h string.h sys/ioctl.h sys/socket.h sys/time.h unistd.h wchar.h])
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_CHECK_HEADER_STDBOOL
|
||||
AC_C_INLINE
|
||||
AC_TYPE_INT16_T
|
||||
AC_TYPE_INT32_T
|
||||
AC_TYPE_INT64_T
|
||||
AC_TYPE_INT8_T
|
||||
AC_TYPE_SIZE_T
|
||||
AC_TYPE_SSIZE_T
|
||||
AC_TYPE_UINT16_T
|
||||
AC_TYPE_UINT32_T
|
||||
AC_TYPE_UINT64_T
|
||||
AC_TYPE_UINT8_T
|
||||
AC_CHECK_TYPES([ptrdiff_t])
|
||||
|
||||
# Checks for library functions.
|
||||
AC_FUNC_ERROR_AT_LINE
|
||||
AC_FUNC_MALLOC
|
||||
AC_FUNC_REALLOC
|
||||
AC_CHECK_FUNCS([clock_gettime floor gettimeofday inet_ntoa memmove memset select socket sqrt strcasecmp strchr strerror strncasecmp strstr strtol strtoul uname])
|
||||
|
||||
AC_CONFIG_FILES([Makefile tgvoip.pc])
|
||||
AC_OUTPUT
|
791
TMessagesProj/jni/libtgvoip2/depcomp
Normal file
791
TMessagesProj/jni/libtgvoip2/depcomp
Normal file
|
@ -0,0 +1,791 @@
|
|||
#! /bin/sh
|
||||
# depcomp - compile a program generating dependencies as side-effects
|
||||
|
||||
scriptversion=2018-03-07.03; # UTC
|
||||
|
||||
# Copyright (C) 1999-2018 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
|
||||
|
||||
case $1 in
|
||||
'')
|
||||
echo "$0: No command. Try '$0 --help' for more information." 1>&2
|
||||
exit 1;
|
||||
;;
|
||||
-h | --h*)
|
||||
cat <<\EOF
|
||||
Usage: depcomp [--help] [--version] PROGRAM [ARGS]
|
||||
|
||||
Run PROGRAMS ARGS to compile a file, generating dependencies
|
||||
as side-effects.
|
||||
|
||||
Environment variables:
|
||||
depmode Dependency tracking mode.
|
||||
source Source file read by 'PROGRAMS ARGS'.
|
||||
object Object file output by 'PROGRAMS ARGS'.
|
||||
DEPDIR directory where to store dependencies.
|
||||
depfile Dependency file to output.
|
||||
tmpdepfile Temporary file to use when outputting dependencies.
|
||||
libtool Whether libtool is used (yes/no).
|
||||
|
||||
Report bugs to <bug-automake@gnu.org>.
|
||||
EOF
|
||||
exit $?
|
||||
;;
|
||||
-v | --v*)
|
||||
echo "depcomp $scriptversion"
|
||||
exit $?
|
||||
;;
|
||||
esac
|
||||
|
||||
# Get the directory component of the given path, and save it in the
|
||||
# global variables '$dir'. Note that this directory component will
|
||||
# be either empty or ending with a '/' character. This is deliberate.
|
||||
set_dir_from ()
|
||||
{
|
||||
case $1 in
|
||||
*/*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
|
||||
*) dir=;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Get the suffix-stripped basename of the given path, and save it the
|
||||
# global variable '$base'.
|
||||
set_base_from ()
|
||||
{
|
||||
base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
|
||||
}
|
||||
|
||||
# If no dependency file was actually created by the compiler invocation,
|
||||
# we still have to create a dummy depfile, to avoid errors with the
|
||||
# Makefile "include basename.Plo" scheme.
|
||||
make_dummy_depfile ()
|
||||
{
|
||||
echo "#dummy" > "$depfile"
|
||||
}
|
||||
|
||||
# Factor out some common post-processing of the generated depfile.
|
||||
# Requires the auxiliary global variable '$tmpdepfile' to be set.
|
||||
aix_post_process_depfile ()
|
||||
{
|
||||
# If the compiler actually managed to produce a dependency file,
|
||||
# post-process it.
|
||||
if test -f "$tmpdepfile"; then
|
||||
# Each line is of the form 'foo.o: dependency.h'.
|
||||
# Do two passes, one to just change these to
|
||||
# $object: dependency.h
|
||||
# and one to simply output
|
||||
# dependency.h:
|
||||
# which is needed to avoid the deleted-header problem.
|
||||
{ sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
|
||||
sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
|
||||
} > "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
else
|
||||
make_dummy_depfile
|
||||
fi
|
||||
}
|
||||
|
||||
# A tabulation character.
|
||||
tab=' '
|
||||
# A newline character.
|
||||
nl='
|
||||
'
|
||||
# Character ranges might be problematic outside the C locale.
|
||||
# These definitions help.
|
||||
upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||
lower=abcdefghijklmnopqrstuvwxyz
|
||||
digits=0123456789
|
||||
alpha=${upper}${lower}
|
||||
|
||||
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
|
||||
echo "depcomp: Variables source, object and depmode must be set" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
|
||||
depfile=${depfile-`echo "$object" |
|
||||
sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
|
||||
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
|
||||
|
||||
rm -f "$tmpdepfile"
|
||||
|
||||
# Avoid interferences from the environment.
|
||||
gccflag= dashmflag=
|
||||
|
||||
# Some modes work just like other modes, but use different flags. We
|
||||
# parameterize here, but still list the modes in the big case below,
|
||||
# to make depend.m4 easier to write. Note that we *cannot* use a case
|
||||
# here, because this file can only contain one case statement.
|
||||
if test "$depmode" = hp; then
|
||||
# HP compiler uses -M and no extra arg.
|
||||
gccflag=-M
|
||||
depmode=gcc
|
||||
fi
|
||||
|
||||
if test "$depmode" = dashXmstdout; then
|
||||
# This is just like dashmstdout with a different argument.
|
||||
dashmflag=-xM
|
||||
depmode=dashmstdout
|
||||
fi
|
||||
|
||||
cygpath_u="cygpath -u -f -"
|
||||
if test "$depmode" = msvcmsys; then
|
||||
# This is just like msvisualcpp but w/o cygpath translation.
|
||||
# Just convert the backslash-escaped backslashes to single forward
|
||||
# slashes to satisfy depend.m4
|
||||
cygpath_u='sed s,\\\\,/,g'
|
||||
depmode=msvisualcpp
|
||||
fi
|
||||
|
||||
if test "$depmode" = msvc7msys; then
|
||||
# This is just like msvc7 but w/o cygpath translation.
|
||||
# Just convert the backslash-escaped backslashes to single forward
|
||||
# slashes to satisfy depend.m4
|
||||
cygpath_u='sed s,\\\\,/,g'
|
||||
depmode=msvc7
|
||||
fi
|
||||
|
||||
if test "$depmode" = xlc; then
|
||||
# IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
|
||||
gccflag=-qmakedep=gcc,-MF
|
||||
depmode=gcc
|
||||
fi
|
||||
|
||||
case "$depmode" in
|
||||
gcc3)
|
||||
## gcc 3 implements dependency tracking that does exactly what
|
||||
## we want. Yay! Note: for some reason libtool 1.4 doesn't like
|
||||
## it if -MD -MP comes after the -MF stuff. Hmm.
|
||||
## Unfortunately, FreeBSD c89 acceptance of flags depends upon
|
||||
## the command line argument order; so add the flags where they
|
||||
## appear in depend2.am. Note that the slowdown incurred here
|
||||
## affects only configure: in makefiles, %FASTDEP% shortcuts this.
|
||||
for arg
|
||||
do
|
||||
case $arg in
|
||||
-c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
|
||||
*) set fnord "$@" "$arg" ;;
|
||||
esac
|
||||
shift # fnord
|
||||
shift # $arg
|
||||
done
|
||||
"$@"
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
mv "$tmpdepfile" "$depfile"
|
||||
;;
|
||||
|
||||
gcc)
|
||||
## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
|
||||
## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
|
||||
## (see the conditional assignment to $gccflag above).
|
||||
## There are various ways to get dependency output from gcc. Here's
|
||||
## why we pick this rather obscure method:
|
||||
## - Don't want to use -MD because we'd like the dependencies to end
|
||||
## up in a subdir. Having to rename by hand is ugly.
|
||||
## (We might end up doing this anyway to support other compilers.)
|
||||
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
|
||||
## -MM, not -M (despite what the docs say). Also, it might not be
|
||||
## supported by the other compilers which use the 'gcc' depmode.
|
||||
## - Using -M directly means running the compiler twice (even worse
|
||||
## than renaming).
|
||||
if test -z "$gccflag"; then
|
||||
gccflag=-MD,
|
||||
fi
|
||||
"$@" -Wp,"$gccflag$tmpdepfile"
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
# The second -e expression handles DOS-style file names with drive
|
||||
# letters.
|
||||
sed -e 's/^[^:]*: / /' \
|
||||
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
|
||||
## This next piece of magic avoids the "deleted header file" problem.
|
||||
## The problem is that when a header file which appears in a .P file
|
||||
## is deleted, the dependency causes make to die (because there is
|
||||
## typically no way to rebuild the header). We avoid this by adding
|
||||
## dummy dependencies for each header file. Too bad gcc doesn't do
|
||||
## this for us directly.
|
||||
## Some versions of gcc put a space before the ':'. On the theory
|
||||
## that the space means something, we add a space to the output as
|
||||
## well. hp depmode also adds that space, but also prefixes the VPATH
|
||||
## to the object. Take care to not repeat it in the output.
|
||||
## Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
## correctly. Breaking it into two sed invocations is a workaround.
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
hp)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
sgi)
|
||||
if test "$libtool" = yes; then
|
||||
"$@" "-Wp,-MDupdate,$tmpdepfile"
|
||||
else
|
||||
"$@" -MDupdate "$tmpdepfile"
|
||||
fi
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
|
||||
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
|
||||
echo "$object : \\" > "$depfile"
|
||||
# Clip off the initial element (the dependent). Don't try to be
|
||||
# clever and replace this with sed code, as IRIX sed won't handle
|
||||
# lines with more than a fixed number of characters (4096 in
|
||||
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
|
||||
# the IRIX cc adds comments like '#:fec' to the end of the
|
||||
# dependency line.
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
|
||||
| tr "$nl" ' ' >> "$depfile"
|
||||
echo >> "$depfile"
|
||||
# The second pass generates a dummy entry for each header file.
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
|
||||
>> "$depfile"
|
||||
else
|
||||
make_dummy_depfile
|
||||
fi
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
xlc)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
aix)
|
||||
# The C for AIX Compiler uses -M and outputs the dependencies
|
||||
# in a .u file. In older versions, this file always lives in the
|
||||
# current directory. Also, the AIX compiler puts '$object:' at the
|
||||
# start of each line; $object doesn't have directory information.
|
||||
# Version 6 uses the directory in both cases.
|
||||
set_dir_from "$object"
|
||||
set_base_from "$object"
|
||||
if test "$libtool" = yes; then
|
||||
tmpdepfile1=$dir$base.u
|
||||
tmpdepfile2=$base.u
|
||||
tmpdepfile3=$dir.libs/$base.u
|
||||
"$@" -Wc,-M
|
||||
else
|
||||
tmpdepfile1=$dir$base.u
|
||||
tmpdepfile2=$dir$base.u
|
||||
tmpdepfile3=$dir$base.u
|
||||
"$@" -M
|
||||
fi
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
do
|
||||
test -f "$tmpdepfile" && break
|
||||
done
|
||||
aix_post_process_depfile
|
||||
;;
|
||||
|
||||
tcc)
|
||||
# tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
|
||||
# FIXME: That version still under development at the moment of writing.
|
||||
# Make that this statement remains true also for stable, released
|
||||
# versions.
|
||||
# It will wrap lines (doesn't matter whether long or short) with a
|
||||
# trailing '\', as in:
|
||||
#
|
||||
# foo.o : \
|
||||
# foo.c \
|
||||
# foo.h \
|
||||
#
|
||||
# It will put a trailing '\' even on the last line, and will use leading
|
||||
# spaces rather than leading tabs (at least since its commit 0394caf7
|
||||
# "Emit spaces for -MD").
|
||||
"$@" -MD -MF "$tmpdepfile"
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
# Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
|
||||
# We have to change lines of the first kind to '$object: \'.
|
||||
sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
|
||||
# And for each line of the second kind, we have to emit a 'dep.h:'
|
||||
# dummy dependency, to avoid the deleted-header problem.
|
||||
sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
## The order of this option in the case statement is important, since the
|
||||
## shell code in configure will try each of these formats in the order
|
||||
## listed in this file. A plain '-MD' option would be understood by many
|
||||
## compilers, so we must ensure this comes after the gcc and icc options.
|
||||
pgcc)
|
||||
# Portland's C compiler understands '-MD'.
|
||||
# Will always output deps to 'file.d' where file is the root name of the
|
||||
# source file under compilation, even if file resides in a subdirectory.
|
||||
# The object file name does not affect the name of the '.d' file.
|
||||
# pgcc 10.2 will output
|
||||
# foo.o: sub/foo.c sub/foo.h
|
||||
# and will wrap long lines using '\' :
|
||||
# foo.o: sub/foo.c ... \
|
||||
# sub/foo.h ... \
|
||||
# ...
|
||||
set_dir_from "$object"
|
||||
# Use the source, not the object, to determine the base name, since
|
||||
# that's sadly what pgcc will do too.
|
||||
set_base_from "$source"
|
||||
tmpdepfile=$base.d
|
||||
|
||||
# For projects that build the same source file twice into different object
|
||||
# files, the pgcc approach of using the *source* file root name can cause
|
||||
# problems in parallel builds. Use a locking strategy to avoid stomping on
|
||||
# the same $tmpdepfile.
|
||||
lockdir=$base.d-lock
|
||||
trap "
|
||||
echo '$0: caught signal, cleaning up...' >&2
|
||||
rmdir '$lockdir'
|
||||
exit 1
|
||||
" 1 2 13 15
|
||||
numtries=100
|
||||
i=$numtries
|
||||
while test $i -gt 0; do
|
||||
# mkdir is a portable test-and-set.
|
||||
if mkdir "$lockdir" 2>/dev/null; then
|
||||
# This process acquired the lock.
|
||||
"$@" -MD
|
||||
stat=$?
|
||||
# Release the lock.
|
||||
rmdir "$lockdir"
|
||||
break
|
||||
else
|
||||
# If the lock is being held by a different process, wait
|
||||
# until the winning process is done or we timeout.
|
||||
while test -d "$lockdir" && test $i -gt 0; do
|
||||
sleep 1
|
||||
i=`expr $i - 1`
|
||||
done
|
||||
fi
|
||||
i=`expr $i - 1`
|
||||
done
|
||||
trap - 1 2 13 15
|
||||
if test $i -le 0; then
|
||||
echo "$0: failed to acquire lock after $numtries attempts" >&2
|
||||
echo "$0: check lockdir '$lockdir'" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
# Each line is of the form `foo.o: dependent.h',
|
||||
# or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
|
||||
# Do two passes, one to just change these to
|
||||
# `$object: dependent.h' and one to simply `dependent.h:'.
|
||||
sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
|
||||
# Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
# correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
hp2)
|
||||
# The "hp" stanza above does not work with aCC (C++) and HP's ia64
|
||||
# compilers, which have integrated preprocessors. The correct option
|
||||
# to use with these is +Maked; it writes dependencies to a file named
|
||||
# 'foo.d', which lands next to the object file, wherever that
|
||||
# happens to be.
|
||||
# Much of this is similar to the tru64 case; see comments there.
|
||||
set_dir_from "$object"
|
||||
set_base_from "$object"
|
||||
if test "$libtool" = yes; then
|
||||
tmpdepfile1=$dir$base.d
|
||||
tmpdepfile2=$dir.libs/$base.d
|
||||
"$@" -Wc,+Maked
|
||||
else
|
||||
tmpdepfile1=$dir$base.d
|
||||
tmpdepfile2=$dir$base.d
|
||||
"$@" +Maked
|
||||
fi
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
|
||||
do
|
||||
test -f "$tmpdepfile" && break
|
||||
done
|
||||
if test -f "$tmpdepfile"; then
|
||||
sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
|
||||
# Add 'dependent.h:' lines.
|
||||
sed -ne '2,${
|
||||
s/^ *//
|
||||
s/ \\*$//
|
||||
s/$/:/
|
||||
p
|
||||
}' "$tmpdepfile" >> "$depfile"
|
||||
else
|
||||
make_dummy_depfile
|
||||
fi
|
||||
rm -f "$tmpdepfile" "$tmpdepfile2"
|
||||
;;
|
||||
|
||||
tru64)
|
||||
# The Tru64 compiler uses -MD to generate dependencies as a side
|
||||
# effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
|
||||
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
|
||||
# dependencies in 'foo.d' instead, so we check for that too.
|
||||
# Subdirectories are respected.
|
||||
set_dir_from "$object"
|
||||
set_base_from "$object"
|
||||
|
||||
if test "$libtool" = yes; then
|
||||
# Libtool generates 2 separate objects for the 2 libraries. These
|
||||
# two compilations output dependencies in $dir.libs/$base.o.d and
|
||||
# in $dir$base.o.d. We have to check for both files, because
|
||||
# one of the two compilations can be disabled. We should prefer
|
||||
# $dir$base.o.d over $dir.libs/$base.o.d because the latter is
|
||||
# automatically cleaned when .libs/ is deleted, while ignoring
|
||||
# the former would cause a distcleancheck panic.
|
||||
tmpdepfile1=$dir$base.o.d # libtool 1.5
|
||||
tmpdepfile2=$dir.libs/$base.o.d # Likewise.
|
||||
tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504
|
||||
"$@" -Wc,-MD
|
||||
else
|
||||
tmpdepfile1=$dir$base.d
|
||||
tmpdepfile2=$dir$base.d
|
||||
tmpdepfile3=$dir$base.d
|
||||
"$@" -MD
|
||||
fi
|
||||
|
||||
stat=$?
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
|
||||
do
|
||||
test -f "$tmpdepfile" && break
|
||||
done
|
||||
# Same post-processing that is required for AIX mode.
|
||||
aix_post_process_depfile
|
||||
;;
|
||||
|
||||
msvc7)
|
||||
if test "$libtool" = yes; then
|
||||
showIncludes=-Wc,-showIncludes
|
||||
else
|
||||
showIncludes=-showIncludes
|
||||
fi
|
||||
"$@" $showIncludes > "$tmpdepfile"
|
||||
stat=$?
|
||||
grep -v '^Note: including file: ' "$tmpdepfile"
|
||||
if test $stat -ne 0; then
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
# The first sed program below extracts the file names and escapes
|
||||
# backslashes for cygpath. The second sed program outputs the file
|
||||
# name when reading, but also accumulates all include files in the
|
||||
# hold buffer in order to output them again at the end. This only
|
||||
# works with sed implementations that can handle large buffers.
|
||||
sed < "$tmpdepfile" -n '
|
||||
/^Note: including file: *\(.*\)/ {
|
||||
s//\1/
|
||||
s/\\/\\\\/g
|
||||
p
|
||||
}' | $cygpath_u | sort -u | sed -n '
|
||||
s/ /\\ /g
|
||||
s/\(.*\)/'"$tab"'\1 \\/p
|
||||
s/.\(.*\) \\/\1:/
|
||||
H
|
||||
$ {
|
||||
s/.*/'"$tab"'/
|
||||
G
|
||||
p
|
||||
}' >> "$depfile"
|
||||
echo >> "$depfile" # make sure the fragment doesn't end with a backslash
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvc7msys)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
#nosideeffect)
|
||||
# This comment above is used by automake to tell side-effect
|
||||
# dependency tracking mechanisms from slower ones.
|
||||
|
||||
dashmstdout)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the preprocessed file to stdout, regardless of -o.
|
||||
"$@" || exit $?
|
||||
|
||||
# Remove the call to Libtool.
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
|
||||
# Remove '-o $object'.
|
||||
IFS=" "
|
||||
for arg
|
||||
do
|
||||
case $arg in
|
||||
-o)
|
||||
shift
|
||||
;;
|
||||
$object)
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"
|
||||
shift # fnord
|
||||
shift # $arg
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
test -z "$dashmflag" && dashmflag=-M
|
||||
# Require at least two characters before searching for ':'
|
||||
# in the target name. This is to cope with DOS-style filenames:
|
||||
# a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
|
||||
"$@" $dashmflag |
|
||||
sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
|
||||
rm -f "$depfile"
|
||||
cat < "$tmpdepfile" > "$depfile"
|
||||
# Some versions of the HPUX 10.20 sed can't process this sed invocation
|
||||
# correctly. Breaking it into two sed invocations is a workaround.
|
||||
tr ' ' "$nl" < "$tmpdepfile" \
|
||||
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
dashXmstdout)
|
||||
# This case only exists to satisfy depend.m4. It is never actually
|
||||
# run, as this mode is specially recognized in the preamble.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
makedepend)
|
||||
"$@" || exit $?
|
||||
# Remove any Libtool call
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
# X makedepend
|
||||
shift
|
||||
cleared=no eat=no
|
||||
for arg
|
||||
do
|
||||
case $cleared in
|
||||
no)
|
||||
set ""; shift
|
||||
cleared=yes ;;
|
||||
esac
|
||||
if test $eat = yes; then
|
||||
eat=no
|
||||
continue
|
||||
fi
|
||||
case "$arg" in
|
||||
-D*|-I*)
|
||||
set fnord "$@" "$arg"; shift ;;
|
||||
# Strip any option that makedepend may not understand. Remove
|
||||
# the object too, otherwise makedepend will parse it as a source file.
|
||||
-arch)
|
||||
eat=yes ;;
|
||||
-*|$object)
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"; shift ;;
|
||||
esac
|
||||
done
|
||||
obj_suffix=`echo "$object" | sed 's/^.*\././'`
|
||||
touch "$tmpdepfile"
|
||||
${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
|
||||
rm -f "$depfile"
|
||||
# makedepend may prepend the VPATH from the source file name to the object.
|
||||
# No need to regex-escape $object, excess matching of '.' is harmless.
|
||||
sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
|
||||
# Some versions of the HPUX 10.20 sed can't process the last invocation
|
||||
# correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed '1,2d' "$tmpdepfile" \
|
||||
| tr ' ' "$nl" \
|
||||
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
|
||||
| sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile" "$tmpdepfile".bak
|
||||
;;
|
||||
|
||||
cpp)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the preprocessed file to stdout.
|
||||
"$@" || exit $?
|
||||
|
||||
# Remove the call to Libtool.
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
|
||||
# Remove '-o $object'.
|
||||
IFS=" "
|
||||
for arg
|
||||
do
|
||||
case $arg in
|
||||
-o)
|
||||
shift
|
||||
;;
|
||||
$object)
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"
|
||||
shift # fnord
|
||||
shift # $arg
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
"$@" -E \
|
||||
| sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
|
||||
-e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
|
||||
| sed '$ s: \\$::' > "$tmpdepfile"
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
cat < "$tmpdepfile" >> "$depfile"
|
||||
sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvisualcpp)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the preprocessed file to stdout.
|
||||
"$@" || exit $?
|
||||
|
||||
# Remove the call to Libtool.
|
||||
if test "$libtool" = yes; then
|
||||
while test "X$1" != 'X--mode=compile'; do
|
||||
shift
|
||||
done
|
||||
shift
|
||||
fi
|
||||
|
||||
IFS=" "
|
||||
for arg
|
||||
do
|
||||
case "$arg" in
|
||||
-o)
|
||||
shift
|
||||
;;
|
||||
$object)
|
||||
shift
|
||||
;;
|
||||
"-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
|
||||
set fnord "$@"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
"$@" -E 2>/dev/null |
|
||||
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
|
||||
echo "$tab" >> "$depfile"
|
||||
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvcmsys)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
none)
|
||||
exec "$@"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Unknown depmode $depmode" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
|
||||
# Local Variables:
|
||||
# mode: shell-script
|
||||
# sh-indentation: 2
|
||||
# eval: (add-hook 'before-save-hook 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC0"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
518
TMessagesProj/jni/libtgvoip2/install-sh
Normal file
518
TMessagesProj/jni/libtgvoip2/install-sh
Normal file
|
@ -0,0 +1,518 @@
|
|||
#!/bin/sh
|
||||
# install - install a program, script, or datafile
|
||||
|
||||
scriptversion=2018-03-11.20; # UTC
|
||||
|
||||
# This originates from X11R5 (mit/util/scripts/install.sh), which was
|
||||
# later released in X11R6 (xc/config/util/install.sh) with the
|
||||
# following copyright and license.
|
||||
#
|
||||
# Copyright (C) 1994 X Consortium
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
|
||||
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
# Except as contained in this notice, the name of the X Consortium shall not
|
||||
# be used in advertising or otherwise to promote the sale, use or other deal-
|
||||
# ings in this Software without prior written authorization from the X Consor-
|
||||
# tium.
|
||||
#
|
||||
#
|
||||
# FSF changes to this file are in the public domain.
|
||||
#
|
||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||
# 'make' implicit rules from creating a file called install from it
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch.
|
||||
|
||||
tab=' '
|
||||
nl='
|
||||
'
|
||||
IFS=" $tab$nl"
|
||||
|
||||
# Set DOITPROG to "echo" to test this script.
|
||||
|
||||
doit=${DOITPROG-}
|
||||
doit_exec=${doit:-exec}
|
||||
|
||||
# Put in absolute file names if you don't have them in your path;
|
||||
# or use environment vars.
|
||||
|
||||
chgrpprog=${CHGRPPROG-chgrp}
|
||||
chmodprog=${CHMODPROG-chmod}
|
||||
chownprog=${CHOWNPROG-chown}
|
||||
cmpprog=${CMPPROG-cmp}
|
||||
cpprog=${CPPROG-cp}
|
||||
mkdirprog=${MKDIRPROG-mkdir}
|
||||
mvprog=${MVPROG-mv}
|
||||
rmprog=${RMPROG-rm}
|
||||
stripprog=${STRIPPROG-strip}
|
||||
|
||||
posix_mkdir=
|
||||
|
||||
# Desired mode of installed file.
|
||||
mode=0755
|
||||
|
||||
chgrpcmd=
|
||||
chmodcmd=$chmodprog
|
||||
chowncmd=
|
||||
mvcmd=$mvprog
|
||||
rmcmd="$rmprog -f"
|
||||
stripcmd=
|
||||
|
||||
src=
|
||||
dst=
|
||||
dir_arg=
|
||||
dst_arg=
|
||||
|
||||
copy_on_change=false
|
||||
is_target_a_directory=possibly
|
||||
|
||||
usage="\
|
||||
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
|
||||
or: $0 [OPTION]... SRCFILES... DIRECTORY
|
||||
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
|
||||
or: $0 [OPTION]... -d DIRECTORIES...
|
||||
|
||||
In the 1st form, copy SRCFILE to DSTFILE.
|
||||
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
|
||||
In the 4th, create DIRECTORIES.
|
||||
|
||||
Options:
|
||||
--help display this help and exit.
|
||||
--version display version info and exit.
|
||||
|
||||
-c (ignored)
|
||||
-C install only if different (preserve the last data modification time)
|
||||
-d create directories instead of installing files.
|
||||
-g GROUP $chgrpprog installed files to GROUP.
|
||||
-m MODE $chmodprog installed files to MODE.
|
||||
-o USER $chownprog installed files to USER.
|
||||
-s $stripprog installed files.
|
||||
-t DIRECTORY install into DIRECTORY.
|
||||
-T report an error if DSTFILE is a directory.
|
||||
|
||||
Environment variables override the default commands:
|
||||
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
|
||||
RMPROG STRIPPROG
|
||||
"
|
||||
|
||||
while test $# -ne 0; do
|
||||
case $1 in
|
||||
-c) ;;
|
||||
|
||||
-C) copy_on_change=true;;
|
||||
|
||||
-d) dir_arg=true;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift;;
|
||||
|
||||
--help) echo "$usage"; exit $?;;
|
||||
|
||||
-m) mode=$2
|
||||
case $mode in
|
||||
*' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
|
||||
echo "$0: invalid mode: $mode" >&2
|
||||
exit 1;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift;;
|
||||
|
||||
-s) stripcmd=$stripprog;;
|
||||
|
||||
-t)
|
||||
is_target_a_directory=always
|
||||
dst_arg=$2
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
shift;;
|
||||
|
||||
-T) is_target_a_directory=never;;
|
||||
|
||||
--version) echo "$0 $scriptversion"; exit $?;;
|
||||
|
||||
--) shift
|
||||
break;;
|
||||
|
||||
-*) echo "$0: invalid option: $1" >&2
|
||||
exit 1;;
|
||||
|
||||
*) break;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# We allow the use of options -d and -T together, by making -d
|
||||
# take the precedence; this is for compatibility with GNU install.
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
if test -n "$dst_arg"; then
|
||||
echo "$0: target directory not allowed when installing a directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
|
||||
# When -d is used, all remaining arguments are directories to create.
|
||||
# When -t is used, the destination is already specified.
|
||||
# Otherwise, the last argument is the destination. Remove it from $@.
|
||||
for arg
|
||||
do
|
||||
if test -n "$dst_arg"; then
|
||||
# $@ is not empty: it contains at least $arg.
|
||||
set fnord "$@" "$dst_arg"
|
||||
shift # fnord
|
||||
fi
|
||||
shift # arg
|
||||
dst_arg=$arg
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $dst_arg in
|
||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
if test $# -eq 0; then
|
||||
if test -z "$dir_arg"; then
|
||||
echo "$0: no input file specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
# It's OK to call 'install-sh -d' without argument.
|
||||
# This can happen when creating conditional directories.
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
if test $# -gt 1 || test "$is_target_a_directory" = always; then
|
||||
if test ! -d "$dst_arg"; then
|
||||
echo "$0: $dst_arg: Is not a directory." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -z "$dir_arg"; then
|
||||
do_exit='(exit $ret); exit $ret'
|
||||
trap "ret=129; $do_exit" 1
|
||||
trap "ret=130; $do_exit" 2
|
||||
trap "ret=141; $do_exit" 13
|
||||
trap "ret=143; $do_exit" 15
|
||||
|
||||
# Set umask so as not to create temps with too-generous modes.
|
||||
# However, 'strip' requires both read and write access to temps.
|
||||
case $mode in
|
||||
# Optimize common cases.
|
||||
*644) cp_umask=133;;
|
||||
*755) cp_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw='% 200'
|
||||
fi
|
||||
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
|
||||
*)
|
||||
if test -z "$stripcmd"; then
|
||||
u_plus_rw=
|
||||
else
|
||||
u_plus_rw=,u+rw
|
||||
fi
|
||||
cp_umask=$mode$u_plus_rw;;
|
||||
esac
|
||||
fi
|
||||
|
||||
for src
|
||||
do
|
||||
# Protect names problematic for 'test' and other utilities.
|
||||
case $src in
|
||||
-* | [=\(\)!]) src=./$src;;
|
||||
esac
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
dst=$src
|
||||
dstdir=$dst
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
if test ! -f "$src" && test ! -d "$src"; then
|
||||
echo "$0: $src does not exist." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if test -z "$dst_arg"; then
|
||||
echo "$0: no destination specified." >&2
|
||||
exit 1
|
||||
fi
|
||||
dst=$dst_arg
|
||||
|
||||
# If destination is a directory, append the input filename.
|
||||
if test -d "$dst"; then
|
||||
if test "$is_target_a_directory" = never; then
|
||||
echo "$0: $dst_arg: Is a directory" >&2
|
||||
exit 1
|
||||
fi
|
||||
dstdir=$dst
|
||||
dstbase=`basename "$src"`
|
||||
case $dst in
|
||||
*/) dst=$dst$dstbase;;
|
||||
*) dst=$dst/$dstbase;;
|
||||
esac
|
||||
dstdir_status=0
|
||||
else
|
||||
dstdir=`dirname "$dst"`
|
||||
test -d "$dstdir"
|
||||
dstdir_status=$?
|
||||
fi
|
||||
fi
|
||||
|
||||
case $dstdir in
|
||||
*/) dstdirslash=$dstdir;;
|
||||
*) dstdirslash=$dstdir/;;
|
||||
esac
|
||||
|
||||
obsolete_mkdir_used=false
|
||||
|
||||
if test $dstdir_status != 0; then
|
||||
case $posix_mkdir in
|
||||
'')
|
||||
# Create intermediate dirs using mode 755 as modified by the umask.
|
||||
# This is like FreeBSD 'install' as of 1997-10-28.
|
||||
umask=`umask`
|
||||
case $stripcmd.$umask in
|
||||
# Optimize common cases.
|
||||
*[2367][2367]) mkdir_umask=$umask;;
|
||||
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
|
||||
|
||||
*[0-7])
|
||||
mkdir_umask=`expr $umask + 22 \
|
||||
- $umask % 100 % 40 + $umask % 20 \
|
||||
- $umask % 10 % 4 + $umask % 2
|
||||
`;;
|
||||
*) mkdir_umask=$umask,go-w;;
|
||||
esac
|
||||
|
||||
# With -d, create the new directory with the user-specified mode.
|
||||
# Otherwise, rely on $mkdir_umask.
|
||||
if test -n "$dir_arg"; then
|
||||
mkdir_mode=-m$mode
|
||||
else
|
||||
mkdir_mode=
|
||||
fi
|
||||
|
||||
posix_mkdir=false
|
||||
case $umask in
|
||||
*[123567][0-7][0-7])
|
||||
# POSIX mkdir -p sets u+wx bits regardless of umask, which
|
||||
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
|
||||
;;
|
||||
*)
|
||||
# Note that $RANDOM variable is not portable (e.g. dash); Use it
|
||||
# here however when possible just to lower collision chance.
|
||||
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
|
||||
|
||||
trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0
|
||||
|
||||
# Because "mkdir -p" follows existing symlinks and we likely work
|
||||
# directly in world-writeable /tmp, make sure that the '$tmpdir'
|
||||
# directory is successfully created first before we actually test
|
||||
# 'mkdir -p' feature.
|
||||
if (umask $mkdir_umask &&
|
||||
$mkdirprog $mkdir_mode "$tmpdir" &&
|
||||
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
|
||||
then
|
||||
if test -z "$dir_arg" || {
|
||||
# Check for POSIX incompatibilities with -m.
|
||||
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
|
||||
# other-writable bit of parent directory when it shouldn't.
|
||||
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
|
||||
test_tmpdir="$tmpdir/a"
|
||||
ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
|
||||
case $ls_ld_tmpdir in
|
||||
d????-?r-*) different_mode=700;;
|
||||
d????-?--*) different_mode=755;;
|
||||
*) false;;
|
||||
esac &&
|
||||
$mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
|
||||
ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
|
||||
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
|
||||
}
|
||||
}
|
||||
then posix_mkdir=:
|
||||
fi
|
||||
rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
|
||||
else
|
||||
# Remove any dirs left behind by ancient mkdir implementations.
|
||||
rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
|
||||
fi
|
||||
trap '' 0;;
|
||||
esac;;
|
||||
esac
|
||||
|
||||
if
|
||||
$posix_mkdir && (
|
||||
umask $mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
|
||||
)
|
||||
then :
|
||||
else
|
||||
|
||||
# The umask is ridiculous, or mkdir does not conform to POSIX,
|
||||
# or it failed possibly due to a race condition. Create the
|
||||
# directory the slow way, step by step, checking for races as we go.
|
||||
|
||||
case $dstdir in
|
||||
/*) prefix='/';;
|
||||
[-=\(\)!]*) prefix='./';;
|
||||
*) prefix='';;
|
||||
esac
|
||||
|
||||
oIFS=$IFS
|
||||
IFS=/
|
||||
set -f
|
||||
set fnord $dstdir
|
||||
shift
|
||||
set +f
|
||||
IFS=$oIFS
|
||||
|
||||
prefixes=
|
||||
|
||||
for d
|
||||
do
|
||||
test X"$d" = X && continue
|
||||
|
||||
prefix=$prefix$d
|
||||
if test -d "$prefix"; then
|
||||
prefixes=
|
||||
else
|
||||
if $posix_mkdir; then
|
||||
(umask=$mkdir_umask &&
|
||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
|
||||
# Don't fail if two instances are running concurrently.
|
||||
test -d "$prefix" || exit 1
|
||||
else
|
||||
case $prefix in
|
||||
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
|
||||
*) qprefix=$prefix;;
|
||||
esac
|
||||
prefixes="$prefixes '$qprefix'"
|
||||
fi
|
||||
fi
|
||||
prefix=$prefix/
|
||||
done
|
||||
|
||||
if test -n "$prefixes"; then
|
||||
# Don't fail if two instances are running concurrently.
|
||||
(umask $mkdir_umask &&
|
||||
eval "\$doit_exec \$mkdirprog $prefixes") ||
|
||||
test -d "$dstdir" || exit 1
|
||||
obsolete_mkdir_used=true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if test -n "$dir_arg"; then
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
|
||||
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
|
||||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
|
||||
else
|
||||
|
||||
# Make a couple of temp file names in the proper directory.
|
||||
dsttmp=${dstdirslash}_inst.$$_
|
||||
rmtmp=${dstdirslash}_rm.$$_
|
||||
|
||||
# Trap to clean up those temp files at exit.
|
||||
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
|
||||
|
||||
# Copy the file name to the temp name.
|
||||
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits.
|
||||
#
|
||||
# If any of these fail, we abort the whole thing. If we want to
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $cpprog $src $dsttmp" command.
|
||||
#
|
||||
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
|
||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
|
||||
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
|
||||
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
|
||||
|
||||
# If -C, don't bother to copy if it wouldn't change the file.
|
||||
if $copy_on_change &&
|
||||
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
|
||||
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
|
||||
set -f &&
|
||||
set X $old && old=:$2:$4:$5:$6 &&
|
||||
set X $new && new=:$2:$4:$5:$6 &&
|
||||
set +f &&
|
||||
test "$old" = "$new" &&
|
||||
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
|
||||
then
|
||||
rm -f "$dsttmp"
|
||||
else
|
||||
# Rename the file to the real destination.
|
||||
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
|
||||
|
||||
# The rename failed, perhaps because mv can't rename something else
|
||||
# to itself, or perhaps because mv is so ancient that it does not
|
||||
# support -f.
|
||||
{
|
||||
# Now remove or move aside any old file at destination location.
|
||||
# We try this two ways since rm can't unlink itself on some
|
||||
# systems and the destination file might be busy for other
|
||||
# reasons. In this case, the final cleanup might fail but the new
|
||||
# file should still install successfully.
|
||||
{
|
||||
test ! -f "$dst" ||
|
||||
$doit $rmcmd -f "$dst" 2>/dev/null ||
|
||||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
|
||||
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
|
||||
} ||
|
||||
{ echo "$0: cannot unlink or rename $dst" >&2
|
||||
(exit 1); exit 1
|
||||
}
|
||||
} &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
$doit $mvcmd "$dsttmp" "$dst"
|
||||
}
|
||||
fi || exit 1
|
||||
|
||||
trap '' 0
|
||||
fi
|
||||
done
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'before-save-hook 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC0"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
795
TMessagesProj/jni/libtgvoip2/json11.cpp
Normal file
795
TMessagesProj/jni/libtgvoip2/json11.cpp
Normal file
|
@ -0,0 +1,795 @@
|
|||
/* Copyright (c) 2013 Dropbox, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "json11.hpp"
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <locale>
|
||||
|
||||
namespace json11 {
|
||||
|
||||
static const int max_depth = 200;
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::map;
|
||||
using std::make_shared;
|
||||
using std::initializer_list;
|
||||
using std::move;
|
||||
|
||||
/* Helper for representing null - just a do-nothing struct, plus comparison
|
||||
* operators so the helpers in JsonValue work. We can't use nullptr_t because
|
||||
* it may not be orderable.
|
||||
*/
|
||||
struct NullStruct {
|
||||
bool operator==(NullStruct) const { return true; }
|
||||
bool operator<(NullStruct) const { return false; }
|
||||
};
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * *
|
||||
* Serialization
|
||||
*/
|
||||
|
||||
static void dump(NullStruct, string &out) {
|
||||
out += "null";
|
||||
}
|
||||
|
||||
static void dump(double value, string &out) {
|
||||
if (std::isfinite(value)) {
|
||||
std::ostringstream stm;
|
||||
stm.imbue(std::locale("C"));
|
||||
stm << value;
|
||||
out += stm.str();
|
||||
} else {
|
||||
out += "null";
|
||||
}
|
||||
}
|
||||
|
||||
static void dump(int value, string &out) {
|
||||
char buf[32];
|
||||
snprintf(buf, sizeof buf, "%d", value);
|
||||
out += buf;
|
||||
}
|
||||
|
||||
static void dump(bool value, string &out) {
|
||||
out += value ? "true" : "false";
|
||||
}
|
||||
|
||||
static void dump(const string &value, string &out) {
|
||||
out += '"';
|
||||
for (size_t i = 0; i < value.length(); i++) {
|
||||
const char ch = value[i];
|
||||
if (ch == '\\') {
|
||||
out += "\\\\";
|
||||
} else if (ch == '"') {
|
||||
out += "\\\"";
|
||||
} else if (ch == '\b') {
|
||||
out += "\\b";
|
||||
} else if (ch == '\f') {
|
||||
out += "\\f";
|
||||
} else if (ch == '\n') {
|
||||
out += "\\n";
|
||||
} else if (ch == '\r') {
|
||||
out += "\\r";
|
||||
} else if (ch == '\t') {
|
||||
out += "\\t";
|
||||
} else if (static_cast<uint8_t>(ch) <= 0x1f) {
|
||||
char buf[8];
|
||||
snprintf(buf, sizeof buf, "\\u%04x", ch);
|
||||
out += buf;
|
||||
} else if (static_cast<uint8_t>(ch) == 0xe2 && static_cast<uint8_t>(value[i+1]) == 0x80
|
||||
&& static_cast<uint8_t>(value[i+2]) == 0xa8) {
|
||||
out += "\\u2028";
|
||||
i += 2;
|
||||
} else if (static_cast<uint8_t>(ch) == 0xe2 && static_cast<uint8_t>(value[i+1]) == 0x80
|
||||
&& static_cast<uint8_t>(value[i+2]) == 0xa9) {
|
||||
out += "\\u2029";
|
||||
i += 2;
|
||||
} else {
|
||||
out += ch;
|
||||
}
|
||||
}
|
||||
out += '"';
|
||||
}
|
||||
|
||||
static void dump(const Json::array &values, string &out) {
|
||||
bool first = true;
|
||||
out += "[";
|
||||
for (const auto &value : values) {
|
||||
if (!first)
|
||||
out += ", ";
|
||||
value.dump(out);
|
||||
first = false;
|
||||
}
|
||||
out += "]";
|
||||
}
|
||||
|
||||
static void dump(const Json::object &values, string &out) {
|
||||
bool first = true;
|
||||
out += "{";
|
||||
for (const auto &kv : values) {
|
||||
if (!first)
|
||||
out += ", ";
|
||||
dump(kv.first, out);
|
||||
out += ": ";
|
||||
kv.second.dump(out);
|
||||
first = false;
|
||||
}
|
||||
out += "}";
|
||||
}
|
||||
|
||||
void Json::dump(string &out) const {
|
||||
m_ptr->dump(out);
|
||||
}
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * *
|
||||
* Value wrappers
|
||||
*/
|
||||
|
||||
template <Json::Type tag, typename T>
|
||||
class Value : public JsonValue {
|
||||
protected:
|
||||
|
||||
// Constructors
|
||||
explicit Value(const T &value) : m_value(value) {}
|
||||
explicit Value(T &&value) : m_value(move(value)) {}
|
||||
|
||||
// Get type tag
|
||||
Json::Type type() const override {
|
||||
return tag;
|
||||
}
|
||||
|
||||
// Comparisons
|
||||
bool equals(const JsonValue * other) const override {
|
||||
return m_value == static_cast<const Value<tag, T> *>(other)->m_value;
|
||||
}
|
||||
bool less(const JsonValue * other) const override {
|
||||
return m_value < static_cast<const Value<tag, T> *>(other)->m_value;
|
||||
}
|
||||
|
||||
const T m_value;
|
||||
void dump(string &out) const override { json11::dump(m_value, out); }
|
||||
};
|
||||
|
||||
class JsonDouble final : public Value<Json::NUMBER, double> {
|
||||
double number_value() const override { return m_value; }
|
||||
int int_value() const override { return static_cast<int>(m_value); }
|
||||
bool equals(const JsonValue * other) const override { return m_value == other->number_value(); }
|
||||
bool less(const JsonValue * other) const override { return m_value < other->number_value(); }
|
||||
public:
|
||||
explicit JsonDouble(double value) : Value(value) {}
|
||||
};
|
||||
|
||||
class JsonInt final : public Value<Json::NUMBER, int> {
|
||||
double number_value() const override { return m_value; }
|
||||
int int_value() const override { return m_value; }
|
||||
bool equals(const JsonValue * other) const override { return m_value == other->number_value(); }
|
||||
bool less(const JsonValue * other) const override { return m_value < other->number_value(); }
|
||||
public:
|
||||
explicit JsonInt(int value) : Value(value) {}
|
||||
};
|
||||
|
||||
class JsonBoolean final : public Value<Json::BOOL, bool> {
|
||||
bool bool_value() const override { return m_value; }
|
||||
public:
|
||||
explicit JsonBoolean(bool value) : Value(value) {}
|
||||
};
|
||||
|
||||
class JsonString final : public Value<Json::STRING, string> {
|
||||
const string &string_value() const override { return m_value; }
|
||||
public:
|
||||
explicit JsonString(const string &value) : Value(value) {}
|
||||
explicit JsonString(string &&value) : Value(move(value)) {}
|
||||
};
|
||||
|
||||
class JsonArray final : public Value<Json::ARRAY, Json::array> {
|
||||
const Json::array &array_items() const override { return m_value; }
|
||||
const Json & operator[](size_t i) const override;
|
||||
public:
|
||||
explicit JsonArray(const Json::array &value) : Value(value) {}
|
||||
explicit JsonArray(Json::array &&value) : Value(move(value)) {}
|
||||
};
|
||||
|
||||
class JsonObject final : public Value<Json::OBJECT, Json::object> {
|
||||
const Json::object &object_items() const override { return m_value; }
|
||||
const Json & operator[](const string &key) const override;
|
||||
public:
|
||||
explicit JsonObject(const Json::object &value) : Value(value) {}
|
||||
explicit JsonObject(Json::object &&value) : Value(move(value)) {}
|
||||
};
|
||||
|
||||
class JsonNull final : public Value<Json::NUL, NullStruct> {
|
||||
public:
|
||||
JsonNull() : Value({}) {}
|
||||
};
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * *
|
||||
* Static globals - static-init-safe
|
||||
*/
|
||||
struct Statics {
|
||||
const std::shared_ptr<JsonValue> null = make_shared<JsonNull>();
|
||||
const std::shared_ptr<JsonValue> t = make_shared<JsonBoolean>(true);
|
||||
const std::shared_ptr<JsonValue> f = make_shared<JsonBoolean>(false);
|
||||
const string empty_string;
|
||||
const vector<Json> empty_vector;
|
||||
const map<string, Json> empty_map;
|
||||
Statics() {}
|
||||
};
|
||||
|
||||
static const Statics & statics() {
|
||||
static const Statics s {};
|
||||
return s;
|
||||
}
|
||||
|
||||
static const Json & static_null() {
|
||||
// This has to be separate, not in Statics, because Json() accesses statics().null.
|
||||
static const Json json_null;
|
||||
return json_null;
|
||||
}
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * *
|
||||
* Constructors
|
||||
*/
|
||||
|
||||
Json::Json() noexcept : m_ptr(statics().null) {}
|
||||
Json::Json(std::nullptr_t) noexcept : m_ptr(statics().null) {}
|
||||
Json::Json(double value) : m_ptr(make_shared<JsonDouble>(value)) {}
|
||||
Json::Json(int value) : m_ptr(make_shared<JsonInt>(value)) {}
|
||||
Json::Json(bool value) : m_ptr(value ? statics().t : statics().f) {}
|
||||
Json::Json(const string &value) : m_ptr(make_shared<JsonString>(value)) {}
|
||||
Json::Json(string &&value) : m_ptr(make_shared<JsonString>(move(value))) {}
|
||||
Json::Json(const char * value) : m_ptr(make_shared<JsonString>(value)) {}
|
||||
Json::Json(const Json::array &values) : m_ptr(make_shared<JsonArray>(values)) {}
|
||||
Json::Json(Json::array &&values) : m_ptr(make_shared<JsonArray>(move(values))) {}
|
||||
Json::Json(const Json::object &values) : m_ptr(make_shared<JsonObject>(values)) {}
|
||||
Json::Json(Json::object &&values) : m_ptr(make_shared<JsonObject>(move(values))) {}
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * *
|
||||
* Accessors
|
||||
*/
|
||||
|
||||
Json::Type Json::type() const { return m_ptr->type(); }
|
||||
double Json::number_value() const { return m_ptr->number_value(); }
|
||||
int Json::int_value() const { return m_ptr->int_value(); }
|
||||
bool Json::bool_value() const { return m_ptr->bool_value(); }
|
||||
const string & Json::string_value() const { return m_ptr->string_value(); }
|
||||
const vector<Json> & Json::array_items() const { return m_ptr->array_items(); }
|
||||
const map<string, Json> & Json::object_items() const { return m_ptr->object_items(); }
|
||||
const Json & Json::operator[] (size_t i) const { return (*m_ptr)[i]; }
|
||||
const Json & Json::operator[] (const string &key) const { return (*m_ptr)[key]; }
|
||||
|
||||
double JsonValue::number_value() const { return 0; }
|
||||
int JsonValue::int_value() const { return 0; }
|
||||
bool JsonValue::bool_value() const { return false; }
|
||||
const string & JsonValue::string_value() const { return statics().empty_string; }
|
||||
const vector<Json> & JsonValue::array_items() const { return statics().empty_vector; }
|
||||
const map<string, Json> & JsonValue::object_items() const { return statics().empty_map; }
|
||||
const Json & JsonValue::operator[] (size_t) const { return static_null(); }
|
||||
const Json & JsonValue::operator[] (const string &) const { return static_null(); }
|
||||
|
||||
const Json & JsonObject::operator[] (const string &key) const {
|
||||
auto iter = m_value.find(key);
|
||||
return (iter == m_value.end()) ? static_null() : iter->second;
|
||||
}
|
||||
const Json & JsonArray::operator[] (size_t i) const {
|
||||
if (i >= m_value.size()) return static_null();
|
||||
else return m_value[i];
|
||||
}
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * *
|
||||
* Comparison
|
||||
*/
|
||||
|
||||
bool Json::operator== (const Json &other) const {
|
||||
if (m_ptr == other.m_ptr)
|
||||
return true;
|
||||
if (m_ptr->type() != other.m_ptr->type())
|
||||
return false;
|
||||
|
||||
return m_ptr->equals(other.m_ptr.get());
|
||||
}
|
||||
|
||||
bool Json::operator< (const Json &other) const {
|
||||
if (m_ptr == other.m_ptr)
|
||||
return false;
|
||||
if (m_ptr->type() != other.m_ptr->type())
|
||||
return m_ptr->type() < other.m_ptr->type();
|
||||
|
||||
return m_ptr->less(other.m_ptr.get());
|
||||
}
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * *
|
||||
* Parsing
|
||||
*/
|
||||
|
||||
/* esc(c)
|
||||
*
|
||||
* Format char c suitable for printing in an error message.
|
||||
*/
|
||||
static inline string esc(char c) {
|
||||
char buf[12];
|
||||
if (static_cast<uint8_t>(c) >= 0x20 && static_cast<uint8_t>(c) <= 0x7f) {
|
||||
snprintf(buf, sizeof buf, "'%c' (%d)", c, c);
|
||||
} else {
|
||||
snprintf(buf, sizeof buf, "(%d)", c);
|
||||
}
|
||||
return string(buf);
|
||||
}
|
||||
|
||||
static inline bool in_range(long x, long lower, long upper) {
|
||||
return (x >= lower && x <= upper);
|
||||
}
|
||||
|
||||
namespace {
|
||||
/* JsonParser
|
||||
*
|
||||
* Object that tracks all state of an in-progress parse.
|
||||
*/
|
||||
struct JsonParser final {
|
||||
|
||||
/* State
|
||||
*/
|
||||
const string &str;
|
||||
size_t i;
|
||||
string &err;
|
||||
bool failed;
|
||||
const JsonParse strategy;
|
||||
|
||||
/* fail(msg, err_ret = Json())
|
||||
*
|
||||
* Mark this parse as failed.
|
||||
*/
|
||||
Json fail(string &&msg) {
|
||||
return fail(move(msg), Json());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T fail(string &&msg, const T err_ret) {
|
||||
if (!failed)
|
||||
err = std::move(msg);
|
||||
failed = true;
|
||||
return err_ret;
|
||||
}
|
||||
|
||||
/* consume_whitespace()
|
||||
*
|
||||
* Advance until the current character is non-whitespace.
|
||||
*/
|
||||
void consume_whitespace() {
|
||||
while (str[i] == ' ' || str[i] == '\r' || str[i] == '\n' || str[i] == '\t')
|
||||
i++;
|
||||
}
|
||||
|
||||
/* consume_comment()
|
||||
*
|
||||
* Advance comments (c-style inline and multiline).
|
||||
*/
|
||||
bool consume_comment() {
|
||||
bool comment_found = false;
|
||||
if (str[i] == '/') {
|
||||
i++;
|
||||
if (i == str.size())
|
||||
return fail("unexpected end of input after start of comment", false);
|
||||
if (str[i] == '/') { // inline comment
|
||||
i++;
|
||||
// advance until next line, or end of input
|
||||
while (i < str.size() && str[i] != '\n') {
|
||||
i++;
|
||||
}
|
||||
comment_found = true;
|
||||
}
|
||||
else if (str[i] == '*') { // multiline comment
|
||||
i++;
|
||||
if (i > str.size()-2)
|
||||
return fail("unexpected end of input inside multi-line comment", false);
|
||||
// advance until closing tokens
|
||||
while (!(str[i] == '*' && str[i+1] == '/')) {
|
||||
i++;
|
||||
if (i > str.size()-2)
|
||||
return fail(
|
||||
"unexpected end of input inside multi-line comment", false);
|
||||
}
|
||||
i += 2;
|
||||
comment_found = true;
|
||||
}
|
||||
else
|
||||
return fail("malformed comment", false);
|
||||
}
|
||||
return comment_found;
|
||||
}
|
||||
|
||||
/* consume_garbage()
|
||||
*
|
||||
* Advance until the current character is non-whitespace and non-comment.
|
||||
*/
|
||||
void consume_garbage() {
|
||||
consume_whitespace();
|
||||
if(strategy == JsonParse::COMMENTS) {
|
||||
bool comment_found = false;
|
||||
do {
|
||||
comment_found = consume_comment();
|
||||
if (failed) return;
|
||||
consume_whitespace();
|
||||
}
|
||||
while(comment_found);
|
||||
}
|
||||
}
|
||||
|
||||
/* get_next_token()
|
||||
*
|
||||
* Return the next non-whitespace character. If the end of the input is reached,
|
||||
* flag an error and return 0.
|
||||
*/
|
||||
char get_next_token() {
|
||||
consume_garbage();
|
||||
if (failed) return (char)0;
|
||||
if (i == str.size())
|
||||
return fail("unexpected end of input", (char)0);
|
||||
|
||||
return str[i++];
|
||||
}
|
||||
|
||||
/* encode_utf8(pt, out)
|
||||
*
|
||||
* Encode pt as UTF-8 and add it to out.
|
||||
*/
|
||||
void encode_utf8(long pt, string & out) {
|
||||
if (pt < 0)
|
||||
return;
|
||||
|
||||
if (pt < 0x80) {
|
||||
out += static_cast<char>(pt);
|
||||
} else if (pt < 0x800) {
|
||||
out += static_cast<char>((pt >> 6) | 0xC0);
|
||||
out += static_cast<char>((pt & 0x3F) | 0x80);
|
||||
} else if (pt < 0x10000) {
|
||||
out += static_cast<char>((pt >> 12) | 0xE0);
|
||||
out += static_cast<char>(((pt >> 6) & 0x3F) | 0x80);
|
||||
out += static_cast<char>((pt & 0x3F) | 0x80);
|
||||
} else {
|
||||
out += static_cast<char>((pt >> 18) | 0xF0);
|
||||
out += static_cast<char>(((pt >> 12) & 0x3F) | 0x80);
|
||||
out += static_cast<char>(((pt >> 6) & 0x3F) | 0x80);
|
||||
out += static_cast<char>((pt & 0x3F) | 0x80);
|
||||
}
|
||||
}
|
||||
|
||||
/* parse_string()
|
||||
*
|
||||
* Parse a string, starting at the current position.
|
||||
*/
|
||||
string parse_string() {
|
||||
string out;
|
||||
long last_escaped_codepoint = -1;
|
||||
while (true) {
|
||||
if (i == str.size())
|
||||
return fail("unexpected end of input in string", "");
|
||||
|
||||
char ch = str[i++];
|
||||
|
||||
if (ch == '"') {
|
||||
encode_utf8(last_escaped_codepoint, out);
|
||||
return out;
|
||||
}
|
||||
|
||||
if (in_range(ch, 0, 0x1f))
|
||||
return fail("unescaped " + esc(ch) + " in string", "");
|
||||
|
||||
// The usual case: non-escaped characters
|
||||
if (ch != '\\') {
|
||||
encode_utf8(last_escaped_codepoint, out);
|
||||
last_escaped_codepoint = -1;
|
||||
out += ch;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle escapes
|
||||
if (i == str.size())
|
||||
return fail("unexpected end of input in string", "");
|
||||
|
||||
ch = str[i++];
|
||||
|
||||
if (ch == 'u') {
|
||||
// Extract 4-byte escape sequence
|
||||
string esc = str.substr(i, 4);
|
||||
// Explicitly check length of the substring. The following loop
|
||||
// relies on std::string returning the terminating NUL when
|
||||
// accessing str[length]. Checking here reduces brittleness.
|
||||
if (esc.length() < 4) {
|
||||
return fail("bad \\u escape: " + esc, "");
|
||||
}
|
||||
for (size_t j = 0; j < 4; j++) {
|
||||
if (!in_range(esc[j], 'a', 'f') && !in_range(esc[j], 'A', 'F')
|
||||
&& !in_range(esc[j], '0', '9'))
|
||||
return fail("bad \\u escape: " + esc, "");
|
||||
}
|
||||
|
||||
long codepoint = strtol(esc.data(), nullptr, 16);
|
||||
|
||||
// JSON specifies that characters outside the BMP shall be encoded as a pair
|
||||
// of 4-hex-digit \u escapes encoding their surrogate pair components. Check
|
||||
// whether we're in the middle of such a beast: the previous codepoint was an
|
||||
// escaped lead (high) surrogate, and this is a trail (low) surrogate.
|
||||
if (in_range(last_escaped_codepoint, 0xD800, 0xDBFF)
|
||||
&& in_range(codepoint, 0xDC00, 0xDFFF)) {
|
||||
// Reassemble the two surrogate pairs into one astral-plane character, per
|
||||
// the UTF-16 algorithm.
|
||||
encode_utf8((((last_escaped_codepoint - 0xD800) << 10)
|
||||
| (codepoint - 0xDC00)) + 0x10000, out);
|
||||
last_escaped_codepoint = -1;
|
||||
} else {
|
||||
encode_utf8(last_escaped_codepoint, out);
|
||||
last_escaped_codepoint = codepoint;
|
||||
}
|
||||
|
||||
i += 4;
|
||||
continue;
|
||||
}
|
||||
|
||||
encode_utf8(last_escaped_codepoint, out);
|
||||
last_escaped_codepoint = -1;
|
||||
|
||||
if (ch == 'b') {
|
||||
out += '\b';
|
||||
} else if (ch == 'f') {
|
||||
out += '\f';
|
||||
} else if (ch == 'n') {
|
||||
out += '\n';
|
||||
} else if (ch == 'r') {
|
||||
out += '\r';
|
||||
} else if (ch == 't') {
|
||||
out += '\t';
|
||||
} else if (ch == '"' || ch == '\\' || ch == '/') {
|
||||
out += ch;
|
||||
} else {
|
||||
return fail("invalid escape character " + esc(ch), "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* parse_number()
|
||||
*
|
||||
* Parse a double.
|
||||
*/
|
||||
Json parse_number() {
|
||||
size_t start_pos = i;
|
||||
|
||||
if (str[i] == '-')
|
||||
i++;
|
||||
|
||||
// Integer part
|
||||
if (str[i] == '0') {
|
||||
i++;
|
||||
if (in_range(str[i], '0', '9'))
|
||||
return fail("leading 0s not permitted in numbers");
|
||||
} else if (in_range(str[i], '1', '9')) {
|
||||
i++;
|
||||
while (in_range(str[i], '0', '9'))
|
||||
i++;
|
||||
} else {
|
||||
return fail("invalid " + esc(str[i]) + " in number");
|
||||
}
|
||||
|
||||
if (str[i] != '.' && str[i] != 'e' && str[i] != 'E'
|
||||
&& (i - start_pos) <= static_cast<size_t>(std::numeric_limits<int>::digits10)) {
|
||||
return std::atoi(str.c_str() + start_pos);
|
||||
}
|
||||
|
||||
// Decimal part
|
||||
if (str[i] == '.') {
|
||||
i++;
|
||||
if (!in_range(str[i], '0', '9'))
|
||||
return fail("at least one digit required in fractional part");
|
||||
|
||||
while (in_range(str[i], '0', '9'))
|
||||
i++;
|
||||
}
|
||||
|
||||
// Exponent part
|
||||
if (str[i] == 'e' || str[i] == 'E') {
|
||||
i++;
|
||||
|
||||
if (str[i] == '+' || str[i] == '-')
|
||||
i++;
|
||||
|
||||
if (!in_range(str[i], '0', '9'))
|
||||
return fail("at least one digit required in exponent");
|
||||
|
||||
while (in_range(str[i], '0', '9'))
|
||||
i++;
|
||||
}
|
||||
|
||||
std::istringstream stm(std::string(str.begin()+start_pos, str.end()));
|
||||
stm.imbue(std::locale("C"));
|
||||
double result;
|
||||
stm >> result;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* expect(str, res)
|
||||
*
|
||||
* Expect that 'str' starts at the character that was just read. If it does, advance
|
||||
* the input and return res. If not, flag an error.
|
||||
*/
|
||||
Json expect(const string &expected, Json res) {
|
||||
assert(i != 0);
|
||||
i--;
|
||||
if (str.compare(i, expected.length(), expected) == 0) {
|
||||
i += expected.length();
|
||||
return res;
|
||||
} else {
|
||||
return fail("parse error: expected " + expected + ", got " + str.substr(i, expected.length()));
|
||||
}
|
||||
}
|
||||
|
||||
/* parse_json()
|
||||
*
|
||||
* Parse a JSON object.
|
||||
*/
|
||||
Json parse_json(int depth) {
|
||||
if (depth > max_depth) {
|
||||
return fail("exceeded maximum nesting depth");
|
||||
}
|
||||
|
||||
char ch = get_next_token();
|
||||
if (failed)
|
||||
return Json();
|
||||
|
||||
if (ch == '-' || (ch >= '0' && ch <= '9')) {
|
||||
i--;
|
||||
return parse_number();
|
||||
}
|
||||
|
||||
if (ch == 't')
|
||||
return expect("true", true);
|
||||
|
||||
if (ch == 'f')
|
||||
return expect("false", false);
|
||||
|
||||
if (ch == 'n')
|
||||
return expect("null", Json());
|
||||
|
||||
if (ch == '"')
|
||||
return parse_string();
|
||||
|
||||
if (ch == '{') {
|
||||
map<string, Json> data;
|
||||
ch = get_next_token();
|
||||
if (ch == '}')
|
||||
return data;
|
||||
|
||||
while (1) {
|
||||
if (ch != '"')
|
||||
return fail("expected '\"' in object, got " + esc(ch));
|
||||
|
||||
string key = parse_string();
|
||||
if (failed)
|
||||
return Json();
|
||||
|
||||
ch = get_next_token();
|
||||
if (ch != ':')
|
||||
return fail("expected ':' in object, got " + esc(ch));
|
||||
|
||||
data[std::move(key)] = parse_json(depth + 1);
|
||||
if (failed)
|
||||
return Json();
|
||||
|
||||
ch = get_next_token();
|
||||
if (ch == '}')
|
||||
break;
|
||||
if (ch != ',')
|
||||
return fail("expected ',' in object, got " + esc(ch));
|
||||
|
||||
ch = get_next_token();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
if (ch == '[') {
|
||||
vector<Json> data;
|
||||
ch = get_next_token();
|
||||
if (ch == ']')
|
||||
return data;
|
||||
|
||||
while (1) {
|
||||
i--;
|
||||
data.push_back(parse_json(depth + 1));
|
||||
if (failed)
|
||||
return Json();
|
||||
|
||||
ch = get_next_token();
|
||||
if (ch == ']')
|
||||
break;
|
||||
if (ch != ',')
|
||||
return fail("expected ',' in list, got " + esc(ch));
|
||||
|
||||
ch = get_next_token();
|
||||
(void)ch;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
return fail("expected value, got " + esc(ch));
|
||||
}
|
||||
};
|
||||
}//namespace {
|
||||
|
||||
Json Json::parse(const string &in, string &err, JsonParse strategy) {
|
||||
JsonParser parser { in, 0, err, false, strategy };
|
||||
Json result = parser.parse_json(0);
|
||||
|
||||
// Check for any trailing garbage
|
||||
parser.consume_garbage();
|
||||
if (parser.failed)
|
||||
return Json();
|
||||
if (parser.i != in.size())
|
||||
return parser.fail("unexpected trailing " + esc(in[parser.i]));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Documented in json11.hpp
|
||||
vector<Json> Json::parse_multi(const string &in,
|
||||
std::string::size_type &parser_stop_pos,
|
||||
string &err,
|
||||
JsonParse strategy) {
|
||||
JsonParser parser { in, 0, err, false, strategy };
|
||||
parser_stop_pos = 0;
|
||||
vector<Json> json_vec;
|
||||
while (parser.i != in.size() && !parser.failed) {
|
||||
json_vec.push_back(parser.parse_json(0));
|
||||
if (parser.failed)
|
||||
break;
|
||||
|
||||
// Check for another object
|
||||
parser.consume_garbage();
|
||||
if (parser.failed)
|
||||
break;
|
||||
parser_stop_pos = parser.i;
|
||||
}
|
||||
return json_vec;
|
||||
}
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * *
|
||||
* Shape-checking
|
||||
*/
|
||||
|
||||
bool Json::has_shape(const shape & types, string & err) const {
|
||||
if (!is_object()) {
|
||||
err = "expected JSON object, got " + dump();
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto & item : types) {
|
||||
if ((*this)[item.first].type() != item.second) {
|
||||
err = "bad type for " + item.first + " in " + dump();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace json11
|
232
TMessagesProj/jni/libtgvoip2/json11.hpp
Normal file
232
TMessagesProj/jni/libtgvoip2/json11.hpp
Normal file
|
@ -0,0 +1,232 @@
|
|||
/* json11
|
||||
*
|
||||
* json11 is a tiny JSON library for C++11, providing JSON parsing and serialization.
|
||||
*
|
||||
* The core object provided by the library is json11::Json. A Json object represents any JSON
|
||||
* value: null, bool, number (int or double), string (std::string), array (std::vector), or
|
||||
* object (std::map).
|
||||
*
|
||||
* Json objects act like values: they can be assigned, copied, moved, compared for equality or
|
||||
* order, etc. There are also helper methods Json::dump, to serialize a Json to a string, and
|
||||
* Json::parse (static) to parse a std::string as a Json object.
|
||||
*
|
||||
* Internally, the various types of Json object are represented by the JsonValue class
|
||||
* hierarchy.
|
||||
*
|
||||
* A note on numbers - JSON specifies the syntax of number formatting but not its semantics,
|
||||
* so some JSON implementations distinguish between integers and floating-point numbers, while
|
||||
* some don't. In json11, we choose the latter. Because some JSON implementations (namely
|
||||
* Javascript itself) treat all numbers as the same type, distinguishing the two leads
|
||||
* to JSON that will be *silently* changed by a round-trip through those implementations.
|
||||
* Dangerous! To avoid that risk, json11 stores all numbers as double internally, but also
|
||||
* provides integer helpers.
|
||||
*
|
||||
* Fortunately, double-precision IEEE754 ('double') can precisely store any integer in the
|
||||
* range +/-2^53, which includes every 'int' on most systems. (Timestamps often use int64
|
||||
* or long long to avoid the Y2038K problem; a double storing microseconds since some epoch
|
||||
* will be exact for +/- 275 years.)
|
||||
*/
|
||||
|
||||
/* Copyright (c) 2013 Dropbox, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <initializer_list>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if _MSC_VER <= 1800 // VS 2013
|
||||
#ifndef noexcept
|
||||
#define noexcept throw()
|
||||
#endif
|
||||
|
||||
#ifndef snprintf
|
||||
#define snprintf _snprintf_s
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace json11 {
|
||||
|
||||
enum JsonParse {
|
||||
STANDARD, COMMENTS
|
||||
};
|
||||
|
||||
class JsonValue;
|
||||
|
||||
class Json final {
|
||||
public:
|
||||
// Types
|
||||
enum Type {
|
||||
NUL, NUMBER, BOOL, STRING, ARRAY, OBJECT
|
||||
};
|
||||
|
||||
// Array and object typedefs
|
||||
typedef std::vector<Json> array;
|
||||
typedef std::map<std::string, Json> object;
|
||||
|
||||
// Constructors for the various types of JSON value.
|
||||
Json() noexcept; // NUL
|
||||
Json(std::nullptr_t) noexcept; // NUL
|
||||
Json(double value); // NUMBER
|
||||
Json(int value); // NUMBER
|
||||
Json(bool value); // BOOL
|
||||
Json(const std::string &value); // STRING
|
||||
Json(std::string &&value); // STRING
|
||||
Json(const char * value); // STRING
|
||||
Json(const array &values); // ARRAY
|
||||
Json(array &&values); // ARRAY
|
||||
Json(const object &values); // OBJECT
|
||||
Json(object &&values); // OBJECT
|
||||
|
||||
// Implicit constructor: anything with a to_json() function.
|
||||
template <class T, class = decltype(&T::to_json)>
|
||||
Json(const T & t) : Json(t.to_json()) {}
|
||||
|
||||
// Implicit constructor: map-like objects (std::map, std::unordered_map, etc)
|
||||
template <class M, typename std::enable_if<
|
||||
std::is_constructible<std::string, decltype(std::declval<M>().begin()->first)>::value
|
||||
&& std::is_constructible<Json, decltype(std::declval<M>().begin()->second)>::value,
|
||||
int>::type = 0>
|
||||
Json(const M & m) : Json(object(m.begin(), m.end())) {}
|
||||
|
||||
// Implicit constructor: vector-like objects (std::list, std::vector, std::set, etc)
|
||||
template <class V, typename std::enable_if<
|
||||
std::is_constructible<Json, decltype(*std::declval<V>().begin())>::value,
|
||||
int>::type = 0>
|
||||
Json(const V & v) : Json(array(v.begin(), v.end())) {}
|
||||
|
||||
// This prevents Json(some_pointer) from accidentally producing a bool. Use
|
||||
// Json(bool(some_pointer)) if that behavior is desired.
|
||||
Json(void *) = delete;
|
||||
|
||||
// Accessors
|
||||
Type type() const;
|
||||
|
||||
bool is_null() const { return type() == NUL; }
|
||||
bool is_number() const { return type() == NUMBER; }
|
||||
bool is_bool() const { return type() == BOOL; }
|
||||
bool is_string() const { return type() == STRING; }
|
||||
bool is_array() const { return type() == ARRAY; }
|
||||
bool is_object() const { return type() == OBJECT; }
|
||||
|
||||
// Return the enclosed value if this is a number, 0 otherwise. Note that json11 does not
|
||||
// distinguish between integer and non-integer numbers - number_value() and int_value()
|
||||
// can both be applied to a NUMBER-typed object.
|
||||
double number_value() const;
|
||||
int int_value() const;
|
||||
|
||||
// Return the enclosed value if this is a boolean, false otherwise.
|
||||
bool bool_value() const;
|
||||
// Return the enclosed string if this is a string, "" otherwise.
|
||||
const std::string &string_value() const;
|
||||
// Return the enclosed std::vector if this is an array, or an empty vector otherwise.
|
||||
const array &array_items() const;
|
||||
// Return the enclosed std::map if this is an object, or an empty map otherwise.
|
||||
const object &object_items() const;
|
||||
|
||||
// Return a reference to arr[i] if this is an array, Json() otherwise.
|
||||
const Json & operator[](size_t i) const;
|
||||
// Return a reference to obj[key] if this is an object, Json() otherwise.
|
||||
const Json & operator[](const std::string &key) const;
|
||||
|
||||
// Serialize.
|
||||
void dump(std::string &out) const;
|
||||
std::string dump() const {
|
||||
std::string out;
|
||||
dump(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
// Parse. If parse fails, return Json() and assign an error message to err.
|
||||
static Json parse(const std::string & in,
|
||||
std::string & err,
|
||||
JsonParse strategy = JsonParse::STANDARD);
|
||||
static Json parse(const char * in,
|
||||
std::string & err,
|
||||
JsonParse strategy = JsonParse::STANDARD) {
|
||||
if (in) {
|
||||
return parse(std::string(in), err, strategy);
|
||||
} else {
|
||||
err = "null input";
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
// Parse multiple objects, concatenated or separated by whitespace
|
||||
static std::vector<Json> parse_multi(
|
||||
const std::string & in,
|
||||
std::string::size_type & parser_stop_pos,
|
||||
std::string & err,
|
||||
JsonParse strategy = JsonParse::STANDARD);
|
||||
|
||||
static inline std::vector<Json> parse_multi(
|
||||
const std::string & in,
|
||||
std::string & err,
|
||||
JsonParse strategy = JsonParse::STANDARD) {
|
||||
std::string::size_type parser_stop_pos;
|
||||
return parse_multi(in, parser_stop_pos, err, strategy);
|
||||
}
|
||||
|
||||
bool operator== (const Json &rhs) const;
|
||||
bool operator< (const Json &rhs) const;
|
||||
bool operator!= (const Json &rhs) const { return !(*this == rhs); }
|
||||
bool operator<= (const Json &rhs) const { return !(rhs < *this); }
|
||||
bool operator> (const Json &rhs) const { return (rhs < *this); }
|
||||
bool operator>= (const Json &rhs) const { return !(*this < rhs); }
|
||||
|
||||
/* has_shape(types, err)
|
||||
*
|
||||
* Return true if this is a JSON object and, for each item in types, has a field of
|
||||
* the given type. If not, return false and set err to a descriptive message.
|
||||
*/
|
||||
typedef std::initializer_list<std::pair<std::string, Type>> shape;
|
||||
bool has_shape(const shape & types, std::string & err) const;
|
||||
|
||||
private:
|
||||
std::shared_ptr<JsonValue> m_ptr;
|
||||
};
|
||||
|
||||
// Internal class hierarchy - JsonValue objects are not exposed to users of this API.
|
||||
class JsonValue {
|
||||
protected:
|
||||
friend class Json;
|
||||
friend class JsonInt;
|
||||
friend class JsonDouble;
|
||||
virtual Json::Type type() const = 0;
|
||||
virtual bool equals(const JsonValue * other) const = 0;
|
||||
virtual bool less(const JsonValue * other) const = 0;
|
||||
virtual void dump(std::string &out) const = 0;
|
||||
virtual double number_value() const;
|
||||
virtual int int_value() const;
|
||||
virtual bool bool_value() const;
|
||||
virtual const std::string &string_value() const;
|
||||
virtual const Json::array &array_items() const;
|
||||
virtual const Json &operator[](size_t i) const;
|
||||
virtual const Json::object &object_items() const;
|
||||
virtual const Json &operator[](const std::string &key) const;
|
||||
virtual ~JsonValue() {}
|
||||
};
|
||||
|
||||
} // namespace json11
|
1069
TMessagesProj/jni/libtgvoip2/libtgvoip.UWP.vcxproj
Normal file
1069
TMessagesProj/jni/libtgvoip2/libtgvoip.UWP.vcxproj
Normal file
File diff suppressed because it is too large
Load diff
1936
TMessagesProj/jni/libtgvoip2/libtgvoip.UWP.vcxproj.filters
Normal file
1936
TMessagesProj/jni/libtgvoip2/libtgvoip.UWP.vcxproj.filters
Normal file
File diff suppressed because it is too large
Load diff
423
TMessagesProj/jni/libtgvoip2/libtgvoip.WP81.vcxproj
Normal file
423
TMessagesProj/jni/libtgvoip2/libtgvoip.WP81.vcxproj
Normal file
|
@ -0,0 +1,423 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|ARM">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>ARM</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|ARM">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>ARM</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{21f10158-c078-4bd7-a82a-9c4aeb8e2f8e}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectName>libtgvoip</ProjectName>
|
||||
<RootNamespace>libtgvoip</RootNamespace>
|
||||
<DefaultLanguage>en-US</DefaultLanguage>
|
||||
<MinimumVisualStudioVersion>12.0</MinimumVisualStudioVersion>
|
||||
<AppContainerApplication>true</AppContainerApplication>
|
||||
<ApplicationType>Windows Phone Silverlight</ApplicationType>
|
||||
<ApplicationTypeRevision>8.1</ApplicationTypeRevision>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PreprocessorDefinitions>_WINRT_DLL;TGVOIP_WP_SILVERLIGHT;_CRT_SECURE_NO_WARNINGS;NOMINMAX;WEBRTC_APM_DEBUG_DUMP=0;TGVOIP_USE_CUSTOM_CRYPTO;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
|
||||
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>webrtc_dsp;../TelegramClient/TelegramClient.Opus/opus/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||
<AdditionalDependencies>ws2_32.lib;phoneaudioses.lib;../TelegramClient/$(Platform)/$(Configuration)/TelegramClient.Opus/TelegramClient.Opus.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PreprocessorDefinitions>_WINRT_DLL;TGVOIP_WP_SILVERLIGHT;NDEBUG;_CRT_SECURE_NO_WARNINGS;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
|
||||
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>webrtc_dsp;../TelegramClient/TelegramClient.Opus/opus/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||
<AdditionalDependencies>ws2_32.lib;phoneaudioses.lib;../TelegramClient/$(Platform)/$(Configuration)/TelegramClient.Opus/TelegramClient.Opus.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PreprocessorDefinitions>_WINRT_DLL;TGVOIP_WP_SILVERLIGHT;_CRT_SECURE_NO_WARNINGS;NOMINMAX;WEBRTC_APM_DEBUG_DUMP=0;TGVOIP_USE_CUSTOM_CRYPTO;noexcept=;_ALLOW_KEYWORD_MACROS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
|
||||
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>webrtc_dsp;../TelegramClient/TelegramClient.Opus/opus/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<DisableSpecificWarnings>4068;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||
<AdditionalDependencies>ws2_32.lib;phoneaudioses.lib;../TelegramClient/$(Platform)/$(Configuration)/TelegramClient.Opus/TelegramClient.Opus.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PreprocessorDefinitions>_WINRT_DLL;TGVOIP_WP_SILVERLIGHT;NDEBUG;_CRT_SECURE_NO_WARNINGS;NOMINMAX;WEBRTC_APM_DEBUG_DUMP=0;TGVOIP_USE_CUSTOM_CRYPTO;noexcept=;_ALLOW_KEYWORD_MACROS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
|
||||
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>webrtc_dsp;../TelegramClient/TelegramClient.Opus/opus/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<RuntimeTypeInfo>true</RuntimeTypeInfo>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||
<AdditionalDependencies>ws2_32.lib;phoneaudioses.lib;../TelegramClient/$(Platform)/$(Configuration)/TelegramClient.Opus/TelegramClient.Opus.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="audio\AudioInput.h" />
|
||||
<ClInclude Include="audio\AudioIO.h" />
|
||||
<ClInclude Include="audio\AudioOutput.h" />
|
||||
<ClInclude Include="audio\Resampler.h" />
|
||||
<ClInclude Include="BlockingQueue.h" />
|
||||
<ClInclude Include="Buffers.h" />
|
||||
<ClInclude Include="CongestionControl.h" />
|
||||
<ClInclude Include="EchoCanceller.h" />
|
||||
<ClInclude Include="JitterBuffer.h" />
|
||||
<ClInclude Include="logging.h" />
|
||||
<ClInclude Include="MediaStreamItf.h" />
|
||||
<ClInclude Include="MessageThread.h" />
|
||||
<ClInclude Include="NetworkSocket.h" />
|
||||
<ClInclude Include="OpusDecoder.h" />
|
||||
<ClInclude Include="OpusEncoder.h" />
|
||||
<ClInclude Include="os\windows\AudioInputWASAPI.h" />
|
||||
<ClInclude Include="os\windows\AudioOutputWASAPI.h" />
|
||||
<ClInclude Include="os\windows\NetworkSocketWinsock.h" />
|
||||
<ClInclude Include="os\windows\WindowsSandboxUtils.h" />
|
||||
<ClInclude Include="PacketReassembler.h" />
|
||||
<ClInclude Include="threading.h" />
|
||||
<ClInclude Include="VoIPController.h" />
|
||||
<ClInclude Include="os\windows\CXWrapper.h" />
|
||||
<ClInclude Include="VoIPServerConfig.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\base\array_view.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\base\atomicops.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\base\basictypes.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\base\checks.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\base\constructormagic.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\base\safe_compare.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\base\safe_conversions.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\base\safe_conversions_impl.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\base\sanitizer.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\base\stringutils.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\base\type_traits.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\common_audio\channel_buffer.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\common_audio\fft4g.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\common_audio\include\audio_util.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\common_audio\ring_buffer.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\common_audio\signal_processing\complex_fft_tables.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\common_audio\signal_processing\include\real_fft.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\common_audio\signal_processing\include\signal_processing_library.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\common_audio\signal_processing\include\spl_inl.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\common_audio\signal_processing\include\spl_inl_armv7.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\common_audio\signal_processing\include\spl_inl_mips.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\common_audio\signal_processing\resample_by_2_internal.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\common_audio\sparse_fir_filter.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\common_audio\wav_file.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\common_audio\wav_header.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\aecm\aecm_core.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\aecm\aecm_defines.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\aecm\echo_control_mobile.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\aec\aec_common.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\aec\aec_core.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\aec\aec_core_optimized_methods.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\aec\aec_resampler.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\aec\echo_cancellation.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\agc\legacy\analog_agc.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\agc\legacy\digital_agc.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\agc\legacy\gain_control.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\logging\apm_data_dumper.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\ns\defines.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\ns\noise_suppression.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\ns\noise_suppression_x.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\ns\nsx_core.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\ns\nsx_defines.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\ns\ns_core.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\ns\windows_private.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\splitting_filter.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\three_band_filter_bank.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\utility\block_mean_calculator.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\utility\delay_estimator.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\utility\delay_estimator_internal.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\utility\delay_estimator_wrapper.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\utility\ooura_fft.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\utility\ooura_fft_tables_common.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\utility\ooura_fft_tables_neon_sse2.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\system_wrappers\include\asm_defines.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\system_wrappers\include\compile_assert_c.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\system_wrappers\include\cpu_features_wrapper.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\system_wrappers\include\metrics.h" />
|
||||
<ClInclude Include="webrtc_dsp\webrtc\typedefs.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="audio\AudioInput.cpp" />
|
||||
<ClCompile Include="audio\AudioIO.cpp" />
|
||||
<ClCompile Include="audio\AudioOutput.cpp" />
|
||||
<ClCompile Include="audio\Resampler.cpp" />
|
||||
<ClCompile Include="BlockingQueue.cpp" />
|
||||
<ClCompile Include="Buffers.cpp" />
|
||||
<ClCompile Include="CongestionControl.cpp" />
|
||||
<ClCompile Include="EchoCanceller.cpp" />
|
||||
<ClCompile Include="JitterBuffer.cpp" />
|
||||
<ClCompile Include="logging.cpp" />
|
||||
<ClCompile Include="MediaStreamItf.cpp" />
|
||||
<ClCompile Include="MessageThread.cpp" />
|
||||
<ClCompile Include="NetworkSocket.cpp" />
|
||||
<ClCompile Include="OpusDecoder.cpp" />
|
||||
<ClCompile Include="OpusEncoder.cpp" />
|
||||
<ClCompile Include="os\windows\AudioInputWASAPI.cpp" />
|
||||
<ClCompile Include="os\windows\AudioOutputWASAPI.cpp" />
|
||||
<ClCompile Include="os\windows\NetworkSocketWinsock.cpp" />
|
||||
<ClCompile Include="os\windows\WindowsSandboxUtils.cpp" />
|
||||
<ClCompile Include="PacketReassembler.cpp" />
|
||||
<ClCompile Include="VoIPController.cpp" />
|
||||
<ClCompile Include="os\windows\CXWrapper.cpp" />
|
||||
<ClCompile Include="VoIPServerConfig.cpp" />
|
||||
<ClCompile Include="webrtc_dsp\webrtc\base\checks.cc" />
|
||||
<ClCompile Include="webrtc_dsp\webrtc\base\stringutils.cc" />
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\audio_util.cc" />
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\channel_buffer.cc" />
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\fft4g.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\ring_buffer.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\auto_correlation.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\auto_corr_to_refl_coef.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\complex_bit_reverse.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\complex_fft.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\copy_set_operations.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\cross_correlation.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\cross_correlation_neon.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\division_operations.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\dot_product_with_scale.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\downsample_fast.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\downsample_fast_neon.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\energy.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\filter_ar.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\filter_ar_fast_q12.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\filter_ma_fast_q12.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\get_hanning_window.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\get_scaling_square.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\ilbc_specific_functions.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\levinson_durbin.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\lpc_to_refl_coef.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\min_max_operations.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\min_max_operations_neon.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\randomization_functions.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\real_fft.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\refl_coef_to_lpc.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\resample.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\resample_48khz.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\resample_by_2.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\resample_by_2_internal.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\resample_fractional.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\splitting_filter_impl.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\spl_init.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\spl_inl.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\spl_sqrt.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\spl_sqrt_floor.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\sqrt_of_one_minus_x_squared.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\vector_scaling_operations.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\sparse_fir_filter.cc" />
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\wav_file.cc" />
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\wav_header.cc" />
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\aecm\aecm_core.cc" />
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\aecm\aecm_core_c.cc" />
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\aecm\aecm_core_neon.cc" />
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\aecm\echo_control_mobile.cc" />
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\aec\aec_core.cc" />
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\aec\aec_core_neon.cc" />
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\aec\aec_core_sse2.cc" />
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\aec\aec_resampler.cc" />
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\aec\echo_cancellation.cc" />
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\agc\legacy\analog_agc.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\agc\legacy\digital_agc.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\logging\apm_data_dumper.cc" />
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\ns\noise_suppression.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\ns\noise_suppression_x.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\ns\nsx_core.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\ns\nsx_core_c.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\ns\nsx_core_neon.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\ns\ns_core.c">
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\splitting_filter.cc" />
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\three_band_filter_bank.cc" />
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\utility\block_mean_calculator.cc" />
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\utility\delay_estimator.cc" />
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\utility\delay_estimator_wrapper.cc" />
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\utility\ooura_fft.cc" />
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\utility\ooura_fft_neon.cc" />
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\utility\ooura_fft_sse2.cc" />
|
||||
<ClCompile Include="webrtc_dsp\webrtc\system_wrappers\source\cpu_features.cc" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
488
TMessagesProj/jni/libtgvoip2/libtgvoip.WP81.vcxproj.filters
Normal file
488
TMessagesProj/jni/libtgvoip2/libtgvoip.WP81.vcxproj.filters
Normal file
|
@ -0,0 +1,488 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Resources">
|
||||
<UniqueIdentifier>11199e80-17a0-460f-a780-9bfde20eb11c</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="audio">
|
||||
<UniqueIdentifier>{c5b75146-c75a-4c56-aeb2-2781658d7b0a}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="windows">
|
||||
<UniqueIdentifier>{de1527d9-7564-4e96-9653-6e023b90d2bc}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="webrtc_dsp">
|
||||
<UniqueIdentifier>{3b15701a-65dd-4d52-92d4-a7b64a73b293}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="VoIPController.cpp" />
|
||||
<ClCompile Include="VoIPServerConfig.cpp" />
|
||||
<ClCompile Include="BlockingQueue.cpp" />
|
||||
<ClCompile Include="CongestionControl.cpp" />
|
||||
<ClCompile Include="EchoCanceller.cpp" />
|
||||
<ClCompile Include="JitterBuffer.cpp" />
|
||||
<ClCompile Include="logging.cpp" />
|
||||
<ClCompile Include="MediaStreamItf.cpp" />
|
||||
<ClCompile Include="NetworkSocket.cpp" />
|
||||
<ClCompile Include="OpusDecoder.cpp" />
|
||||
<ClCompile Include="OpusEncoder.cpp" />
|
||||
<ClCompile Include="audio\AudioInput.cpp">
|
||||
<Filter>audio</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="audio\AudioOutput.cpp">
|
||||
<Filter>audio</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="audio\Resampler.cpp">
|
||||
<Filter>audio</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="os\windows\AudioInputWASAPI.cpp">
|
||||
<Filter>windows</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="os\windows\AudioOutputWASAPI.cpp">
|
||||
<Filter>windows</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="os\windows\NetworkSocketWinsock.cpp">
|
||||
<Filter>windows</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="os\windows\WindowsSandboxUtils.cpp">
|
||||
<Filter>windows</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\base\checks.cc">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\base\stringutils.cc">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\audio_util.cc">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\channel_buffer.cc">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\fft4g.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\ring_buffer.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\auto_correlation.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\auto_corr_to_refl_coef.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\complex_bit_reverse.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\complex_fft.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\copy_set_operations.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\cross_correlation.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\cross_correlation_neon.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\division_operations.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\dot_product_with_scale.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\downsample_fast.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\downsample_fast_neon.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\energy.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\filter_ar.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\filter_ar_fast_q12.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\filter_ma_fast_q12.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\get_hanning_window.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\get_scaling_square.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\ilbc_specific_functions.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\levinson_durbin.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\lpc_to_refl_coef.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\min_max_operations.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\min_max_operations_neon.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\randomization_functions.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\real_fft.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\refl_coef_to_lpc.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\resample.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\resample_48khz.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\resample_by_2.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\resample_by_2_internal.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\resample_fractional.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\splitting_filter_impl.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\spl_init.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\spl_inl.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\spl_sqrt.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\spl_sqrt_floor.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\sqrt_of_one_minus_x_squared.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\signal_processing\vector_scaling_operations.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\sparse_fir_filter.cc">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\wav_file.cc">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\common_audio\wav_header.cc">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\aec\aec_core.cc">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\aec\aec_core_neon.cc">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\aec\aec_core_sse2.cc">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\aec\aec_resampler.cc">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\aec\echo_cancellation.cc">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\aecm\aecm_core.cc">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\aecm\aecm_core_c.cc">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\aecm\aecm_core_neon.cc">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\aecm\echo_control_mobile.cc">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\agc\legacy\analog_agc.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\agc\legacy\digital_agc.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\logging\apm_data_dumper.cc">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\ns\noise_suppression.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\ns\noise_suppression_x.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\ns\nsx_core.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\ns\nsx_core_c.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\ns\nsx_core_neon.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\ns\ns_core.c">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\splitting_filter.cc">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\three_band_filter_bank.cc">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\utility\block_mean_calculator.cc">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\utility\delay_estimator.cc">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\utility\delay_estimator_wrapper.cc">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\utility\ooura_fft.cc">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\utility\ooura_fft_neon.cc">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\modules\audio_processing\utility\ooura_fft_sse2.cc">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="webrtc_dsp\webrtc\system_wrappers\source\cpu_features.cc">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="os\windows\CXWrapper.cpp">
|
||||
<Filter>windows</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Buffers.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="VoIPController.h" />
|
||||
<ClInclude Include="VoIPServerConfig.h" />
|
||||
<ClInclude Include="BlockingQueue.h" />
|
||||
<ClInclude Include="CongestionControl.h" />
|
||||
<ClInclude Include="EchoCanceller.h" />
|
||||
<ClInclude Include="JitterBuffer.h" />
|
||||
<ClInclude Include="logging.h" />
|
||||
<ClInclude Include="MediaStreamItf.h" />
|
||||
<ClInclude Include="NetworkSocket.h" />
|
||||
<ClInclude Include="OpusDecoder.h" />
|
||||
<ClInclude Include="OpusEncoder.h" />
|
||||
<ClInclude Include="threading.h" />
|
||||
<ClInclude Include="audio\AudioInput.h">
|
||||
<Filter>audio</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="audio\AudioOutput.h">
|
||||
<Filter>audio</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="audio\Resampler.h">
|
||||
<Filter>audio</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="os\windows\AudioInputWASAPI.h">
|
||||
<Filter>windows</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="os\windows\AudioOutputWASAPI.h">
|
||||
<Filter>windows</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="os\windows\NetworkSocketWinsock.h">
|
||||
<Filter>windows</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="os\windows\WindowsSandboxUtils.h">
|
||||
<Filter>windows</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\base\array_view.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\base\atomicops.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\base\basictypes.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\base\checks.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\base\constructormagic.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\base\safe_compare.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\base\safe_conversions.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\base\safe_conversions_impl.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\base\sanitizer.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\base\stringutils.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\base\type_traits.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\common_audio\channel_buffer.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\common_audio\fft4g.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\common_audio\include\audio_util.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\common_audio\ring_buffer.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\common_audio\signal_processing\complex_fft_tables.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\common_audio\signal_processing\include\real_fft.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\common_audio\signal_processing\include\signal_processing_library.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\common_audio\signal_processing\include\spl_inl.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\common_audio\signal_processing\include\spl_inl_armv7.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\common_audio\signal_processing\include\spl_inl_mips.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\common_audio\signal_processing\resample_by_2_internal.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\common_audio\sparse_fir_filter.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\common_audio\wav_file.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\common_audio\wav_header.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\aec\aec_common.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\aec\aec_core.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\aec\aec_core_optimized_methods.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\aec\aec_resampler.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\aec\echo_cancellation.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\aecm\aecm_core.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\aecm\aecm_defines.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\aecm\echo_control_mobile.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\agc\legacy\analog_agc.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\agc\legacy\digital_agc.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\agc\legacy\gain_control.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\logging\apm_data_dumper.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\ns\defines.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\ns\noise_suppression.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\ns\noise_suppression_x.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\ns\nsx_core.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\ns\nsx_defines.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\ns\ns_core.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\ns\windows_private.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\splitting_filter.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\three_band_filter_bank.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\utility\block_mean_calculator.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\utility\delay_estimator.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\utility\delay_estimator_internal.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\utility\delay_estimator_wrapper.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\utility\ooura_fft.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\utility\ooura_fft_tables_common.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\modules\audio_processing\utility\ooura_fft_tables_neon_sse2.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\system_wrappers\include\asm_defines.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\system_wrappers\include\compile_assert_c.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\system_wrappers\include\cpu_features_wrapper.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\system_wrappers\include\metrics.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="webrtc_dsp\webrtc\typedefs.h">
|
||||
<Filter>webrtc_dsp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="os\windows\CXWrapper.h">
|
||||
<Filter>windows</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Buffers.h" />
|
||||
</ItemGroup>
|
||||
</Project>
|
3911
TMessagesProj/jni/libtgvoip2/libtgvoip.xcodeproj/project.pbxproj
Normal file
3911
TMessagesProj/jni/libtgvoip2/libtgvoip.xcodeproj/project.pbxproj
Normal file
File diff suppressed because it is too large
Load diff
7
TMessagesProj/jni/libtgvoip2/libtgvoip.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
7
TMessagesProj/jni/libtgvoip2/libtgvoip.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:libtgvoip.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>FILEHEADER</key>
|
||||
<string>
|
||||
libtgvoip is free and unencumbered public domain software.
|
||||
For more information, see http://unlicense.org or the UNLICENSE file
|
||||
you should have received with this source code distribution.
|
||||
</string>
|
||||
</dict>
|
||||
</plist>
|
4144
TMessagesProj/jni/libtgvoip2/libtgvoip_osx.xcodeproj/project.pbxproj
Normal file
4144
TMessagesProj/jni/libtgvoip2/libtgvoip_osx.xcodeproj/project.pbxproj
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:libtgvoip.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>FILEHEADER</key>
|
||||
<string>
|
||||
libtgvoip is free and unencumbered public domain software.
|
||||
For more information, see http://unlicense.org or the UNLICENSE file
|
||||
you should have received with this source code distribution.
|
||||
</string>
|
||||
</dict>
|
||||
</plist>
|
104
TMessagesProj/jni/libtgvoip2/logging.cpp
Normal file
104
TMessagesProj/jni/libtgvoip2/logging.cpp
Normal file
|
@ -0,0 +1,104 @@
|
|||
//
|
||||
// libtgvoip is free and unencumbered public domain software.
|
||||
// For more information, see http://unlicense.org or the UNLICENSE file
|
||||
// you should have received with this source code distribution.
|
||||
//
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "VoIPController.h"
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include <sys/system_properties.h>
|
||||
#elif defined(__linux__)
|
||||
#include <sys/utsname.h>
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <TargetConditionals.h>
|
||||
#include "os/darwin/DarwinSpecific.h"
|
||||
#endif
|
||||
|
||||
FILE* tgvoipLogFile=NULL;
|
||||
|
||||
void tgvoip_log_file_printf(char level, const char* msg, ...){
|
||||
if(tgvoipLogFile){
|
||||
va_list argptr;
|
||||
va_start(argptr, msg);
|
||||
time_t t = time(0);
|
||||
struct tm *now = localtime(&t);
|
||||
fprintf(tgvoipLogFile, "%02d-%02d %02d:%02d:%02d %c: ", now->tm_mon + 1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec, level);
|
||||
vfprintf(tgvoipLogFile, msg, argptr);
|
||||
fprintf(tgvoipLogFile, "\n");
|
||||
fflush(tgvoipLogFile);
|
||||
}
|
||||
}
|
||||
|
||||
void tgvoip_log_file_write_header(FILE* file){
|
||||
if(file){
|
||||
time_t t = time(0);
|
||||
struct tm *now = localtime(&t);
|
||||
#if defined(_WIN32)
|
||||
#if WINAPI_PARTITION_DESKTOP
|
||||
char systemVersion[64];
|
||||
OSVERSIONINFOA vInfo;
|
||||
vInfo.dwOSVersionInfoSize=sizeof(vInfo);
|
||||
GetVersionExA(&vInfo);
|
||||
snprintf(systemVersion, sizeof(systemVersion), "Windows %d.%d.%d %s", vInfo.dwMajorVersion, vInfo.dwMinorVersion, vInfo.dwBuildNumber, vInfo.szCSDVersion);
|
||||
#else
|
||||
char* systemVersion="Windows RT";
|
||||
#endif
|
||||
#elif defined(__linux__)
|
||||
#ifdef __ANDROID__
|
||||
char systemVersion[128];
|
||||
char sysRel[PROP_VALUE_MAX];
|
||||
char deviceVendor[PROP_VALUE_MAX];
|
||||
char deviceModel[PROP_VALUE_MAX];
|
||||
__system_property_get("ro.build.version.release", sysRel);
|
||||
__system_property_get("ro.product.manufacturer", deviceVendor);
|
||||
__system_property_get("ro.product.model", deviceModel);
|
||||
snprintf(systemVersion, sizeof(systemVersion), "Android %s (%s %s)", sysRel, deviceVendor, deviceModel);
|
||||
#else
|
||||
struct utsname sysname;
|
||||
uname(&sysname);
|
||||
std::string sysver(sysname.sysname);
|
||||
sysver+=" ";
|
||||
sysver+=sysname.release;
|
||||
sysver+=" (";
|
||||
sysver+=sysname.version;
|
||||
sysver+=")";
|
||||
const char* systemVersion=sysver.c_str();
|
||||
#endif
|
||||
#elif defined(__APPLE__)
|
||||
char osxVer[128];
|
||||
tgvoip::DarwinSpecific::GetSystemName(osxVer, sizeof(osxVer));
|
||||
char systemVersion[128];
|
||||
#if TARGET_OS_OSX
|
||||
snprintf(systemVersion, sizeof(systemVersion), "OS X %s", osxVer);
|
||||
#elif TARGET_OS_IPHONE
|
||||
snprintf(systemVersion, sizeof(systemVersion), "iOS %s", osxVer);
|
||||
#else
|
||||
snprintf(systemVersion, sizeof(systemVersion), "Unknown Darwin %s", osxVer);
|
||||
#endif
|
||||
#else
|
||||
const char* systemVersion="Unknown OS";
|
||||
#endif
|
||||
|
||||
#if defined(__aarch64__)
|
||||
const char* cpuArch="ARM64";
|
||||
#elif defined(__arm__) || defined(_M_ARM)
|
||||
const char* cpuArch="ARM";
|
||||
#elif defined(_M_X64) || defined(__x86_64__)
|
||||
const char* cpuArch="x86_64";
|
||||
#elif defined(_M_IX86) || defined(__i386__)
|
||||
const char* cpuArch="x86";
|
||||
#else
|
||||
const char* cpuArch="Unknown CPU";
|
||||
#endif
|
||||
|
||||
fprintf(file, "---------------\nlibtgvoip v" LIBTGVOIP_VERSION " on %s %s\nLog started on %d/%02d/%d at %d:%02d:%02d\n---------------\n", systemVersion, cpuArch, now->tm_mday, now->tm_mon+1, now->tm_year+1900, now->tm_hour, now->tm_min, now->tm_sec);
|
||||
}
|
||||
}
|
106
TMessagesProj/jni/libtgvoip2/logging.h
Normal file
106
TMessagesProj/jni/libtgvoip2/logging.h
Normal file
|
@ -0,0 +1,106 @@
|
|||
//
|
||||
// libtgvoip is free and unencumbered public domain software.
|
||||
// For more information, see http://unlicense.org or the UNLICENSE file
|
||||
// you should have received with this source code distribution.
|
||||
//
|
||||
|
||||
#ifndef __LOGGING_H
|
||||
#define __LOGGING_H
|
||||
#define LSTR_INT(x) LSTR_DO_INT(x)
|
||||
#define LSTR_DO_INT(x) #x
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <TargetConditionals.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
void tgvoip_log_file_printf(char level, const char* msg, ...);
|
||||
void tgvoip_log_file_write_header(FILE* file);
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
|
||||
#include <android/log.h>
|
||||
|
||||
//#define _LOG_WRAP(...) __BASE_FILE__":"LSTR_INT(__LINE__)": "__VA_ARGS__
|
||||
#define _LOG_WRAP(...) __VA_ARGS__
|
||||
#define TAG "tgvoip"
|
||||
#define LOGV(...) {__android_log_print(ANDROID_LOG_VERBOSE, TAG, _LOG_WRAP(__VA_ARGS__)); tgvoip_log_file_printf('V', __VA_ARGS__);}
|
||||
#define LOGD(...) {__android_log_print(ANDROID_LOG_DEBUG, TAG, _LOG_WRAP(__VA_ARGS__)); tgvoip_log_file_printf('D', __VA_ARGS__);}
|
||||
#define LOGI(...) {__android_log_print(ANDROID_LOG_INFO, TAG, _LOG_WRAP(__VA_ARGS__)); tgvoip_log_file_printf('I', __VA_ARGS__);}
|
||||
#define LOGW(...) {__android_log_print(ANDROID_LOG_WARN, TAG, _LOG_WRAP(__VA_ARGS__)); tgvoip_log_file_printf('W', __VA_ARGS__);}
|
||||
#define LOGE(...) {__android_log_print(ANDROID_LOG_ERROR, TAG, _LOG_WRAP(__VA_ARGS__)); tgvoip_log_file_printf('E', __VA_ARGS__);}
|
||||
|
||||
#elif defined(__APPLE__) && TARGET_OS_IPHONE && defined(TGVOIP_HAVE_TGLOG)
|
||||
|
||||
#include "os/darwin/TGLogWrapper.h"
|
||||
|
||||
#define LOGV(msg, ...) {__tgvoip_call_tglog("V/tgvoip: " msg, ##__VA_ARGS__); tgvoip_log_file_printf('V', msg, ##__VA_ARGS__);}
|
||||
#define LOGD(msg, ...) {__tgvoip_call_tglog("D/tgvoip: " msg, ##__VA_ARGS__); tgvoip_log_file_printf('D', msg, ##__VA_ARGS__);}
|
||||
#define LOGI(msg, ...) {__tgvoip_call_tglog("I/tgvoip: " msg, ##__VA_ARGS__); tgvoip_log_file_printf('I', msg, ##__VA_ARGS__);}
|
||||
#define LOGW(msg, ...) {__tgvoip_call_tglog("W/tgvoip: " msg, ##__VA_ARGS__); tgvoip_log_file_printf('W', msg, ##__VA_ARGS__);}
|
||||
#define LOGE(msg, ...) {__tgvoip_call_tglog("E/tgvoip: " msg, ##__VA_ARGS__); tgvoip_log_file_printf('E', msg, ##__VA_ARGS__);}
|
||||
|
||||
#elif defined(_WIN32) && defined(_DEBUG)
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define _TGVOIP_W32_LOG_PRINT(verb, msg, ...){ char __log_buf[1024]; snprintf(__log_buf, 1024, "%c/tgvoip: " msg "\n", verb, ##__VA_ARGS__); OutputDebugStringA(__log_buf); tgvoip_log_file_printf((char)verb, msg, __VA_ARGS__);}
|
||||
|
||||
#define LOGV(msg, ...) _TGVOIP_W32_LOG_PRINT('V', msg, ##__VA_ARGS__)
|
||||
#define LOGD(msg, ...) _TGVOIP_W32_LOG_PRINT('D', msg, ##__VA_ARGS__)
|
||||
#define LOGI(msg, ...) _TGVOIP_W32_LOG_PRINT('I', msg, ##__VA_ARGS__)
|
||||
#define LOGW(msg, ...) _TGVOIP_W32_LOG_PRINT('W', msg, ##__VA_ARGS__)
|
||||
#define LOGE(msg, ...) _TGVOIP_W32_LOG_PRINT('E', msg, ##__VA_ARGS__)
|
||||
|
||||
#else
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef TGVOIP_NO_STDOUT_LOGS
|
||||
#ifndef TGVOIP_NO_STDOUT_COLOR
|
||||
#define _TGVOIP_LOG_PRINT(verb, color, msg, ...) {printf("\033[%dm%c/tgvoip: " msg "\033[0m\n", color, verb, ##__VA_ARGS__); tgvoip_log_file_printf(verb, msg, ##__VA_ARGS__);}
|
||||
#else
|
||||
#define _TGVOIP_LOG_PRINT(verb, color, msg, ...) {printf("%c/tgvoip: " msg "\n", verb, ##__VA_ARGS__); tgvoip_log_file_printf(verb, msg, ##__VA_ARGS__);}
|
||||
#endif
|
||||
#else
|
||||
#define _TGVOIP_LOG_PRINT(verb, color, msg, ...) {tgvoip_log_file_printf(verb, msg, ##__VA_ARGS__);}
|
||||
#endif
|
||||
|
||||
#define LOGV(msg, ...) _TGVOIP_LOG_PRINT('V', 90, msg, ##__VA_ARGS__)
|
||||
#define LOGD(msg, ...) _TGVOIP_LOG_PRINT('D', 37, msg, ##__VA_ARGS__)
|
||||
#define LOGI(msg, ...) _TGVOIP_LOG_PRINT('I', 94, msg, ##__VA_ARGS__)
|
||||
#define LOGW(msg, ...) _TGVOIP_LOG_PRINT('W', 93, msg, ##__VA_ARGS__)
|
||||
#define LOGE(msg, ...) _TGVOIP_LOG_PRINT('E', 91, msg, ##__VA_ARGS__)
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(snprintf) && defined(_WIN32) && defined(__cplusplus_winrt)
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
#ifdef TGVOIP_LOG_VERBOSITY
|
||||
#if TGVOIP_LOG_VERBOSITY<5
|
||||
#undef LOGV
|
||||
#define LOGV(msg, ...)
|
||||
#endif
|
||||
#if TGVOIP_LOG_VERBOSITY<4
|
||||
#undef LOGD
|
||||
#define LOGD(msg, ...)
|
||||
#endif
|
||||
#if TGVOIP_LOG_VERBOSITY<3
|
||||
#undef LOGI
|
||||
#define LOGI(msg, ...)
|
||||
#endif
|
||||
#if TGVOIP_LOG_VERBOSITY<2
|
||||
#undef LOGW
|
||||
#define LOGW(msg, ...)
|
||||
#endif
|
||||
#if TGVOIP_LOG_VERBOSITY<1
|
||||
#undef LOGE
|
||||
#define LOGE(msg, ...)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif //__LOGGING_H
|
11369
TMessagesProj/jni/libtgvoip2/ltmain.sh
Normal file
11369
TMessagesProj/jni/libtgvoip2/ltmain.sh
Normal file
File diff suppressed because it is too large
Load diff
215
TMessagesProj/jni/libtgvoip2/missing
Normal file
215
TMessagesProj/jni/libtgvoip2/missing
Normal file
|
@ -0,0 +1,215 @@
|
|||
#! /bin/sh
|
||||
# Common wrapper for a few potentially missing GNU programs.
|
||||
|
||||
scriptversion=2018-03-07.03; # UTC
|
||||
|
||||
# Copyright (C) 1996-2018 Free Software Foundation, Inc.
|
||||
# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
if test $# -eq 0; then
|
||||
echo 1>&2 "Try '$0 --help' for more information"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case $1 in
|
||||
|
||||
--is-lightweight)
|
||||
# Used by our autoconf macros to check whether the available missing
|
||||
# script is modern enough.
|
||||
exit 0
|
||||
;;
|
||||
|
||||
--run)
|
||||
# Back-compat with the calling convention used by older automake.
|
||||
shift
|
||||
;;
|
||||
|
||||
-h|--h|--he|--hel|--help)
|
||||
echo "\
|
||||
$0 [OPTION]... PROGRAM [ARGUMENT]...
|
||||
|
||||
Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
|
||||
to PROGRAM being missing or too old.
|
||||
|
||||
Options:
|
||||
-h, --help display this help and exit
|
||||
-v, --version output version information and exit
|
||||
|
||||
Supported PROGRAM values:
|
||||
aclocal autoconf autoheader autom4te automake makeinfo
|
||||
bison yacc flex lex help2man
|
||||
|
||||
Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
|
||||
'g' are ignored when checking the name.
|
||||
|
||||
Send bug reports to <bug-automake@gnu.org>."
|
||||
exit $?
|
||||
;;
|
||||
|
||||
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
|
||||
echo "missing $scriptversion (GNU Automake)"
|
||||
exit $?
|
||||
;;
|
||||
|
||||
-*)
|
||||
echo 1>&2 "$0: unknown '$1' option"
|
||||
echo 1>&2 "Try '$0 --help' for more information"
|
||||
exit 1
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
# Run the given program, remember its exit status.
|
||||
"$@"; st=$?
|
||||
|
||||
# If it succeeded, we are done.
|
||||
test $st -eq 0 && exit 0
|
||||
|
||||
# Also exit now if we it failed (or wasn't found), and '--version' was
|
||||
# passed; such an option is passed most likely to detect whether the
|
||||
# program is present and works.
|
||||
case $2 in --version|--help) exit $st;; esac
|
||||
|
||||
# Exit code 63 means version mismatch. This often happens when the user
|
||||
# tries to use an ancient version of a tool on a file that requires a
|
||||
# minimum version.
|
||||
if test $st -eq 63; then
|
||||
msg="probably too old"
|
||||
elif test $st -eq 127; then
|
||||
# Program was missing.
|
||||
msg="missing on your system"
|
||||
else
|
||||
# Program was found and executed, but failed. Give up.
|
||||
exit $st
|
||||
fi
|
||||
|
||||
perl_URL=https://www.perl.org/
|
||||
flex_URL=https://github.com/westes/flex
|
||||
gnu_software_URL=https://www.gnu.org/software
|
||||
|
||||
program_details ()
|
||||
{
|
||||
case $1 in
|
||||
aclocal|automake)
|
||||
echo "The '$1' program is part of the GNU Automake package:"
|
||||
echo "<$gnu_software_URL/automake>"
|
||||
echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
|
||||
echo "<$gnu_software_URL/autoconf>"
|
||||
echo "<$gnu_software_URL/m4/>"
|
||||
echo "<$perl_URL>"
|
||||
;;
|
||||
autoconf|autom4te|autoheader)
|
||||
echo "The '$1' program is part of the GNU Autoconf package:"
|
||||
echo "<$gnu_software_URL/autoconf/>"
|
||||
echo "It also requires GNU m4 and Perl in order to run:"
|
||||
echo "<$gnu_software_URL/m4/>"
|
||||
echo "<$perl_URL>"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
give_advice ()
|
||||
{
|
||||
# Normalize program name to check for.
|
||||
normalized_program=`echo "$1" | sed '
|
||||
s/^gnu-//; t
|
||||
s/^gnu//; t
|
||||
s/^g//; t'`
|
||||
|
||||
printf '%s\n' "'$1' is $msg."
|
||||
|
||||
configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
|
||||
case $normalized_program in
|
||||
autoconf*)
|
||||
echo "You should only need it if you modified 'configure.ac',"
|
||||
echo "or m4 files included by it."
|
||||
program_details 'autoconf'
|
||||
;;
|
||||
autoheader*)
|
||||
echo "You should only need it if you modified 'acconfig.h' or"
|
||||
echo "$configure_deps."
|
||||
program_details 'autoheader'
|
||||
;;
|
||||
automake*)
|
||||
echo "You should only need it if you modified 'Makefile.am' or"
|
||||
echo "$configure_deps."
|
||||
program_details 'automake'
|
||||
;;
|
||||
aclocal*)
|
||||
echo "You should only need it if you modified 'acinclude.m4' or"
|
||||
echo "$configure_deps."
|
||||
program_details 'aclocal'
|
||||
;;
|
||||
autom4te*)
|
||||
echo "You might have modified some maintainer files that require"
|
||||
echo "the 'autom4te' program to be rebuilt."
|
||||
program_details 'autom4te'
|
||||
;;
|
||||
bison*|yacc*)
|
||||
echo "You should only need it if you modified a '.y' file."
|
||||
echo "You may want to install the GNU Bison package:"
|
||||
echo "<$gnu_software_URL/bison/>"
|
||||
;;
|
||||
lex*|flex*)
|
||||
echo "You should only need it if you modified a '.l' file."
|
||||
echo "You may want to install the Fast Lexical Analyzer package:"
|
||||
echo "<$flex_URL>"
|
||||
;;
|
||||
help2man*)
|
||||
echo "You should only need it if you modified a dependency" \
|
||||
"of a man page."
|
||||
echo "You may want to install the GNU Help2man package:"
|
||||
echo "<$gnu_software_URL/help2man/>"
|
||||
;;
|
||||
makeinfo*)
|
||||
echo "You should only need it if you modified a '.texi' file, or"
|
||||
echo "any other file indirectly affecting the aspect of the manual."
|
||||
echo "You might want to install the Texinfo package:"
|
||||
echo "<$gnu_software_URL/texinfo/>"
|
||||
echo "The spurious makeinfo call might also be the consequence of"
|
||||
echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
|
||||
echo "want to install GNU make:"
|
||||
echo "<$gnu_software_URL/make/>"
|
||||
;;
|
||||
*)
|
||||
echo "You might have modified some files without having the proper"
|
||||
echo "tools for further handling them. Check the 'README' file, it"
|
||||
echo "often tells you about the needed prerequisites for installing"
|
||||
echo "this package. You may also peek at any GNU archive site, in"
|
||||
echo "case some other package contains this missing '$1' program."
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
give_advice "$1" | sed -e '1s/^/WARNING: /' \
|
||||
-e '2,$s/^/ /' >&2
|
||||
|
||||
# Propagate the correct exit status (expected to be 127 for a program
|
||||
# not found, 63 for a program that failed due to version mismatch).
|
||||
exit $st
|
||||
|
||||
# Local variables:
|
||||
# eval: (add-hook 'before-save-hook 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC0"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue