Skip to content

feat: iOS AVS calling support [WPB-24959]#4130

Open
Garzas wants to merge 6 commits into
developfrom
feat/ios-avs-calling-support
Open

feat: iOS AVS calling support [WPB-24959]#4130
Garzas wants to merge 6 commits into
developfrom
feat/ios-avs-calling-support

Conversation

@Garzas
Copy link
Copy Markdown
Contributor

@Garzas Garzas commented May 12, 2026

https://wearezeta.atlassian.net/browse/WPB-24959


PR Submission Checklist for internal contributors

  • The PR Title

    • conforms to the style of semantic commits messages¹ supported in Wire's Github Workflow²
    • contains a reference JIRA issue number like SQPIT-764
    • answers the question: If merged, this PR will: ... ³
  • The PR Description

    • is free of optional paragraphs and you have filled the relevant parts to the best of your ability

What's new in this PR?

Issues

  • Adds iOS AVS calling support in Kalium’s Apple calling implementation.
  • Enables iOS call signaling and call control paths that were previously no-op on Apple targets.
  • Adds iOS video-related AVS flow manager plumbing.
  • Wires avs-kmp only into iOS source sets to avoid resolving unavailable macOS variants.

Causes (Optional)

Apple calling code was still using placeholder/no-op implementations for call manager, media manager, and flow manager paths. Adding avs-kmp at the wider Apple source set level also caused KMP variant resolution to request macOS artifacts, while the current AVS KMP artifact is iOS-only.

Solutions

  • Added AppleAvsInterop to bridge Kalium’s Apple calling code to AVS KMP / AVS C APIs.
  • Replaced the Apple no-op CallManagerImpl with a real implementation for:
    • incoming signaling message handling
    • start / answer / reject / end call
    • mute state
    • video send state
    • remote video stream requests
    • MLS epoch updates
    • conversation clients updates
    • background / notification / network quality reporting
  • Updated GlobalCallManager on Apple to create real CallManagerImpl, FlowManagerServiceImpl, and MediaManagerServiceImpl instances.
  • Updated Apple FlowManagerServiceImpl to start AVS media/flow managers, attach iOS video views, and switch camera capture device.
  • Extended Apple PlatformView to carry a UIView? for AVS video attachment.
  • Added avs-kmp dependency alias and scoped it to ios*Main source sets only, avoiding unsupported macOS variant resolution.

Notes

  • This PR wires the Kalium-side iOS AVS call control path, but full end-to-end video rendering still requires iOS UI integration that provides and manages native UIView instances for AVS video preview/rendering.
  • iOS speaker routing is still not implemented in MediaManagerServiceImpl; speaker state currently remains a no-op/false path.
  • Video view lifecycle still needs follow-up validation/cleanup handling for attach/detach, call teardown, rejoin, and background/foreground transitions.
  • UI rotation is not wired because the current AVS KMP AVSFlowManager API does not expose the equivalent operation.
  • avs-kmp is scoped to iOS source sets only because the current artifact does not publish macOS variants.

@Garzas Garzas self-assigned this May 12, 2026
@Garzas Garzas requested a review from a team as a code owner May 12, 2026 10:35
@Garzas Garzas requested review from emmaoke-w, ohassine, saleniuk, typfel and yamilmedina and removed request for a team May 12, 2026 10:35
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 12, 2026

Test Results

0 tests   - 4 911   0 ✅  - 4 796   0s ⏱️ - 3m 6s
0 suites  -   806   0 💤  -   115 
0 files    -   806   0 ❌ ±    0 

Results for commit 15bc414. ± Comparison against base commit 86391e2.

♻️ This comment has been updated with latest results.

@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented May 12, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 61.55%. Comparing base (86391e2) to head (15bc414).

Additional details and impacted files
@@            Coverage Diff             @@
##             develop    #4130   +/-   ##
==========================================
  Coverage      61.55%   61.55%           
  Complexity      4022     4022           
