Работающие звонки

This commit is contained in:
2026-03-27 03:12:04 +05:00
parent 9cca071bd8
commit b663450db5
10 changed files with 343 additions and 53 deletions

View File

@@ -16,6 +16,7 @@
#include <signal.h> #include <signal.h>
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <time.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include <android/log.h> #include <android/log.h>
@@ -125,6 +126,12 @@ struct AdditionalTsState {
uint64_t base_timestamp = 0; uint64_t base_timestamp = 0;
}; };
struct SenderTsOffsetState {
bool initialized = false;
bool enabled = false;
uint64_t offset = 0;
};
static inline uint16_t load16_be(const uint8_t* p) { static inline uint16_t load16_be(const uint8_t* p) {
return (uint16_t)(((uint16_t)p[0] << 8) | (uint16_t)p[1]); return (uint16_t)(((uint16_t)p[0] << 8) | (uint16_t)p[1]);
} }
@@ -334,6 +341,25 @@ static inline void fill_nonce_from_ts32(uint32_t ts, uint8_t nonce[24]) {
nonce[7] = (uint8_t)(ts); nonce[7] = (uint8_t)(ts);
} }
static inline void fill_nonce_from_ts64(uint64_t ts, uint8_t nonce[24]) {
nonce[0] = (uint8_t)(ts >> 56);
nonce[1] = (uint8_t)(ts >> 48);
nonce[2] = (uint8_t)(ts >> 40);
nonce[3] = (uint8_t)(ts >> 32);
nonce[4] = (uint8_t)(ts >> 24);
nonce[5] = (uint8_t)(ts >> 16);
nonce[6] = (uint8_t)(ts >> 8);
nonce[7] = (uint8_t)(ts);
}
static inline uint64_t monotonic_48k_ticks() {
struct timespec ts {};
if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) return 0;
const uint64_t sec = (uint64_t)ts.tv_sec;
const uint64_t nsec = (uint64_t)ts.tv_nsec;
return sec * 48000ULL + (nsec * 48000ULL) / 1000000000ULL;
}
static inline uint32_t opus_base_frame_samples(uint8_t config) { static inline uint32_t opus_base_frame_samples(uint8_t config) {
// RFC 6716 TOC config mapping at 48 kHz. // RFC 6716 TOC config mapping at 48 kHz.
if (config <= 11) { if (config <= 11) {
@@ -550,6 +576,7 @@ public:
bool nonce_from_generated_ts = false; bool nonce_from_generated_ts = false;
bool nonce_from_additional_data = false; bool nonce_from_additional_data = false;
bool additional_was_rtp_header = false; bool additional_was_rtp_header = false;
bool additional_used_mono_offset = false;
uint32_t generated_ts_used = 0; uint32_t generated_ts_used = 0;
// Build nonce from RTP timestamp in additional_data (preferred). // Build nonce from RTP timestamp in additional_data (preferred).
@@ -579,23 +606,36 @@ public:
} }
} }
if (nonce_from_rtp_header && header_size <= frame.size()) { // Some Android sender pipelines expose stream-relative ad8 timestamps
// Keep RTP header clear, encrypt payload only. // (0, 960, 1920, ...), while desktop receiver expects an absolute base.
if (header_size > 0) { // For interop, add a monotonic 48k offset once when first ad8 is tiny.
memcpy(encrypted_frame.data(), frame.data(), header_size); if (nonce_from_additional_data &&
additional_data.size() == 8 &&
!additional_was_rtp_header &&
additional_data.data() != nullptr) {
const uint64_t ad_ts64 = load64_be(additional_data.data());
if (!sender_ts_offset_.initialized) {
sender_ts_offset_.initialized = true;
// Keep pure raw-abs mode by default; desktop is the source of truth.
sender_ts_offset_.enabled = false;
sender_ts_offset_.offset = 0ULL;
diag_event("ENC ad8-base init ssrc=%u ad_ts=%llu use_mono=%d mono_off=%llu\n",
ssrc,
(unsigned long long)ad_ts64,
sender_ts_offset_.enabled ? 1 : 0,
(unsigned long long)sender_ts_offset_.offset);
}
if (sender_ts_offset_.enabled) {
const uint64_t ts_adj = ad_ts64 + sender_ts_offset_.offset;
fill_nonce_from_ts64(ts_adj, nonce);
additional_used_mono_offset = true;
} }
const size_t payload_size = frame.size() - header_size;
rosetta_xchacha20_xor(
encrypted_frame.data() + header_size,
frame.data() + header_size,
payload_size,
nonce,
key_);
} else {
// Legacy path: frame is payload-only.
rosetta_xchacha20_xor(encrypted_frame.data(),
frame.data(), frame.size(), nonce, key_);
} }
// Desktop createEncodedStreams encrypts full encoded chunk.
// To stay wire-compatible, do not preserve any leading RTP-like bytes.
rosetta_xchacha20_xor(encrypted_frame.data(),
frame.data(), frame.size(), nonce, key_);
*bytes_written = frame.size(); *bytes_written = frame.size();
if (nonce_from_generated_ts) { if (nonce_from_generated_ts) {
@@ -628,7 +668,9 @@ public:
: (nonce_from_additional_data : (nonce_from_additional_data
? (additional_was_rtp_header ? (additional_was_rtp_header
? "ad-rtp" ? "ad-rtp"
: (additional_used_relative_ts ? "raw-rel" : "raw-abs")) : (additional_used_mono_offset
? "raw-abs+mono"
: (additional_used_relative_ts ? "raw-rel" : "raw-abs")))
: "raw-abs")); : "raw-abs"));
LOGI("ENC frame#%d mt=%s ssrc=%u sz=%zu ad=%zu hdr=%zu mode=%s nonce_ts=%u gen_ts=%u next_step=%u rtp_ok=%d rtp_seq=%u rtp_ts=%u rtp_ssrc=%u opus_ok=%d key_fp=%08x in_h=%08x out_h=%08x ad8=%02x%02x%02x%02x%02x%02x%02x%02x", LOGI("ENC frame#%d mt=%s ssrc=%u sz=%zu ad=%zu hdr=%zu mode=%s nonce_ts=%u gen_ts=%u next_step=%u rtp_ok=%d rtp_seq=%u rtp_ts=%u rtp_ssrc=%u opus_ok=%d key_fp=%08x in_h=%08x out_h=%08x ad8=%02x%02x%02x%02x%02x%02x%02x%02x",
n, media_type_name(media_type), ssrc, frame.size(), additional_data.size(), header_size, mode, n, media_type_name(media_type), ssrc, frame.size(), additional_data.size(), header_size, mode,
@@ -663,6 +705,7 @@ private:
mutable std::atomic<int> diag_count_{0}; mutable std::atomic<int> diag_count_{0};
mutable RtpProbeState rtp_probe_; mutable RtpProbeState rtp_probe_;
mutable GeneratedTsState generated_ts_; mutable GeneratedTsState generated_ts_;
mutable SenderTsOffsetState sender_ts_offset_;
uint32_t key_fingerprint_ = 0; uint32_t key_fingerprint_ = 0;
uint8_t key_[32]; uint8_t key_[32];
}; };
@@ -746,20 +789,8 @@ public:
bool used_generated_resync = false; bool used_generated_resync = false;
if (nonce_from_rtp_header && header_size <= encrypted_frame.size()) { // Desktop createEncodedStreams decrypts full encoded chunk.
if (header_size > 0) { rosetta_xchacha20_xor(frame.data(), encrypted_frame.data(), encrypted_frame.size(), nonce, key_);
memcpy(frame.data(), encrypted_frame.data(), header_size);
}
const size_t payload_size = encrypted_frame.size() - header_size;
rosetta_xchacha20_xor(
frame.data() + header_size,
encrypted_frame.data() + header_size,
payload_size,
nonce,
key_);
} else {
rosetta_xchacha20_xor(frame.data(), encrypted_frame.data(), encrypted_frame.size(), nonce, key_);
}
if (nonce_from_additional_data) { if (nonce_from_additional_data) {
bool plausible = is_plausible_decrypted_audio_frame(frame.data(), encrypted_frame.size()); bool plausible = is_plausible_decrypted_audio_frame(frame.data(), encrypted_frame.size());

View File

@@ -6,7 +6,6 @@ import android.util.Log
import com.rosetta.messenger.data.MessageRepository import com.rosetta.messenger.data.MessageRepository
import java.security.MessageDigest import java.security.MessageDigest
import java.security.SecureRandom import java.security.SecureRandom
import java.util.IdentityHashMap
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
@@ -137,8 +136,8 @@ object CallManager {
// E2EE (XChaCha20 — compatible with Desktop) // E2EE (XChaCha20 — compatible with Desktop)
private var sharedKeyBytes: ByteArray? = null private var sharedKeyBytes: ByteArray? = null
private val senderEncryptors = IdentityHashMap<RtpSender, XChaCha20E2EE.Encryptor>() private val senderEncryptors = LinkedHashMap<String, XChaCha20E2EE.Encryptor>()
private val receiverDecryptors = IdentityHashMap<RtpReceiver, XChaCha20E2EE.Decryptor>() private val receiverDecryptors = LinkedHashMap<String, XChaCha20E2EE.Decryptor>()
private var pendingAudioSenderForE2ee: RtpSender? = null private var pendingAudioSenderForE2ee: RtpSender? = null
private var lastRemoteOfferFingerprint: String = "" private var lastRemoteOfferFingerprint: String = ""
private var lastLocalOfferFingerprint: String = "" private var lastLocalOfferFingerprint: String = ""
@@ -1063,11 +1062,22 @@ object CallManager {
breadcrumb("STATE[$marker] ${buildStateSnapshot()}") breadcrumb("STATE[$marker] ${buildStateSnapshot()}")
} }
private fun senderMapKey(sender: RtpSender): String {
val id = runCatching { sender.id() }.getOrNull().orEmpty()
return if (id.isNotBlank()) "sid:$id" else "sender@${System.identityHashCode(sender)}"
}
private fun receiverMapKey(receiver: RtpReceiver): String {
val id = runCatching { receiver.id() }.getOrNull().orEmpty()
return if (id.isNotBlank()) "rid:$id" else "recv@${System.identityHashCode(receiver)}"
}
private fun attachSenderE2EE(sender: RtpSender?) { private fun attachSenderE2EE(sender: RtpSender?) {
if (!e2eeAvailable) return if (!e2eeAvailable) return
val key = sharedKeyBytes ?: return val key = sharedKeyBytes ?: return
if (sender == null) return if (sender == null) return
val existing = senderEncryptors[sender] val mapKey = senderMapKey(sender)
val existing = senderEncryptors[mapKey]
if (existing != null) { if (existing != null) {
runCatching { sender.setFrameEncryptor(existing) } runCatching { sender.setFrameEncryptor(existing) }
return return
@@ -1086,7 +1096,7 @@ object CallManager {
breadcrumb("4. calling sender.setFrameEncryptor…") breadcrumb("4. calling sender.setFrameEncryptor…")
sender.setFrameEncryptor(enc) sender.setFrameEncryptor(enc)
breadcrumb("5. setFrameEncryptor OK!") breadcrumb("5. setFrameEncryptor OK!")
senderEncryptors[sender] = enc senderEncryptors[mapKey] = enc
pendingAudioSenderForE2ee = null pendingAudioSenderForE2ee = null
} catch (e: Throwable) { } catch (e: Throwable) {
saveCrashReport("attachSenderE2EE failed", e) saveCrashReport("attachSenderE2EE failed", e)
@@ -1104,7 +1114,8 @@ object CallManager {
if (!e2eeAvailable) return if (!e2eeAvailable) return
val key = sharedKeyBytes ?: return val key = sharedKeyBytes ?: return
if (receiver == null) return if (receiver == null) return
val existing = receiverDecryptors[receiver] val mapKey = receiverMapKey(receiver)
val existing = receiverDecryptors[mapKey]
if (existing != null) { if (existing != null) {
runCatching { receiver.setFrameDecryptor(existing) } runCatching { receiver.setFrameDecryptor(existing) }
return return
@@ -1123,7 +1134,7 @@ object CallManager {
breadcrumb("9. calling receiver.setFrameDecryptor…") breadcrumb("9. calling receiver.setFrameDecryptor…")
receiver.setFrameDecryptor(dec) receiver.setFrameDecryptor(dec)
breadcrumb("10. setFrameDecryptor OK!") breadcrumb("10. setFrameDecryptor OK!")
receiverDecryptors[receiver] = dec receiverDecryptors[mapKey] = dec
} catch (e: Throwable) { } catch (e: Throwable) {
saveCrashReport("attachReceiverE2EE failed", e) saveCrashReport("attachReceiverE2EE failed", e)
Log.e(TAG, "E2EE: receiver decryptor failed", e) Log.e(TAG, "E2EE: receiver decryptor failed", e)

View File

@@ -1,5 +1,6 @@
package com.rosetta.messenger.ui.crashlogs package com.rosetta.messenger.ui.crashlogs
import android.widget.Toast
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
@@ -8,13 +9,16 @@ import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.BugReport import androidx.compose.material.icons.filled.BugReport
import androidx.compose.material.icons.filled.ContentCopy
import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Share import androidx.compose.material.icons.filled.Share
import androidx.compose.material3.* import androidx.compose.material3.*
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@@ -263,6 +267,8 @@ private fun CrashDetailScreen(
onDelete: () -> Unit onDelete: () -> Unit
) { ) {
var showDeleteDialog by remember { mutableStateOf(false) } var showDeleteDialog by remember { mutableStateOf(false) }
val clipboardManager = LocalClipboardManager.current
val context = LocalContext.current
Scaffold( Scaffold(
topBar = { topBar = {
@@ -274,6 +280,14 @@ private fun CrashDetailScreen(
} }
}, },
actions = { actions = {
IconButton(
onClick = {
clipboardManager.setText(AnnotatedString(crashReport.content))
Toast.makeText(context, "Full log copied", Toast.LENGTH_SHORT).show()
}
) {
Icon(Icons.Default.ContentCopy, contentDescription = "Copy Full Log")
}
IconButton(onClick = { /* TODO: Share */ }) { IconButton(onClick = { /* TODO: Share */ }) {
Icon(Icons.Default.Share, contentDescription = "Share") Icon(Icons.Default.Share, contentDescription = "Share")
} }

View File

@@ -9,7 +9,8 @@ Stock `io.github.webrtc-sdk:android:125.6422.07` can call audio frame encryptor
`additional_data` (`ad=0`), so nonce derivation based on timestamp is unavailable. `additional_data` (`ad=0`), so nonce derivation based on timestamp is unavailable.
Desktop uses frame timestamp for nonce. This patch aligns Android with that approach by passing Desktop uses frame timestamp for nonce. This patch aligns Android with that approach by passing
an 8-byte big-endian timestamp payload in `additional_data`: an 8-byte big-endian timestamp payload in `additional_data` (absolute RTP timestamp,
including sender start offset):
- bytes `0..3` = `0` - bytes `0..3` = `0`
- bytes `4..7` = RTP timestamp (big-endian) - bytes `4..7` = RTP timestamp (big-endian)
@@ -18,10 +19,14 @@ an 8-byte big-endian timestamp payload in `additional_data`:
- `build_custom_webrtc.sh` — reproducible build script - `build_custom_webrtc.sh` — reproducible build script
- `patches/0001-audio-e2ee-pass-rtp-timestamp-as-additional-data.patch` — WebRTC patch - `patches/0001-audio-e2ee-pass-rtp-timestamp-as-additional-data.patch` — WebRTC patch
- `patches/0002-android-build-on-mac-host.patch` — allows Android target build on macOS host
- `patches/0003-macos-host-java-ijar.patch` — enables host tools (`ijar`/`jdk`) on macOS
- `patches/0004-macos-linker-missing-L-dirs.patch` — skips invalid host `-L...` paths for lld
- `patches/0005-macos-server-utils-socket.patch` — handles macOS socket errno in Android Java compile helper
## Build ## Build
Recommended on Linux (macOS can work but is less predictable for long WebRTC builds). Recommended on Linux (macOS is supported via additional patches in this folder).
Bootstrap `depot_tools` first: Bootstrap `depot_tools` first:
@@ -47,6 +52,7 @@ Optional env vars:
- `SYNC_JOBS``gclient sync` jobs (default: `1`, safer for googlesource limits) - `SYNC_JOBS``gclient sync` jobs (default: `1`, safer for googlesource limits)
- `SYNC_RETRIES` — sync retry attempts (default: `8`) - `SYNC_RETRIES` — sync retry attempts (default: `8`)
- `SYNC_RETRY_BASE_SEC` — base retry delay in seconds (default: `20`) - `SYNC_RETRY_BASE_SEC` — base retry delay in seconds (default: `20`)
- `MAC_ANDROID_NDK_ROOT` — local Android NDK path on macOS (default: `~/Library/Android/sdk/ndk/27.1.12297006`)
## Troubleshooting (HTTP 429 / RESOURCE_EXHAUSTED) ## Troubleshooting (HTTP 429 / RESOURCE_EXHAUSTED)

View File

@@ -9,7 +9,13 @@ set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROSETTA_ANDROID_DIR="$(cd "${SCRIPT_DIR}/../.." && pwd)" ROSETTA_ANDROID_DIR="$(cd "${SCRIPT_DIR}/../.." && pwd)"
PATCH_FILE="${SCRIPT_DIR}/patches/0001-audio-e2ee-pass-rtp-timestamp-as-additional-data.patch" PATCH_FILES=(
"${SCRIPT_DIR}/patches/0001-audio-e2ee-pass-rtp-timestamp-as-additional-data.patch"
"${SCRIPT_DIR}/patches/0002-android-build-on-mac-host.patch"
"${SCRIPT_DIR}/patches/0003-macos-host-java-ijar.patch"
"${SCRIPT_DIR}/patches/0004-macos-linker-missing-L-dirs.patch"
"${SCRIPT_DIR}/patches/0005-macos-server-utils-socket.patch"
)
# Default target: WebRTC M125 family used by app dependency 125.6422.07. # Default target: WebRTC M125 family used by app dependency 125.6422.07.
WEBRTC_BRANCH="${WEBRTC_BRANCH:-branch-heads/6422}" WEBRTC_BRANCH="${WEBRTC_BRANCH:-branch-heads/6422}"
@@ -132,21 +138,63 @@ sync_with_retry
echo "[webrtc-custom] applying Rosetta patch..." echo "[webrtc-custom] applying Rosetta patch..."
git reset --hard git reset --hard
git apply --check "${PATCH_FILE}" for patch in "${PATCH_FILES[@]}"; do
git apply "${PATCH_FILE}" echo "[webrtc-custom] apply $(basename "${patch}")"
git apply --check "${patch}"
git apply "${patch}"
done
# macOS host tweaks:
# - point third_party/jdk/current to local JDK
# - use locally installed Android NDK (darwin toolchain)
if [[ "$(uname -s)" == "Darwin" ]]; then
if [[ -z "${JAVA_HOME:-}" ]]; then
JAVA_HOME="$(/usr/libexec/java_home 2>/dev/null || true)"
fi
if [[ -z "${JAVA_HOME:-}" || ! -d "${JAVA_HOME}" ]]; then
echo "[webrtc-custom] ERROR: JAVA_HOME not found on macOS"
exit 1
fi
JAVA_HOME_CANDIDATE="${JAVA_HOME}"
if [[ ! -f "${JAVA_HOME_CANDIDATE}/conf/logging.properties" ]] && [[ -d "${JAVA_HOME_CANDIDATE}/libexec/openjdk.jdk/Contents/Home" ]]; then
JAVA_HOME_CANDIDATE="${JAVA_HOME_CANDIDATE}/libexec/openjdk.jdk/Contents/Home"
fi
if [[ ! -f "${JAVA_HOME_CANDIDATE}/conf/logging.properties" ]]; then
echo "[webrtc-custom] ERROR: invalid JAVA_HOME (conf/logging.properties not found): ${JAVA_HOME}"
exit 1
fi
JAVA_HOME="${JAVA_HOME_CANDIDATE}"
ln -sfn "${JAVA_HOME}" "${WEBRTC_SRC}/third_party/jdk/current"
echo "[webrtc-custom] macOS JDK linked: ${WEBRTC_SRC}/third_party/jdk/current -> ${JAVA_HOME}"
fi
mkdir -p "$(dirname "${OUT_AAR}")" mkdir -p "$(dirname "${OUT_AAR}")"
echo "[webrtc-custom] building AAR (this can take a while)..." echo "[webrtc-custom] building AAR (this can take a while)..."
GN_ARGS=(
is_debug=false
is_component_build=false
rtc_include_tests=false
rtc_build_examples=false
)
if [[ "$(uname -s)" == "Darwin" ]]; then
MAC_ANDROID_NDK_ROOT="${MAC_ANDROID_NDK_ROOT:-$HOME/Library/Android/sdk/ndk/27.1.12297006}"
if [[ ! -d "${MAC_ANDROID_NDK_ROOT}" ]]; then
echo "[webrtc-custom] ERROR: Android NDK not found at ${MAC_ANDROID_NDK_ROOT}"
echo "[webrtc-custom] Set MAC_ANDROID_NDK_ROOT to your local NDK path."
exit 1
fi
GN_ARGS+=("android_ndk_root=\"${MAC_ANDROID_NDK_ROOT}\"")
GN_ARGS+=("android_ndk_version=\"27.1.12297006\"")
echo "[webrtc-custom] macOS Android NDK: ${MAC_ANDROID_NDK_ROOT}"
fi
python3 tools_webrtc/android/build_aar.py \ python3 tools_webrtc/android/build_aar.py \
--build-dir out_rosetta_aar \ --build-dir out_rosetta_aar \
--output "${OUT_AAR}" \ --output "${OUT_AAR}" \
--arch "${ARCHS[@]}" \ --arch "${ARCHS[@]}" \
--extra-gn-args \ --extra-gn-args "${GN_ARGS[@]}"
is_debug=false \
is_component_build=false \
rtc_include_tests=false \
rtc_build_examples=false
echo "[webrtc-custom] done" echo "[webrtc-custom] done"
echo "[webrtc-custom] AAR: ${OUT_AAR}" echo "[webrtc-custom] AAR: ${OUT_AAR}"

View File

@@ -25,22 +25,24 @@ index 17cf859ed8..b9d9ab14c8 100644
decrypted_audio_payload); decrypted_audio_payload);
diff --git a/audio/channel_send.cc b/audio/channel_send.cc diff --git a/audio/channel_send.cc b/audio/channel_send.cc
index 4a2700177b..93283c2e78 100644 index 4a2700177b..7ebb501704 100644
--- a/audio/channel_send.cc --- a/audio/channel_send.cc
+++ b/audio/channel_send.cc +++ b/audio/channel_send.cc
@@ -320,10 +320,21 @@ int32_t ChannelSend::SendRtpAudio(AudioFrameType frameType, @@ -320,10 +320,23 @@ int32_t ChannelSend::SendRtpAudio(AudioFrameType frameType,
// Encrypt the audio payload into the buffer. // Encrypt the audio payload into the buffer.
size_t bytes_written = 0; size_t bytes_written = 0;
+ const uint32_t additional_data_timestamp =
+ rtp_timestamp_without_offset + rtp_rtcp_->StartTimestamp();
+ const uint8_t additional_data_bytes[8] = { + const uint8_t additional_data_bytes[8] = {
+ 0, + 0,
+ 0, + 0,
+ 0, + 0,
+ 0, + 0,
+ static_cast<uint8_t>((rtp_timestamp_without_offset >> 24) & 0xff), + static_cast<uint8_t>((additional_data_timestamp >> 24) & 0xff),
+ static_cast<uint8_t>((rtp_timestamp_without_offset >> 16) & 0xff), + static_cast<uint8_t>((additional_data_timestamp >> 16) & 0xff),
+ static_cast<uint8_t>((rtp_timestamp_without_offset >> 8) & 0xff), + static_cast<uint8_t>((additional_data_timestamp >> 8) & 0xff),
+ static_cast<uint8_t>(rtp_timestamp_without_offset & 0xff), + static_cast<uint8_t>(additional_data_timestamp & 0xff),
+ }; + };
+ +
int encrypt_status = frame_encryptor_->Encrypt( int encrypt_status = frame_encryptor_->Encrypt(

View File

@@ -0,0 +1,27 @@
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn
index 26fad5adf..7a614f334 100644
--- a/build/config/BUILDCONFIG.gn
+++ b/build/config/BUILDCONFIG.gn
@@ -239,7 +239,8 @@ if (host_toolchain == "") {
_default_toolchain = ""
if (target_os == "android") {
- assert(host_os == "linux", "Android builds are only supported on Linux.")
+ assert(host_os == "linux" || host_os == "mac",
+ "Android builds are only supported on Linux/macOS.")
_default_toolchain = "//build/toolchain/android:android_clang_$target_cpu"
} else if (target_os == "chromeos" || target_os == "linux") {
# See comments in build/toolchain/cros/BUILD.gn about board compiles.
diff --git a/build/config/android/config.gni b/build/config/android/config.gni
index 427739d70..6a5ab0594 100644
--- a/build/config/android/config.gni
+++ b/build/config/android/config.gni
@@ -327,7 +327,7 @@ if (is_android || is_chromeos) {
# Defines the name the Android build gives to the current host CPU
# architecture, which is different than the names GN uses.
- if (host_cpu == "x64") {
+ if (host_cpu == "x64" || host_cpu == "arm64") {
android_host_arch = "x86_64"
} else if (host_cpu == "x86") {
android_host_arch = "x86"

View File

@@ -0,0 +1,34 @@
diff --git a/third_party/ijar/BUILD.gn b/third_party/ijar/BUILD.gn
index 8dc9fe21cf8..49c50e6636f 100644
--- a/third_party/ijar/BUILD.gn
+++ b/third_party/ijar/BUILD.gn
@@ -4,7 +4,7 @@
# A tool that removes all non-interface-specific parts from a .jar file.
-if (is_linux || is_chromeos) {
+if (is_linux || is_chromeos || is_mac) {
config("ijar_compiler_flags") {
if (is_clang) {
cflags = [
diff --git a/third_party/jdk/BUILD.gn b/third_party/jdk/BUILD.gn
index e003eef94d7..ec49922942b 100644
--- a/third_party/jdk/BUILD.gn
+++ b/third_party/jdk/BUILD.gn
@@ -3,10 +3,12 @@
# found in the LICENSE file.
config("jdk") {
- include_dirs = [
- "current/include",
- "current/include/linux",
- ]
+ include_dirs = [ "current/include" ]
+ if (host_os == "mac") {
+ include_dirs += [ "current/include/darwin" ]
+ } else {
+ include_dirs += [ "current/include/linux" ]
+ }
}
group("java_data") {

View File

@@ -0,0 +1,102 @@
diff --git a/build/toolchain/apple/linker_driver.py b/build/toolchain/apple/linker_driver.py
index 0632230cf..798442534 100755
--- a/build/toolchain/apple/linker_driver.py
+++ b/build/toolchain/apple/linker_driver.py
@@ -7,6 +7,7 @@
import os
import os.path
import re
+import shlex
import shutil
import subprocess
import sys
@@ -113,6 +114,53 @@ class LinkerDriver(object):
# The temporary directory for intermediate LTO object files. If it
# exists, it will clean itself up on script exit.
self._object_path_lto = None
+ self._temp_rsp_files = []
+
+ def _sanitize_rsp_arg(self, arg):
+ if not arg.startswith('@'):
+ return arg
+ rsp_path = arg[1:]
+ if not os.path.isfile(rsp_path):
+ return arg
+
+ try:
+ with open(rsp_path, 'r', encoding='utf-8') as f:
+ rsp_content = f.read()
+ except OSError:
+ return arg
+
+ tokens = shlex.split(rsp_content, posix=True)
+ sanitized = []
+ changed = False
+ i = 0
+ while i < len(tokens):
+ tok = tokens[i]
+ if tok == '-L' and i + 1 < len(tokens):
+ lib_dir = tokens[i + 1]
+ if not os.path.isdir(lib_dir):
+ changed = True
+ i += 2
+ continue
+ elif tok.startswith('-L') and len(tok) > 2:
+ lib_dir = tok[2:]
+ if not os.path.isdir(lib_dir):
+ changed = True
+ i += 1
+ continue
+ sanitized.append(tok)
+ i += 1
+
+ if not changed:
+ return arg
+
+ fd, temp_path = tempfile.mkstemp(prefix='linker_driver_', suffix='.rsp')
+ os.close(fd)
+ with open(temp_path, 'w', encoding='utf-8') as f:
+ for tok in sanitized:
+ f.write(tok)
+ f.write('\n')
+ self._temp_rsp_files.append(temp_path)
+ return '@' + temp_path
def run(self):
"""Runs the linker driver, separating out the main compiler driver's
@@ -135,11 +183,25 @@ class LinkerDriver(object):
assert driver_action[0] not in linker_driver_actions
linker_driver_actions[driver_action[0]] = driver_action[1]
else:
+ if arg.startswith('@'):
+ arg = self._sanitize_rsp_arg(arg)
# TODO(crbug.com/1446796): On Apple, the linker command line
# produced by rustc for LTO includes these arguments, but the
# Apple linker doesn't accept them.
# Upstream bug: https://github.com/rust-lang/rust/issues/60059
BAD_RUSTC_ARGS = '-Wl,-plugin-opt=O[0-9],-plugin-opt=mcpu=.*'
+ if arg == '-Wl,-fatal_warnings':
+ # Some host link steps on Apple Silicon produce benign
+ # warnings from injected search paths (e.g. /usr/local/lib
+ # missing). Don't fail the whole build on those warnings.
+ continue
+ if arg.startswith('-L') and len(arg) > 2:
+ # Some environments inject non-existent library search
+ # paths (e.g. /usr/local/lib on Apple Silicon). lld treats
+ # them as hard errors, so skip missing -L entries.
+ lib_dir = arg[2:]
+ if not os.path.isdir(lib_dir):
+ continue
if not re.match(BAD_RUSTC_ARGS, arg):
compiler_driver_args.append(arg)
@@ -185,6 +247,9 @@ class LinkerDriver(object):
# Re-report the original failure.
raise
+ finally:
+ for path in self._temp_rsp_files:
+ _remove_path(path)
def _get_linker_output(self):
"""Returns the value of the output argument to the linker."""

View File

@@ -0,0 +1,15 @@
diff --git a/build/android/gyp/util/server_utils.py b/build/android/gyp/util/server_utils.py
index 6d5ed79d3..c05b57529 100644
--- a/build/android/gyp/util/server_utils.py
+++ b/build/android/gyp/util/server_utils.py
@@ -36,7 +36,9 @@ def MaybeRunCommand(name, argv, stamp_file, force):
except socket.error as e:
# [Errno 111] Connection refused. Either the server has not been started
# or the server is not currently accepting new connections.
- if e.errno == 111:
+ # [Errno 2] Abstract Unix sockets are unsupported on macOS, so treat
+ # this the same way (build server unavailable).
+ if e.errno in (111, 2):
if force:
raise RuntimeError(
'\n\nBuild server is not running and '