ios: default in-call audio to the loudspeaker (AVAudioSession) at build time

Calls were routing to the quiet earpiece. ios-patch.sh now runs a Node helper (Node 20 is
already in the build env) that injects an AVAudioSession .playAndRecord/.voiceChat category with
.defaultToSpeaker + Bluetooth into the generated AppDelegate. Tolerant: exits 0 and no-ops if the
template differs, so it can never fail the Codemagic build. Verified locally against the Cap 7
AppDelegate template — injects correctly and is idempotent. First pass; if WebRTC re-grabs the
session mid-call on device, a follow-up plugin will re-assert .overrideOutputAudioPort(.speaker).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-19 16:18:52 +05:30
parent f2b965bd3d
commit 134cb8999d
2 changed files with 48 additions and 0 deletions
+12
View File
@@ -38,6 +38,18 @@ set_str CFBundleVersion "$BUILD_NO"
# Allow the webview to load our HTTPS origin (we do NOT enable arbitrary cleartext).
"$PB" -c "Delete :NSAppTransportSecurity" "$PLIST" 2>/dev/null || true
# ── Default in-call audio to the LOUDSPEAKER (AVAudioSession) ──────────────────────────────────────
# Without this, iOS routes WebRTC call audio to the quiet EARPIECE. A Node helper (Node 20 is already set
# up for this build) injects an AVAudioSession category into the generated AppDelegate so calls default to
# the speaker (headphones/Bluetooth still win when connected). The helper is tolerant and exits 0 even if
# the template differs, so it NEVER fails the build. First-pass fix — if WebRTC re-grabs the session
# mid-call on device, we follow up with a plugin that re-asserts .overrideOutputAudioPort(.speaker).
AD="mobile/ios/App/App/AppDelegate.swift"
if [ -f "$AD" ]; then
echo "Patching AppDelegate audio session"
node "$(dirname "$0")/inject-audio.js" "$AD" || echo " (AVAudioSession patch skipped — non-fatal)"
fi
echo "Info.plist patched:"
"$PB" -c "Print :NSCameraUsageDescription" "$PLIST"
"$PB" -c "Print :NSMicrophoneUsageDescription" "$PLIST"