==========================================
  Files           2068     2068           
  Lines          67436    67436           
  Branches        6651     6651           
==========================================
  Hits           41513    41513           
  Misses         23277    23277           
  Partials        2646     2646           

Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 86391e2...15bc414. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 12, 2026

🐰 Bencher Report

Branchfeat/ios-avs-calling-support
Testbedubuntu-latest

⚠️ WARNING: No Threshold found!

Without a Threshold, no Alerts will ever be generated.

Click here to create a new Threshold
For more information, see the Threshold documentation.
To only post results if a Threshold exists, set the --ci-only-thresholds flag.

Click to view all benchmark results
BenchmarkLatencymicroseconds (µs)
com.wire.kalium.benchmarks.logic.CoreLogicBenchmark.createObjectInFiles📈 view plot
⚠️ NO THRESHOLD
896.90 µs
com.wire.kalium.benchmarks.logic.CoreLogicBenchmark.createObjectInMemory📈 view plot
⚠️ NO THRESHOLD
342,544.91 µs
com.wire.kalium.benchmarks.persistence.MessageReadBenchmark.inboxPagingDeepPageBenchmark📈 view plot
⚠️ NO THRESHOLD
127,403.31 µs
com.wire.kalium.benchmarks.persistence.MessageReadBenchmark.inboxPagingFirstPageBenchmark📈 view plot
⚠️ NO THRESHOLD
122,187.75 µs
com.wire.kalium.benchmarks.persistence.MessageReadBenchmark.localMarkAsReadBenchmark📈 view plot
⚠️ NO THRESHOLD
3,207.96 µs
com.wire.kalium.benchmarks.persistence.MessageReadBenchmark.messagePagingDeepPageBenchmark📈 view plot
⚠️ NO THRESHOLD
27,176.45 µs
com.wire.kalium.benchmarks.persistence.MessageReadBenchmark.messagePagingFirstPageBenchmark📈 view plot
⚠️ NO THRESHOLD
11,204.77 µs
com.wire.kalium.benchmarks.persistence.MessagesNoPragmaTuneBenchmark.messageInsertionBenchmark📈 view plot
⚠️ NO THRESHOLD
1,246,372.01 µs
com.wire.kalium.benchmarks.persistence.MessagesNoPragmaTuneBenchmark.queryMessagesBenchmark📈 view plot
⚠️ NO THRESHOLD
20,047.28 µs
🐰 View full continuous benchmarking report in Bencher

Copy link
Copy Markdown
Contributor

@saleniuk saleniuk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a few (possibly silly) questions 🙇

Comment on lines +68 to +74
matching { sourceSet ->
sourceSet.name.startsWith("ios") && sourceSet.name.endsWith("Main")
}.all {
dependencies {
api(libs.avsKmp)
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we use the same approach as for other platforms?
Something like:

val iosMain by getting {
    dependencies {
        api(libs.avsKmp)
    }
}

Comment thread gradle/libs.versions.toml

# avs
avs = { module = "com.wire:avs", version.ref = "avs" }
avsKmp = { module = "com.wire:avs-kmp", version.ref = "avs" }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't be better to separate the version numbers for regular and kmp?

}

fun notifyNetworkChangedIfAvailable(): Boolean {
if (!startIfAvailable()) return false
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why only some functions are secured by this if (!startIfAvailable()) return false?
Others, like setNetworkQualityInterval can still be called before it's started and fail in that case, right?
Is it because some of them are called inside the withCalling block? So maybe either we should secure all of them just to be sure or maybe we should make it so that they are all scoped and can be called only inside the withCalling block?

import kotlin.uuid.Uuid

@Suppress("LongParameterList", "TooManyFunctions")
internal class CallManagerImpl internal constructor(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it basically almost 1:1 copy of JvmAndroid's CallManagerImpl? It will take quite a bit more work to maintain them separately and make sure they stay consistent, so would it be possible to extract the common code and reuse it?

@sonarqubecloud
Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants