Use opus-rs for realtime transport

- switch realtime transport and test server to opus-rs
- drop native opus bazel and cmake plumbing

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
Ahmed Ibrahim
2026-04-05 00:43:41 -07:00
parent f9739d0178
commit 76397dbdd0
11 changed files with 118 additions and 214 deletions

View File

@@ -38,18 +38,6 @@ runs:
shell: pwsh
run: Copy-Item (Get-Command dotslash).Source -Destination "$env:LOCALAPPDATA\Microsoft\WindowsApps\dotslash.exe"
- name: Install CMake for Bazel Rust build scripts (Linux)
if: runner.os == 'Linux'
shell: bash
run: |
sudo DEBIAN_FRONTEND=noninteractive apt-get update
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends cmake
- name: Install CMake for Bazel Rust build scripts (macOS)
if: runner.os == 'macOS'
shell: bash
run: brew install cmake
- name: Set up Bazel
uses: bazelbuild/setup-bazelisk@v3

View File

@@ -345,25 +345,6 @@ crate.annotation(
inject_repo(crate, "alsa_lib")
bazel_dep(name = "opus", version = "1.6.0")
single_version_override(
module_name = "opus",
patch_strip = 1,
patches = [
"//patches:opus_windows_gnullvm_stack_probe.patch",
],
version = "1.6.0",
)
crate.annotation(
crate = "audiopus_sys",
gen_build_script = "off",
deps = ["@opus"],
)
inject_repo(crate, "opus")
bazel_dep(name = "v8", version = "14.6.202.9")
archive_override(
module_name = "v8",

11
MODULE.bazel.lock generated
View File

@@ -50,7 +50,6 @@
"https://bcr.bazel.build/modules/bazel_features/1.9.0/MODULE.bazel": "885151d58d90d8d9c811eb75e3288c11f850e1d6b481a8c9f766adee4712358b",
"https://bcr.bazel.build/modules/bazel_features/1.9.1/MODULE.bazel": "8f679097876a9b609ad1f60249c49d68bfab783dd9be012faf9d82547b14815a",
"https://bcr.bazel.build/modules/bazel_lib/3.0.0/MODULE.bazel": "22b70b80ac89ad3f3772526cd9feee2fa412c2b01933fea7ed13238a448d370d",
"https://bcr.bazel.build/modules/bazel_lib/3.1.0/MODULE.bazel": "6809765c14e3c766a9b9286c7b0ec56ed87a73326e48fe01749f0c0fdcfe3287",
"https://bcr.bazel.build/modules/bazel_lib/3.2.2/MODULE.bazel": "e2c890c8a515d6bca9c66d47718aa9e44b458fde64ec7204b8030bf2d349058c",
"https://bcr.bazel.build/modules/bazel_lib/3.2.2/source.json": "9e84e115c20e14652c5c21401ae85ff4daa8702e265b5c0b3bf89353f17aa212",
"https://bcr.bazel.build/modules/bazel_skylib/1.0.3/MODULE.bazel": "bcb0fd896384802d1ad283b4e4eb4d718eebd8cb820b0a2c3a347fb971afd9d8",
@@ -66,8 +65,7 @@
"https://bcr.bazel.build/modules/bazel_skylib/1.7.1/MODULE.bazel": "3120d80c5861aa616222ec015332e5f8d3171e062e3e804a2a0253e1be26e59b",
"https://bcr.bazel.build/modules/bazel_skylib/1.8.1/MODULE.bazel": "88ade7293becda963e0e3ea33e7d54d3425127e0a326e0d17da085a5f1f03ff6",
"https://bcr.bazel.build/modules/bazel_skylib/1.8.2/MODULE.bazel": "69ad6927098316848b34a9142bcc975e018ba27f08c4ff403f50c1b6e646ca67",
"https://bcr.bazel.build/modules/bazel_skylib/1.9.0/MODULE.bazel": "72997b29dfd95c3fa0d0c48322d05590418edef451f8db8db5509c57875fb4b7",
"https://bcr.bazel.build/modules/bazel_skylib/1.9.0/source.json": "7ad77c1e8c1b84222d9b3f3cae016a76639435744c19330b0b37c0a3c9da7dc0",
"https://bcr.bazel.build/modules/bazel_skylib/1.8.2/source.json": "34a3c8bcf233b835eb74be9d628899bb32999d3e0eadef1947a0a562a2b16ffb",
"https://bcr.bazel.build/modules/buildozer/8.2.1/MODULE.bazel": "61e9433c574c2bd9519cad7fa66b9c1d2b8e8d5f3ae5d6528a2c2d26e68d874d",
"https://bcr.bazel.build/modules/buildozer/8.2.1/source.json": "7c33f6a26ee0216f85544b4bca5e9044579e0219b6898dd653f5fb449cf2e484",
"https://bcr.bazel.build/modules/bzip2/1.0.8.bcr.3/MODULE.bazel": "29ecf4babfd3c762be00d7573c288c083672ab60e79c833ff7f49ee662e54471",
@@ -94,8 +92,6 @@
"https://bcr.bazel.build/modules/nlohmann_json/3.6.1/source.json": "f448c6e8963fdfa7eb831457df83ad63d3d6355018f6574fb017e8169deb43a9",
"https://bcr.bazel.build/modules/openssl/3.5.4.bcr.0/MODULE.bazel": "0f6b8f20b192b9ff0781406256150bcd46f19e66d807dcb0c540548439d6fc35",
"https://bcr.bazel.build/modules/openssl/3.5.4.bcr.0/source.json": "543ed7627cc18e6460b9c1ae4a1b6b1debc5a5e0aca878b00f7531c7186b73da",
"https://bcr.bazel.build/modules/opus/1.6.0/MODULE.bazel": "16494aa652f82a20b5e9757b709117d6e6dd77123bb253772c56bd82a3ef8d9c",
"https://bcr.bazel.build/modules/opus/1.6.0/source.json": "a24d79510adedf18b9d6fe03b4a3443d9c89c8d9f889d1cb99bd7ab2c4bde138",
"https://bcr.bazel.build/modules/package_metadata/0.0.5/MODULE.bazel": "ef4f9439e3270fdd6b9fd4dbc3d2f29d13888e44c529a1b243f7a31dfbc2e8e4",
"https://bcr.bazel.build/modules/package_metadata/0.0.5/source.json": "2326db2f6592578177751c3e1f74786b79382cd6008834c9d01ec865b9126a85",
"https://bcr.bazel.build/modules/platforms/0.0.10/MODULE.bazel": "8cb8efaf200bdeb2150d93e162c40f388529a25852b332cec879373771e48ed5",
@@ -130,8 +126,6 @@
"https://bcr.bazel.build/modules/rules_apple/3.16.0/MODULE.bazel": "0d1caf0b8375942ce98ea944be754a18874041e4e0459401d925577624d3a54a",
"https://bcr.bazel.build/modules/rules_apple/4.1.0/MODULE.bazel": "76e10fd4a48038d3fc7c5dc6e63b7063bbf5304a2e3bd42edda6ec660eebea68",
"https://bcr.bazel.build/modules/rules_apple/4.1.0/source.json": "8ee81e1708756f81b343a5eb2b2f0b953f1d25c4ab3d4a68dc02754872e80715",
"https://bcr.bazel.build/modules/rules_autoconf/0.0.16/MODULE.bazel": "cabdd0c2471ce4890b2d6745fba31ad3fcf576936fbcd35fb503f7b57fb02f92",
"https://bcr.bazel.build/modules/rules_autoconf/0.0.16/source.json": "be5db175c04294b0a822e1405a9a9c2bdc5e625745ab476565c4684389d5670f",
"https://bcr.bazel.build/modules/rules_cc/0.0.1/MODULE.bazel": "cb2aa0747f84c6c3a78dad4e2049c154f08ab9d166b1273835a8174940365647",
"https://bcr.bazel.build/modules/rules_cc/0.0.10/MODULE.bazel": "ec1705118f7eaedd6e118508d3d26deba2a4e76476ada7e0e3965211be012002",
"https://bcr.bazel.build/modules/rules_cc/0.0.13/MODULE.bazel": "0e8529ed7b323dad0775ff924d2ae5af7640b23553dfcd4d34344c7e7a867191",
@@ -651,7 +645,6 @@
"asynk-strim_0.1.5": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"async-fn-stream\",\"req\":\"^0.3.2\"},{\"kind\":\"dev\",\"name\":\"async-stream\",\"req\":\"^0.3.6\"},{\"default_features\":false,\"features\":[\"cargo_bench_support\",\"plotters\"],\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.7.0\"},{\"default_features\":false,\"name\":\"futures-core\",\"req\":\"^0.3.31\"},{\"default_features\":false,\"features\":[\"std\"],\"kind\":\"dev\",\"name\":\"futures-lite\",\"req\":\"^2.3.0\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2.14\"},{\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.99\"}],\"features\":{}}",
"atoi_2.0.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.4.0\"},{\"default_features\":false,\"name\":\"num-traits\",\"req\":\"^0.2.14\"}],\"features\":{\"default\":[\"std\"],\"std\":[\"num-traits/std\"]}}",
"atomic-waker_1.1.2": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"cargo_bench_support\"],\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.4.0\"},{\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3.5\"},{\"default_features\":false,\"name\":\"portable-atomic\",\"optional\":true,\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"rayon\",\"req\":\"^1.7.0\"}],\"features\":{}}",
"audiopus_sys_0.2.2": "{\"dependencies\":[{\"kind\":\"build\",\"name\":\"bindgen\",\"optional\":true,\"req\":\"^0.58\"},{\"kind\":\"build\",\"name\":\"cmake\",\"req\":\"^0.1\"},{\"kind\":\"build\",\"name\":\"log\",\"req\":\"^0.4\"},{\"kind\":\"build\",\"name\":\"pkg-config\",\"req\":\"^0.3\"}],\"features\":{\"default\":[],\"dynamic\":[],\"generate_binding\":[\"bindgen\"],\"static\":[]}}",
"autocfg_1.5.0": "{\"dependencies\":[],\"features\":{}}",
"aws-lc-rs_1.16.2": "{\"dependencies\":[{\"name\":\"aws-lc-fips-sys\",\"optional\":true,\"req\":\"^0.13.1\"},{\"default_features\":false,\"name\":\"aws-lc-sys\",\"optional\":true,\"req\":\"^0.39.0\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"clap\",\"req\":\"^4.4\"},{\"kind\":\"dev\",\"name\":\"hex\",\"req\":\"^0.4.3\"},{\"kind\":\"dev\",\"name\":\"lazy_static\",\"req\":\"^1.5.0\"},{\"kind\":\"dev\",\"name\":\"paste\",\"req\":\"^1.0.15\"},{\"kind\":\"dev\",\"name\":\"regex\",\"req\":\"^1.11.1\"},{\"name\":\"untrusted\",\"optional\":true,\"req\":\"^0.7.1\"},{\"name\":\"zeroize\",\"req\":\"^1.8.1\"}],\"features\":{\"alloc\":[],\"asan\":[\"aws-lc-sys?/asan\",\"aws-lc-fips-sys?/asan\"],\"bindgen\":[\"aws-lc-sys?/bindgen\",\"aws-lc-fips-sys?/bindgen\"],\"default\":[\"aws-lc-sys\",\"alloc\",\"ring-io\",\"ring-sig-verify\"],\"dev-tests-only\":[],\"fips\":[\"dep:aws-lc-fips-sys\"],\"non-fips\":[\"aws-lc-sys\"],\"prebuilt-nasm\":[\"aws-lc-sys?/prebuilt-nasm\"],\"ring-io\":[\"dep:untrusted\"],\"ring-sig-verify\":[\"dep:untrusted\"],\"test_logging\":[],\"unstable\":[]}}",
"aws-lc-sys_0.39.0": "{\"dependencies\":[{\"kind\":\"build\",\"name\":\"bindgen\",\"optional\":true,\"req\":\"^0.72.0\"},{\"features\":[\"parallel\"],\"kind\":\"build\",\"name\":\"cc\",\"req\":\"^1.2.26\"},{\"kind\":\"build\",\"name\":\"cmake\",\"req\":\"^0.1.54\"},{\"kind\":\"build\",\"name\":\"dunce\",\"req\":\"^1.0.5\"},{\"kind\":\"build\",\"name\":\"fs_extra\",\"req\":\"^1.3.0\"}],\"features\":{\"all-bindings\":[],\"asan\":[],\"bindgen\":[\"dep:bindgen\"],\"default\":[\"all-bindings\"],\"disable-prebuilt-nasm\":[],\"fips\":[\"dep:bindgen\"],\"prebuilt-nasm\":[],\"ssl\":[\"bindgen\",\"all-bindings\"]}}",
@@ -1147,7 +1140,7 @@
"opentelemetry_0.31.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5\"},{\"kind\":\"dev\",\"name\":\"futures\",\"req\":\"^0.3\"},{\"name\":\"futures-core\",\"optional\":true,\"req\":\"^0.3\"},{\"name\":\"futures-sink\",\"optional\":true,\"req\":\"^0.3\"},{\"name\":\"js-sys\",\"req\":\"^0.3.63\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", not(target_os = \\\"wasi\\\")))\"},{\"name\":\"pin-project-lite\",\"optional\":true,\"req\":\"^0.2\"},{\"default_features\":false,\"features\":[\"os_rng\",\"thread_rng\"],\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.9\"},{\"default_features\":false,\"name\":\"thiserror\",\"optional\":true,\"req\":\"^2\"},{\"features\":[\"full\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"tracing\",\"optional\":true,\"req\":\">=0.1.40\"}],\"features\":{\"default\":[\"trace\",\"metrics\",\"logs\",\"internal-logs\",\"futures\"],\"futures\":[\"futures-core\",\"futures-sink\",\"pin-project-lite\"],\"internal-logs\":[\"tracing\"],\"logs\":[],\"metrics\":[],\"spec_unstable_logs_enabled\":[\"logs\"],\"testing\":[\"trace\"],\"trace\":[\"futures\",\"thiserror\"]}}",
"opentelemetry_sdk_0.31.0": "{\"dependencies\":[{\"features\":[\"html_reports\"],\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5\"},{\"name\":\"futures-channel\",\"req\":\"^0.3\"},{\"name\":\"futures-executor\",\"req\":\"^0.3\"},{\"default_features\":false,\"features\":[\"std\",\"sink\",\"async-await-macro\"],\"name\":\"futures-util\",\"req\":\"^0.3\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"http\",\"optional\":true,\"req\":\"^1.1\"},{\"default_features\":false,\"name\":\"opentelemetry\",\"req\":\"^0.31\"},{\"default_features\":false,\"name\":\"opentelemetry-http\",\"optional\":true,\"req\":\"^0.31\"},{\"name\":\"percent-encoding\",\"optional\":true,\"req\":\"^2.0\"},{\"features\":[\"flamegraph\",\"criterion\"],\"kind\":\"dev\",\"name\":\"pprof\",\"req\":\"^0.14\",\"target\":\"cfg(not(target_os = \\\"windows\\\"))\"},{\"default_features\":false,\"features\":[\"std\",\"std_rng\",\"small_rng\",\"os_rng\",\"thread_rng\"],\"name\":\"rand\",\"optional\":true,\"req\":\"^0.9\"},{\"kind\":\"dev\",\"name\":\"rstest\",\"req\":\"^0.23.0\"},{\"default_features\":false,\"features\":[\"derive\",\"rc\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"temp-env\",\"req\":\"^0.3.6\"},{\"default_features\":false,\"name\":\"thiserror\",\"req\":\"^2\"},{\"default_features\":false,\"name\":\"tokio\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"tokio-stream\",\"optional\":true,\"req\":\"^0.1\"},{\"default_features\":false,\"name\":\"url\",\"optional\":true,\"req\":\"^2.5\"}],\"features\":{\"default\":[\"trace\",\"metrics\",\"logs\",\"internal-logs\"],\"experimental_async_runtime\":[],\"experimental_logs_batch_log_processor_with_async_runtime\":[\"logs\",\"experimental_async_runtime\"],\"experimental_logs_concurrent_log_processor\":[\"logs\"],\"experimental_metrics_custom_reader\":[\"metrics\"],\"experimental_metrics_disable_name_validation\":[\"metrics\"],\"experimental_metrics_periodicreader_with_async_runtime\":[\"metrics\",\"experimental_async_runtime\"],\"experimental_trace_batch_span_processor_with_async_runtime\":[\"tokio/sync\",\"trace\",\"experimental_async_runtime\"],\"internal-logs\":[\"opentelemetry/internal-logs\"],\"jaeger_remote_sampler\":[\"trace\",\"opentelemetry-http\",\"http\",\"serde\",\"serde_json\",\"url\",\"experimental_async_runtime\"],\"logs\":[\"opentelemetry/logs\"],\"metrics\":[\"opentelemetry/metrics\"],\"rt-tokio\":[\"tokio/rt\",\"tokio/time\",\"tokio-stream\",\"experimental_async_runtime\"],\"rt-tokio-current-thread\":[\"tokio/rt\",\"tokio/time\",\"tokio-stream\",\"experimental_async_runtime\"],\"spec_unstable_logs_enabled\":[\"logs\",\"opentelemetry/spec_unstable_logs_enabled\"],\"spec_unstable_metrics_views\":[\"metrics\"],\"testing\":[\"opentelemetry/testing\",\"trace\",\"metrics\",\"logs\",\"rt-tokio\",\"rt-tokio-current-thread\",\"tokio/macros\",\"tokio/rt-multi-thread\"],\"trace\":[\"opentelemetry/trace\",\"rand\",\"percent-encoding\"]}}",
"option-ext_0.2.0": "{\"dependencies\":[],\"features\":{}}",
"opus_0.3.1": "{\"dependencies\":[{\"name\":\"audiopus_sys\",\"req\":\"^0.2.0\"}],\"features\":{}}",
"opus-rs_0.1.11": "{\"dependencies\":[{\"features\":[\"html_reports\"],\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.8.2\"},{\"name\":\"num-complex\",\"req\":\"^0.4\"},{\"name\":\"once_cell\",\"req\":\"^1.17\"},{\"kind\":\"dev\",\"name\":\"opusic-sys\",\"req\":\"^0.6.0\"},{\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1\"}],\"features\":{}}",
"ordered-stream_0.2.0": "{\"dependencies\":[{\"name\":\"futures-core\",\"req\":\"^0.3\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2\"},{\"kind\":\"dev\",\"name\":\"futures-executor\",\"req\":\"^0.3.25\"},{\"kind\":\"dev\",\"name\":\"futures-util\",\"req\":\"^0.3.25\"}],\"features\":{}}",
"os_info_3.14.0": "{\"dependencies\":[{\"name\":\"android_system_properties\",\"req\":\"^0.1\",\"target\":\"cfg(target_os = \\\"android\\\")\"},{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3\"},{\"name\":\"log\",\"req\":\"^0.4\"},{\"features\":[\"feature\"],\"name\":\"nix\",\"req\":\"^0.30\",\"target\":\"cfg(any(target_os = \\\"aix\\\", target_os = \\\"dragonfly\\\", target_os = \\\"freebsd\\\", target_os = \\\"illumos\\\", target_os = \\\"linux\\\", target_os = \\\"macos\\\", target_os = \\\"netbsd\\\", target_os = \\\"openbsd\\\", target_os = \\\"cygwin\\\"))\"},{\"name\":\"objc2\",\"req\":\"^0.6\",\"target\":\"cfg(target_os = \\\"ios\\\")\"},{\"features\":[\"NSString\"],\"name\":\"objc2-foundation\",\"req\":\"^0.3\",\"target\":\"cfg(target_os = \\\"ios\\\")\"},{\"features\":[\"NSData\",\"NSError\",\"NSEnumerator\",\"NSString\"],\"name\":\"objc2-foundation\",\"req\":\"^0.3\",\"target\":\"cfg(target_os = \\\"macos\\\")\"},{\"name\":\"objc2-ui-kit\",\"req\":\"^0.3\",\"target\":\"cfg(target_os = \\\"ios\\\")\"},{\"kind\":\"dev\",\"name\":\"pretty_assertions\",\"req\":\"^1\"},{\"name\":\"schemars\",\"optional\":true,\"req\":\"^1.0.3\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1\"},{\"features\":[\"Win32_Foundation\",\"Win32_System_LibraryLoader\",\"Win32_System_Registry\",\"Win32_System_SystemInformation\",\"Win32_System_SystemServices\",\"Win32_System_Threading\",\"Win32_UI_WindowsAndMessaging\"],\"name\":\"windows-sys\",\"req\":\"^0.61\",\"target\":\"cfg(windows)\"}],\"features\":{\"default\":[\"serde\"]}}",
"os_pipe_1.2.3": "{\"dependencies\":[{\"name\":\"libc\",\"req\":\"^0.2.62\",\"target\":\"cfg(not(windows))\"},{\"features\":[\"Win32_Foundation\",\"Win32_System_Pipes\",\"Win32_Security\"],\"name\":\"windows-sys\",\"req\":\">=0.28, <=0.61\",\"target\":\"cfg(windows)\"}],\"features\":{\"io_safety\":[]}}",

24
codex-rs/Cargo.lock generated
View File

@@ -784,17 +784,6 @@ version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
[[package]]
name = "audiopus_sys"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62314a1546a2064e033665d658e88c620a62904be945f8147e6b16c3db9f8651"
dependencies = [
"cmake",
"log",
"pkg-config",
]
[[package]]
name = "autocfg"
version = "1.5.0"
@@ -1472,7 +1461,7 @@ dependencies = [
"futures",
"http 1.4.0",
"interceptor",
"opus",
"opus-rs",
"pretty_assertions",
"regex-lite",
"reqwest",
@@ -3407,7 +3396,7 @@ dependencies = [
"notify",
"opentelemetry",
"opentelemetry_sdk",
"opus",
"opus-rs",
"pretty_assertions",
"regex-lite",
"reqwest",
@@ -7329,12 +7318,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
name = "opus"
version = "0.3.1"
name = "opus-rs"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d3809943dff6fbad5f0484449ea26bdb9cb7d8efdf26ed50d3c7f227f69eb5c"
checksum = "f857fcc607bea70f9b073ad267e829080646b14c260ea5e43c48ba9fca8e7dd4"
dependencies = [
"audiopus_sys",
"num-complex",
"once_cell",
]
[[package]]

View File

@@ -256,7 +256,7 @@ notify = "8.2.0"
nucleo = { git = "https://github.com/helix-editor/nucleo.git", rev = "4253de9faabb4e5c6d81d946a5e35a90f87347ee" }
once_cell = "1.20.2"
openssl-sys = "*"
opus = "0.3.0"
opus-rs = "0.1.11"
opentelemetry = "0.31.0"
opentelemetry-appender-tracing = "0.31.0"
opentelemetry-otlp = "0.31.0"

View File

@@ -15,7 +15,7 @@ codex-utils-rustls-provider = { workspace = true }
futures = { workspace = true }
http = { workspace = true }
interceptor = { workspace = true }
opus = { workspace = true }
opus-rs = { workspace = true }
reqwest = { workspace = true, features = ["multipart"] }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }

View File

@@ -21,10 +21,9 @@ use codex_utils_rustls_provider::ensure_rustls_crypto_provider;
use http::HeaderMap;
use http::HeaderValue;
use interceptor::registry::Registry;
use opus::Application;
use opus::Channels;
use opus::Decoder as OpusDecoder;
use opus::Encoder as OpusEncoder;
use opus_rs::Application;
use opus_rs::OpusDecoder;
use opus_rs::OpusEncoder;
use std::collections::HashMap;
use std::sync::Arc;
use std::sync::Mutex as StdMutex;
@@ -607,10 +606,7 @@ async fn connect_webrtc_transport(
"realtime WebRTC session connected"
);
let opus_encoder =
OpusEncoder::new(24_000, Channels::Mono, Application::Voip).map_err(|err| {
ApiError::Stream(format!("failed to initialize realtime Opus encoder: {err}"))
})?;
let opus_encoder = new_realtime_opus_encoder(Application::Voip)?;
Ok((
RealtimeWebRtcTransport {
@@ -742,7 +738,7 @@ async fn pump_remote_audio_track(
track: Arc<TrackRemote>,
tx_message: mpsc::UnboundedSender<Result<RealtimeTransportEvent, ApiError>>,
) {
let mut decoder = match OpusDecoder::new(24_000, Channels::Mono) {
let mut decoder = match new_realtime_opus_decoder() {
Ok(decoder) => decoder,
Err(err) => {
let _ = tx_message.send(Err(ApiError::Stream(format!(
@@ -751,7 +747,7 @@ async fn pump_remote_audio_track(
return;
}
};
let mut decoded = vec![0i16; OPUS_MAX_DECODED_SAMPLES_PER_CHANNEL];
let mut decoded = vec![0.0f32; OPUS_MAX_DECODED_SAMPLES_PER_CHANNEL];
loop {
let packet = match track.read_rtp().await {
@@ -767,9 +763,18 @@ async fn pump_remote_audio_track(
continue;
}
let samples_per_channel = match decoder.decode(&packet.payload, &mut decoded, false) {
let samples_per_channel = match decoder.decode(
&packet.payload,
OPUS_MAX_DECODED_SAMPLES_PER_CHANNEL,
&mut decoded,
) {
Ok(samples_per_channel) => samples_per_channel,
Err(err) => {
warn!(
%err,
payload_len = packet.payload.len(),
"failed to decode realtime Opus packet"
);
let _ = tx_message.send(Err(ApiError::Stream(format!(
"failed to decode realtime Opus packet: {err}"
))));
@@ -782,7 +787,7 @@ async fn pump_remote_audio_track(
let mut pcm_bytes = Vec::with_capacity(samples_per_channel * 2);
for sample in &decoded[..samples_per_channel] {
pcm_bytes.extend_from_slice(&sample.to_le_bytes());
pcm_bytes.extend_from_slice(&f32_to_i16(*sample).to_le_bytes());
}
let _ = tx_message.send(Ok(RealtimeTransportEvent::AudioOut(RealtimeAudioFrame {
data: BASE64_STANDARD.encode(pcm_bytes),
@@ -862,13 +867,24 @@ impl RealtimeInputAudioEncoder {
let mut samples = Vec::new();
while self.pending_samples.len() >= REALTIME_AUDIO_PACKET_SAMPLES {
let frame: Vec<f32> = self.pending_samples[..REALTIME_AUDIO_PACKET_SAMPLES]
.iter()
.copied()
.map(i16_to_f32)
.collect();
let encoded_len = self
.opus_encoder
.encode(
&self.pending_samples[..REALTIME_AUDIO_PACKET_SAMPLES],
&frame,
REALTIME_AUDIO_PACKET_SAMPLES,
&mut self.encoded_packet,
)
.map_err(|err| {
warn!(
%err,
pending_samples = self.pending_samples.len(),
"failed to encode realtime input Opus"
);
ApiError::Stream(format!("failed to encode realtime input Opus: {err}"))
})?;
self.pending_samples.drain(..REALTIME_AUDIO_PACKET_SAMPLES);
@@ -883,6 +899,52 @@ impl RealtimeInputAudioEncoder {
}
}
fn new_realtime_opus_encoder(application: Application) -> Result<OpusEncoder, ApiError> {
let encoder = OpusEncoder::new(24_000, usize::from(REALTIME_AUDIO_CHANNELS), application)
.map_err(|err| {
warn!(
%err,
sample_rate = 24_000,
channels = REALTIME_AUDIO_CHANNELS,
"failed to initialize realtime Opus encoder"
);
ApiError::Stream(format!("failed to initialize realtime Opus encoder: {err}"))
})?;
debug!(
sample_rate = 24_000,
channels = REALTIME_AUDIO_CHANNELS,
"initialized realtime Opus encoder"
);
Ok(encoder)
}
fn new_realtime_opus_decoder() -> Result<OpusDecoder, ApiError> {
let decoder =
OpusDecoder::new(24_000, usize::from(REALTIME_AUDIO_CHANNELS)).map_err(|err| {
warn!(
%err,
sample_rate = 24_000,
channels = REALTIME_AUDIO_CHANNELS,
"failed to initialize realtime Opus decoder"
);
ApiError::Stream(format!("failed to initialize realtime Opus decoder: {err}"))
})?;
debug!(
sample_rate = 24_000,
channels = REALTIME_AUDIO_CHANNELS,
"initialized realtime Opus decoder"
);
Ok(decoder)
}
fn i16_to_f32(sample: i16) -> f32 {
(sample as f32) / (i16::MAX as f32)
}
fn f32_to_i16(sample: f32) -> i16 {
(sample.clamp(-1.0, 1.0) * i16::MAX as f32) as i16
}
#[cfg(test)]
mod tests {
use super::*;
@@ -959,8 +1021,7 @@ mod tests {
#[test]
fn input_audio_encoder_rejects_non_mono_24khz_audio() {
let mut encoder = RealtimeInputAudioEncoder {
opus_encoder: OpusEncoder::new(24_000, Channels::Mono, Application::Audio)
.expect("encoder"),
opus_encoder: new_realtime_opus_encoder(Application::Audio).expect("encoder"),
pending_samples: Vec::new(),
encoded_packet: vec![0u8; OPUS_MAX_PACKET_BYTES],
};

View File

@@ -29,7 +29,7 @@ futures = { workspace = true }
notify = { workspace = true }
opentelemetry = { workspace = true }
opentelemetry_sdk = { workspace = true }
opus = { workspace = true }
opus-rs = { workspace = true }
regex-lite = { workspace = true }
serde_json = { workspace = true }
tempfile = { workspace = true }

View File

@@ -5,8 +5,7 @@ use std::time::Duration;
use base64::Engine;
use base64::engine::general_purpose::STANDARD as BASE64_STANDARD;
use opus::Channels;
use opus::Decoder as OpusDecoder;
use opus_rs::OpusDecoder;
use serde_json::Value;
use tokio::io::AsyncReadExt;
use tokio::io::AsyncWriteExt;
@@ -15,6 +14,8 @@ use tokio::sync::Notify;
use tokio::sync::mpsc;
use tokio::sync::oneshot;
use tokio::time::timeout;
use tracing::debug;
use tracing::warn;
use webrtc::api::APIBuilder;
use webrtc::api::interceptor_registry::register_default_interceptors;
use webrtc::api::media_engine::MediaEngine;
@@ -290,17 +291,34 @@ async fn pump_remote_audio_track(
track: Arc<TrackRemote>,
tx_request: mpsc::UnboundedSender<Value>,
) {
let Ok(mut decoder) = OpusDecoder::new(24_000, Channels::Mono) else {
return;
let mut decoder = match OpusDecoder::new(24_000, usize::from(REALTIME_AUDIO_CHANNELS)) {
Ok(decoder) => decoder,
Err(err) => {
warn!(%err, "failed to initialize realtime Opus decoder in test server");
return;
}
};
let mut decoded = vec![0i16; REALTIME_MAX_DECODED_SAMPLES_PER_CHANNEL];
debug!("initialized realtime Opus decoder in test server");
let mut decoded = vec![0.0f32; REALTIME_MAX_DECODED_SAMPLES_PER_CHANNEL];
while let Ok((packet, _)) = track.read_rtp().await {
if packet.payload.is_empty() {
continue;
}
let Ok(samples_per_channel) = decoder.decode(&packet.payload, &mut decoded, false) else {
return;
let samples_per_channel = match decoder.decode(
&packet.payload,
REALTIME_MAX_DECODED_SAMPLES_PER_CHANNEL,
&mut decoded,
) {
Ok(samples_per_channel) => samples_per_channel,
Err(err) => {
warn!(
%err,
payload_len = packet.payload.len(),
"failed to decode realtime Opus packet in test server"
);
return;
}
};
if samples_per_channel == 0 {
continue;
@@ -308,7 +326,7 @@ async fn pump_remote_audio_track(
let mut pcm_bytes = Vec::with_capacity(samples_per_channel * 2);
for sample in &decoded[..samples_per_channel] {
pcm_bytes.extend_from_slice(&sample.to_le_bytes());
pcm_bytes.extend_from_slice(&f32_to_i16(*sample).to_le_bytes());
}
let _ = tx_request.send(serde_json::json!({
"type": "input_audio_buffer.append",
@@ -320,6 +338,10 @@ async fn pump_remote_audio_track(
}
}
fn f32_to_i16(sample: f32) -> i16 {
(sample.clamp(-1.0, 1.0) * i16::MAX as f32) as i16
}
async fn serve_scripted_requests(
connection: WebSocketConnectionConfig,
connection_index: usize,

View File

@@ -4,7 +4,6 @@ exports_files([
"aws-lc-sys_windows_msvc_prebuilt_nasm.patch",
"aws-lc-sys_windows_msvc_memcmp_probe.patch",
"llvm_windows_symlink_extract.patch",
"opus_windows_gnullvm_stack_probe.patch",
"rules_rust_windows_bootstrap_process_wrapper_linker.patch",
"rules_rust_windows_build_script_runner_paths.patch",
"rules_rust_windows_exec_bin_target.patch",

View File

@@ -1,130 +0,0 @@
diff --git a/BUILD.bazel b/BUILD.bazel
--- a/BUILD.bazel
+++ b/BUILD.bazel
@@ -1,5 +1,5 @@
load("@rules_cc//cc:defs.bzl", "cc_library")
-load("//:defs.bzl", "AVX2_COPTS", "OPUS_COPTS", "OPUS_INCLUDES", "OPUS_LINKOPTS", "SSE2_COPTS", "SSE4_1_COPTS", "SSE_COPTS")
+load("//:defs.bzl", "AVX2_COPTS", "OPUS_COPTS", "OPUS_INCLUDES", "OPUS_LINKOPTS", "OPUS_X86_STACK_COPTS", "SSE2_COPTS", "SSE4_1_COPTS", "SSE_COPTS")
package(default_visibility = ["//:__subpackages__"])
@@ -76,7 +76,7 @@ cc_library(
"celt/x86/x86cpu.c",
"celt/x86/x86_celt_map.c",
] + INTERNAL_HEADERS,
- copts = OPUS_COPTS,
+ copts = OPUS_COPTS + OPUS_X86_STACK_COPTS,
includes = OPUS_INCLUDES,
deps = [
":config",
@@ -91,7 +91,7 @@ cc_library(
cc_library(
name = "celt_sse",
srcs = ["celt/x86/pitch_sse.c"] + INTERNAL_HEADERS,
- copts = OPUS_COPTS + SSE_COPTS,
+ copts = OPUS_COPTS + OPUS_X86_STACK_COPTS + SSE_COPTS,
includes = OPUS_INCLUDES,
deps = [
":config",
@@ -108,7 +108,7 @@ cc_library(
"celt/x86/pitch_sse2.c",
"celt/x86/vq_sse2.c",
] + INTERNAL_HEADERS,
- copts = OPUS_COPTS + SSE2_COPTS,
+ copts = OPUS_COPTS + OPUS_X86_STACK_COPTS + SSE2_COPTS,
includes = OPUS_INCLUDES,
deps = [
":config",
@@ -125,7 +125,7 @@ cc_library(
"celt/x86/celt_lpc_sse4_1.c",
"celt/x86/pitch_sse4_1.c",
] + INTERNAL_HEADERS,
- copts = OPUS_COPTS + SSE4_1_COPTS,
+ copts = OPUS_COPTS + OPUS_X86_STACK_COPTS + SSE4_1_COPTS,
includes = OPUS_INCLUDES,
deps = [
":config",
@@ -140,7 +140,7 @@ cc_library(
cc_library(
name = "celt_avx2",
srcs = ["celt/x86/pitch_avx.c"] + INTERNAL_HEADERS,
- copts = OPUS_COPTS + AVX2_COPTS,
+ copts = OPUS_COPTS + OPUS_X86_STACK_COPTS + AVX2_COPTS,
includes = OPUS_INCLUDES,
deps = [
":config",
@@ -184,7 +184,7 @@ cc_library(
cc_library(
name = "silk_x86_rtcd",
srcs = ["silk/x86/x86_silk_map.c"] + INTERNAL_HEADERS,
- copts = OPUS_COPTS,
+ copts = OPUS_COPTS + OPUS_X86_STACK_COPTS,
includes = OPUS_INCLUDES,
deps = [
":config",
@@ -201,7 +201,7 @@ cc_library(
"silk/x86/VAD_sse4_1.c",
"silk/x86/VQ_WMat_EC_sse4_1.c",
] + INTERNAL_HEADERS,
- copts = OPUS_COPTS + SSE4_1_COPTS,
+ copts = OPUS_COPTS + OPUS_X86_STACK_COPTS + SSE4_1_COPTS,
includes = OPUS_INCLUDES,
deps = [
":config",
@@ -219,7 +219,7 @@ cc_library(
"silk/x86/NSQ_del_dec_avx2.c",
"silk/float/x86/inner_product_FLP_avx2.c",
] + INTERNAL_HEADERS,
- copts = OPUS_COPTS + AVX2_COPTS,
+ copts = OPUS_COPTS + OPUS_X86_STACK_COPTS + AVX2_COPTS,
includes = OPUS_INCLUDES,
deps = [
":config",
@@ -258,6 +258,9 @@ cc_library(
"celt/mathops.c",
],
- copts = OPUS_COPTS,
+ copts = OPUS_COPTS + select({
+ "@platforms//cpu:x86_64": OPUS_X86_STACK_COPTS,
+ "//conditions:default": [],
+ }),
includes = OPUS_INCLUDES,
deps = [
":config",
@@ -373,7 +376,10 @@ cc_library(
"silk/float/schur_FLP.c",
"silk/float/sort_FLP.c",
] + glob(["silk/**/*.h"]),
- copts = OPUS_COPTS,
+ copts = OPUS_COPTS + select({
+ "@platforms//cpu:x86_64": OPUS_X86_STACK_COPTS,
+ "//conditions:default": [],
+ }),
includes = OPUS_INCLUDES,
deps = [
":celt",
@@ -419,6 +425,9 @@ cc_library(
"src/mlp_data.c",
] + glob(["src/*.h"]),
- copts = OPUS_COPTS,
+ copts = OPUS_COPTS + select({
+ "@platforms//cpu:x86_64": OPUS_X86_STACK_COPTS,
+ "//conditions:default": [],
+ }),
includes = ["include"],
deps = [
":celt",
diff --git a/defs.bzl b/defs.bzl
--- a/defs.bzl
+++ b/defs.bzl
@@ -1,4 +1,9 @@
-OPUS_COPTS = ["-std=gnu99"]
+OPUS_COPTS = [
+ "-fno-stack-protector",
+ "-std=gnu99",
+]
+
+OPUS_X86_STACK_COPTS = ["-mno-stack-arg-probe"]
OPUS_INCLUDES = [
"include",