Skip to content

Commit 0aae959

Browse files
committed
update to 13.0.3 (7183)
1 parent 1c84083 commit 0aae959

37 files changed

Lines changed: 3572 additions & 65 deletions

‎TMessagesProj/jni/audio.c‎

Lines changed: 824 additions & 1 deletion
Large diffs are not rendered by default.

‎TMessagesProj/jni/voip/webrtc/p2p/base/ice_transport_internal.cc‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include "p2p/base/ice_transport_internal.h"
1212

13+
#include "absl/strings/match.h"
1314
#include "absl/strings/string_view.h"
1415
#include "p2p/base/p2p_constants.h"
1516

@@ -35,7 +36,10 @@ RTCError VerifyCandidate(const Candidate& cand) {
3536
return RTCError::OK();
3637
}
3738
if (port < 1024) {
38-
if ((port != 80) && (port != 443)) {
39+
// Telegram reflector addresses are synthetic hostnames whose port identifies
40+
// the relay server. ReflectorPort validates and handles these candidates.
41+
if (!absl::EndsWith(cand.address().hostname(), ".reflector") &&
42+
(port != 80) && (port != 443)) {
3943
return RTCError(RTCErrorType::INVALID_PARAMETER,
4044
"candidate has port below 1024, but not 80 or 443");
4145
}
-53.2 KB
Binary file not shown.

‎TMessagesProj/src/main/java/org/telegram/messenger/AppGlobalConfig.java‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ public class AppGlobalConfig {
6060
public final ConfigBoolean disableBlurInLightTheme = ofBoolean("android_disable_blur_in_light_theme", false);
6161
public final ConfigBoolean disableBlurInDarkTheme = ofBoolean("android_disable_blur_in_dark_theme", false);
6262

63+
public final ConfigBoolean audioRecorderV2Disabled = ofBoolean("android_audio_recorder_v2_disabled", false);
64+
6365
public final ConfigTime noForwardsRequestExpirePeriod = ofTime("no_forwards_request_expire_period", 86400, TimeUnit.SECONDS);
6466
public final ConfigTime pollClosePeriodMax = ofTime("poll_close_period_max", 86400 * 30, TimeUnit.SECONDS);
6567

Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
package org.telegram.messenger;
2+
3+
import android.content.Context;
4+
import android.os.Handler;
5+
import android.os.Looper;
6+
7+
import androidx.annotation.NonNull;
8+
import androidx.annotation.Nullable;
9+
10+
import org.telegram.utils.recorder.audio.AudioRecordingSession;
11+
import org.telegram.utils.settings.SharedSettings;
12+
13+
import java.io.File;
14+
import java.util.HashMap;
15+
import java.util.HashSet;
16+
17+
/** Bridges the standalone recorder to Telegram's existing voice-recording lifecycle. */
18+
final class AudioRecorderV2Controller {
19+
20+
interface Listener {
21+
void onOutputStarted(@NonNull File file);
22+
23+
void onOutputInvalidated(@NonNull File file);
24+
25+
void onRecordingStarted();
26+
27+
void onRecordingResumed();
28+
29+
void onRecordingProgress(long durationMs, double amplitude);
30+
31+
void onPreviewReady(
32+
long durationMs,
33+
@NonNull File file,
34+
@Nullable byte[] waveform
35+
);
36+
37+
void onCompleted(@NonNull AudioRecordingSession.Result result);
38+
39+
void onRecordingTooShort(long durationMs);
40+
41+
void onError(@NonNull Exception error);
42+
}
43+
44+
private final Handler mainHandler = new Handler(Looper.getMainLooper());
45+
private final Listener listener;
46+
private final AudioRecordingSession session;
47+
private final Object outputLock = new Object();
48+
private final HashMap<Long, File> outputFiles = new HashMap<>();
49+
private final HashSet<Long> deliveredOutputIds = new HashSet<>();
50+
51+
private AudioRecordingSession.State previousState = AudioRecordingSession.State.IDLE;
52+
private boolean finishRequested;
53+
private boolean released;
54+
55+
AudioRecorderV2Controller(
56+
@NonNull Context context,
57+
@NonNull File outputDirectory,
58+
@NonNull Listener listener
59+
) {
60+
this.listener = listener;
61+
session = new AudioRecordingSession.Builder(context)
62+
.setOutputDirectory(outputDirectory)
63+
.setMinimumDurationMs(700L)
64+
.setMaximumDurationMs(0L)
65+
.setNoiseSuppression(SharedSettings.audioRecorderNoiseSuppression.get())
66+
.setListener(new AudioRecordingSession.Listener() {
67+
@Override
68+
public void onStateChanged(@NonNull AudioRecordingSession.StateInfo stateInfo) {
69+
AudioRecordingSession.State state = stateInfo.getState();
70+
AudioRecordingSession.State previous = previousState;
71+
previousState = state;
72+
if (state == AudioRecordingSession.State.RECORDING) {
73+
if (!finishRequested
74+
&& previous == AudioRecordingSession.State.STARTING) {
75+
listener.onRecordingStarted();
76+
} else if (!finishRequested
77+
&& previous == AudioRecordingSession.State.RESUMING) {
78+
listener.onRecordingResumed();
79+
}
80+
completePendingFinish(state);
81+
}
82+
}
83+
84+
@Override
85+
public void onRecordingProgress(long durationMs, double amplitude) {
86+
listener.onRecordingProgress(durationMs, amplitude);
87+
}
88+
89+
@Override
90+
public void onPreviewReady(
91+
long durationMs,
92+
long trimStartMs,
93+
long trimEndMs,
94+
@Nullable byte[] waveform
95+
) {
96+
if (finishRequested) {
97+
finishRequested = false;
98+
session.finish();
99+
return;
100+
}
101+
File file = session.getPreviewFile();
102+
if (file == null) {
103+
listener.onError(new IllegalStateException("Preview file is unavailable"));
104+
return;
105+
}
106+
listener.onPreviewReady(durationMs, file, waveform);
107+
}
108+
109+
@Override
110+
public void onRecordingTooShort(long durationMs) {
111+
listener.onRecordingTooShort(durationMs);
112+
}
113+
114+
@Override
115+
public void onCompleted(@NonNull AudioRecordingSession.Result result) {
116+
listener.onCompleted(result);
117+
}
118+
119+
@Override
120+
public void onError(@NonNull Exception error) {
121+
listener.onError(error);
122+
}
123+
})
124+
.setOutputListener(new AudioRecordingSession.OutputListener() {
125+
@Override
126+
public void onOutputStarted(long outputId, @NonNull File file) {
127+
synchronized (outputLock) {
128+
outputFiles.put(outputId, file);
129+
}
130+
mainHandler.post(() -> {
131+
if (released) return;
132+
deliveredOutputIds.add(outputId);
133+
listener.onOutputStarted(file);
134+
});
135+
}
136+
137+
@Override
138+
public void onOutputInvalidated(
139+
long outputId,
140+
@NonNull AudioRecordingSession.OutputInvalidationReason reason
141+
) {
142+
File file;
143+
synchronized (outputLock) {
144+
file = outputFiles.remove(outputId);
145+
}
146+
if (file != null) {
147+
mainHandler.post(() -> {
148+
if (deliveredOutputIds.remove(outputId)) {
149+
listener.onOutputInvalidated(file);
150+
}
151+
});
152+
}
153+
}
154+
155+
@Override
156+
public void onOutputCompleted(
157+
long outputId,
158+
@NonNull File file,
159+
long finalSize,
160+
long durationMs
161+
) {
162+
synchronized (outputLock) {
163+
outputFiles.put(outputId, file);
164+
}
165+
}
166+
})
167+
.setLogger(new AudioRecordingSession.Logger() {
168+
@Override
169+
public void log(@NonNull String message) {
170+
if (BuildVars.LOGS_ENABLED) {
171+
FileLog.d("AudioRecorderV2 " + message);
172+
}
173+
}
174+
175+
@Override
176+
public void error(@NonNull String message, @NonNull Throwable error) {
177+
FileLog.e("AudioRecorderV2 " + message, error);
178+
}
179+
})
180+
.build();
181+
}
182+
183+
boolean start() {
184+
return session.start();
185+
}
186+
187+
boolean togglePause() {
188+
AudioRecordingSession.State state = session.getStateInfo().getState();
189+
if (state == AudioRecordingSession.State.RECORDING) {
190+
return session.pauseRecording();
191+
}
192+
if (state == AudioRecordingSession.State.PREVIEWING) {
193+
return session.resumeRecording();
194+
}
195+
return false;
196+
}
197+
198+
boolean setTrimRange(long startMs, long endMs) {
199+
return session.setTrimRange(startMs, endMs);
200+
}
201+
202+
void finishWhenReady() {
203+
finishRequested = true;
204+
completePendingFinish(session.getStateInfo().getState());
205+
}
206+
207+
void cancel() {
208+
finishRequested = false;
209+
session.cancel();
210+
}
211+
212+
void release() {
213+
session.release();
214+
released = true;
215+
}
216+
217+
boolean detachPreviewOutput() {
218+
AudioRecordingSession.Result result = session.detachPreviewOutput();
219+
if (result == null) return false;
220+
session.release();
221+
released = true;
222+
return true;
223+
}
224+
225+
boolean isPreviewing() {
226+
return session.getStateInfo().getState() == AudioRecordingSession.State.PREVIEWING;
227+
}
228+
229+
private void completePendingFinish(@NonNull AudioRecordingSession.State state) {
230+
if (!finishRequested) return;
231+
if (state == AudioRecordingSession.State.RECORDING
232+
|| state == AudioRecordingSession.State.PREVIEWING) {
233+
finishRequested = false;
234+
session.finish();
235+
}
236+
}
237+
}

0 commit comments

Comments
 (0)