Skip to content

Commit

Permalink
Merge remote-tracking branch 'official/master' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
omg-xtao committed Sep 14, 2023
2 parents a931893 + dcad7b4 commit 7ee7c6e
Show file tree
Hide file tree
Showing 280 changed files with 17,830 additions and 6,800 deletions.
8 changes: 4 additions & 4 deletions TMessagesProj/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import cn.hutool.core.util.RuntimeUtil
apply plugin: "com.android.application"
apply plugin: "kotlin-android"

def verName = "10.0.5"
def verCode = 1137
def verName = "10.0.8"
def verCode = 1138


def officialVer = "10.0.5"
def officialCode = 3804
def officialVer = "10.0.8"
def officialCode = 3867

def serviceAccountCredentialsFile = rootProject.file("service_account_credentials.json")

Expand Down
2 changes: 1 addition & 1 deletion TMessagesProj/jni/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -494,7 +494,7 @@ target_include_directories(breakpad PUBLIC
#voip
include(${CMAKE_HOME_DIRECTORY}/voip/CMakeLists.txt)

set(NATIVE_LIB "tmessages.45")
set(NATIVE_LIB "tmessages.46")

#tmessages
add_library(${NATIVE_LIB} SHARED
Expand Down
68 changes: 32 additions & 36 deletions TMessagesProj/jni/TgNetWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,42 +111,38 @@ void sendRequest(JNIEnv *env, jclass c, jint instanceNum, jlong object, jobject
DEBUG_REF("sendRequest onWriteToSocket");
onWriteToSocket = env->NewGlobalRef(onWriteToSocket);
}
ConnectionsManager::getInstance(instanceNum).sendRequest(request, ([onComplete, instanceNum](
TLObject *response, TL_error *error, int32_t networkType, int64_t responseTime, int64_t msgId) {
TL_api_response *resp = (TL_api_response *) response;
jlong ptr = 0;
jint errorCode = 0;
jstring errorText = nullptr;
if (resp != nullptr) {
ptr = (jlong) resp->response.get();
} else if (error != nullptr) {
errorCode = error->code;
const char *text = error->text.c_str();
size_t size = error->text.size();
if (check_utf8(text, size)) {
errorText = jniEnv[instanceNum]->NewStringUTF(text);
} else {
errorText = jniEnv[instanceNum]->NewStringUTF("UTF-8 ERROR");
}
}
if (onComplete != nullptr) {
jniEnv[instanceNum]->CallVoidMethod(onComplete, jclass_RequestDelegateInternal_run, ptr,
errorCode, errorText, networkType, responseTime);
}
if (errorText != nullptr) {
jniEnv[instanceNum]->DeleteLocalRef(errorText);
}
}), ([onQuickAck, instanceNum] {
if (onQuickAck != nullptr) {
jniEnv[instanceNum]->CallVoidMethod(onQuickAck, jclass_QuickAckDelegate_run);
}
}), ([onWriteToSocket, instanceNum] {
if (onWriteToSocket != nullptr) {
jniEnv[instanceNum]->CallVoidMethod(onWriteToSocket, jclass_WriteToSocketDelegate_run);
}
}), (uint32_t) flags, (uint32_t) datacenterId, (ConnectionType) connetionType, immediate, token,
onComplete, onQuickAck,
onWriteToSocket);
ConnectionsManager::getInstance(instanceNum).sendRequest(request, ([onComplete, instanceNum](TLObject *response, TL_error *error, int32_t networkType, int64_t responseTime, int64_t msgId) {
TL_api_response *resp = (TL_api_response *) response;
jlong ptr = 0;
jint errorCode = 0;
jstring errorText = nullptr;
if (resp != nullptr) {
ptr = (jlong) resp->response.get();
} else if (error != nullptr) {
errorCode = error->code;
const char *text = error->text.c_str();
size_t size = error->text.size();
if (check_utf8(text, size)) {
errorText = jniEnv[instanceNum]->NewStringUTF(text);
} else {
errorText = jniEnv[instanceNum]->NewStringUTF("UTF-8 ERROR");
}
}
if (onComplete != nullptr) {
jniEnv[instanceNum]->CallVoidMethod(onComplete, jclass_RequestDelegateInternal_run, ptr, errorCode, errorText, networkType, responseTime, msgId);
}
if (errorText != nullptr) {
jniEnv[instanceNum]->DeleteLocalRef(errorText);
}
}), ([onQuickAck, instanceNum] {
if (onQuickAck != nullptr) {
jniEnv[instanceNum]->CallVoidMethod(onQuickAck, jclass_QuickAckDelegate_run);
}
}), ([onWriteToSocket, instanceNum] {
if (onWriteToSocket != nullptr) {
jniEnv[instanceNum]->CallVoidMethod(onWriteToSocket, jclass_WriteToSocketDelegate_run);
}
}), (uint32_t) flags, (uint32_t) datacenterId, (ConnectionType) connetionType, immediate, token, onComplete, onQuickAck, onWriteToSocket);
}

void cancelRequest(JNIEnv *env, jclass c, jint instanceNum, jint token, jboolean notifyServer) {
Expand Down
141 changes: 141 additions & 0 deletions TMessagesProj/jni/audio.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <opusfile.h>
#include <math.h>
#include "c_utils.h"
#include "libavformat/avformat.h"

typedef struct {
int version;
Expand Down Expand Up @@ -687,3 +688,143 @@ JNIEXPORT jbyteArray Java_org_telegram_messenger_MediaController_getWaveform(JNI

return result;
}

JNIEXPORT void JNICALL Java_org_telegram_ui_Stories_recorder_FfmpegAudioWaveformLoader_init(JNIEnv *env, jobject obj, jstring pathJStr, jint count) {
const char *path = (*env)->GetStringUTFChars(env, pathJStr, 0);

// Initialize FFmpeg components
av_register_all();

AVFormatContext *formatContext = avformat_alloc_context();
if (!formatContext) {
// Handle error
return;
}

int res;
if ((res = avformat_open_input(&formatContext, path, NULL, NULL)) != 0) {
LOGD("avformat_open_input error %s", av_err2str(res));
// Handle error
avformat_free_context(formatContext);
return;
}

if (avformat_find_stream_info(formatContext, NULL) < 0) {
// Handle error
avformat_close_input(&formatContext);
return;
}

AVCodec *codec = NULL;
int audioStreamIndex = av_find_best_stream(formatContext, AVMEDIA_TYPE_AUDIO, -1, -1, &codec, 0);
if (audioStreamIndex < 0) {
LOGD("av_find_best_stream error %s", av_err2str(audioStreamIndex));
// Handle error
avformat_close_input(&formatContext);
return;
}

AVCodecContext *codecContext = avcodec_alloc_context3(codec);
avcodec_parameters_to_context(codecContext, formatContext->streams[audioStreamIndex]->codecpar);

int64_t duration_in_microseconds = formatContext->duration;
double duration_in_seconds = (double)duration_in_microseconds / AV_TIME_BASE;

if (avcodec_open2(codecContext, codec, NULL) < 0) {
// Handle error
avcodec_free_context(&codecContext);
avformat_close_input(&formatContext);
return;
}

// Obtain the class and method to callback
jclass cls = (*env)->GetObjectClass(env, obj);
jmethodID mid = (*env)->GetMethodID(env, cls, "receiveChunk", "([SI)V");

AVFrame *frame = av_frame_alloc();
AVPacket packet;

int sampleRate = codecContext->sample_rate; // Sample rate from FFmpeg's codec context
int skip = 4;
int barWidth = (int) round((double) duration_in_seconds * sampleRate / count / (1 + skip)); // Assuming you have 'duration' and 'count' defined somewhere

short peak = 0;
int currentCount = 0;
int index = 0;
int chunkIndex = 0;
short waveformChunkData[32]; // Allocate the chunk array

while (av_read_frame(formatContext, &packet) >= 0) {
if (packet.stream_index == audioStreamIndex) {
// Decode the audio packet
int response = avcodec_send_packet(codecContext, &packet);

while (response >= 0) {
response = avcodec_receive_frame(codecContext, frame);
if (response == AVERROR(EAGAIN) || response == AVERROR_EOF) {
break;
} else if (response < 0) {
// Handle error
break;
}

int16_t* samples = (int16_t*) frame->data[0];
for (int i = 0; i < frame->nb_samples; i++) {
short value = samples[i]; // Read the 16-bit PCM sample

if (currentCount >= barWidth) {
waveformChunkData[index - chunkIndex] = peak;
index++;
if (index - chunkIndex >= sizeof(waveformChunkData) / sizeof(short) || index >= count) {
jshortArray waveformData = (*env)->NewShortArray(env, sizeof(waveformChunkData) / sizeof(short));
(*env)->SetShortArrayRegion(env, waveformData, 0, sizeof(waveformChunkData) / sizeof(short), waveformChunkData);
(*env)->CallVoidMethod(env, obj, mid, waveformData, sizeof(waveformChunkData) / sizeof(short));

// Reset the chunk data
memset(waveformChunkData, 0, sizeof(waveformChunkData));
chunkIndex = index;

// Delete local reference to avoid memory leak
(*env)->DeleteLocalRef(env, waveformData);
}
peak = 0;
currentCount = 0;
if (index >= count) {
break;
}
}

if (peak < value) {
peak = value;
}
currentCount++;

// Skip logic
i += skip;
if (i >= frame->nb_samples) {
break;
}
}
}
}

av_packet_unref(&packet);

if (index >= count) {
break;
}

// Check for stopping flag
jfieldID fid = (*env)->GetFieldID(env, cls, "running", "Z");
jboolean running = (*env)->GetBooleanField(env, obj, fid);
if (running == JNI_FALSE) {
break;
}
}

av_frame_free(&frame);
avcodec_free_context(&codecContext);
avformat_close_input(&formatContext);

(*env)->ReleaseStringUTFChars(env, pathJStr, path);
}
Loading

0 comments on commit 7ee7c6e

Please sign in to comment.