review-case

star 343

Structured code review for a case in the APIExample-Audio project. Checks engine lifecycle, audio-only constraints, thread safety, permissions, and API correctness. This project uses AgoraAudio_iOS — video APIs must not appear.

AgoraIO By AgoraIO schedule Updated 3/5/2026

name: review-case description: > Structured code review for a case in the APIExample-Audio project. Checks engine lifecycle, audio-only constraints, thread safety, permissions, and API correctness. This project uses AgoraAudio_iOS — video APIs must not appear. compatibility: [Cursor, Kiro, Windsurf, Claude, Copilot] license: MIT metadata: author: APIExample Team version: 1.0.0 platform: iOS

review-case — APIExample-Audio

Review Dimensions (in priority order)

1. Audio-Only Constraint (highest priority for this project)

Check:

  • No calls to enableVideo(), disableVideo(), setupLocalVideo(), setupRemoteVideo(), startPreview(), stopPreview()
  • No AgoraRtcVideoCanvas instantiation
  • No VideoView or video rendering views in storyboard or code
  • No camera permission requests

Any video API call in this project is a critical error — the SDK will crash or silently fail.


2. Engine Lifecycle

Check:

  • AgoraRtcEngineKit.sharedEngine(with:delegate:) called in viewDidLoad (not in Entry VC)
  • leaveChannel() + AgoraRtcEngineKit.destroy() called in willMove(toParent:) when parent == nil
  • No engine instance stored beyond the Main VC's lifetime

Correct:

override func willMove(toParent parent: UIViewController?) {
    super.willMove(toParent: parent)
    if parent == nil {
        agoraKit?.leaveChannel()
        AgoraRtcEngineKit.destroy()
    }
}

3. Thread Safety

All AgoraRtcEngineDelegate callbacks may arrive on a background thread.

Check:

  • Every UI update inside a delegate callback is wrapped in DispatchQueue.main.async { }
  • No UIKit objects mutated directly in callbacks

4. Permissions

Check:

  • Microphone permission requested before joinChannel()
  • joinChannel() called only inside the permission grant callback
  • No camera permission requests (audio-only project)

5. Error Handling

Check:

  • Return value of joinChannel() checked
  • rtcEngine(_:didOccurError:) implemented and logged
  • Token expiry handled if token is used

6. Code Conventions

Check:

  • Entry class inherits UIViewController, Main class inherits BaseViewController
  • Class names follow <ExampleName>Entry / <ExampleName>Main pattern
  • configs dictionary used to pass data from Entry to Main
  • File placed under Examples/Basic/ or Examples/Advanced/ matching the MenuItem section
  • Storyboard contains only audio controls (labels, sliders, buttons) — no video views

7. Audio API Usage

Check:

  • setAudioProfile(_:) called before joinChannel() if non-default profile needed
  • setAudioScenario(_:) called before joinChannel() if non-default scenario needed
  • enableAudioVolumeIndication(_:smooth:reportVad:) called if volume callbacks are needed
  • Custom audio tracks stopped and released on exit
  • External audio sinks disabled on exit if enableExternalAudioSink was called

8. Resource Cleanup

Check:

  • Audio mixing stopped (stopAudioMixing()) if started
  • Rhythm player stopped (stopRhythmPlayer()) if started
  • Echo test stopped (stopEchoTest()) if started
  • Last-mile probe stopped (stopLastmileProbeTest()) if started
  • Custom audio tracks destroyed on exit

Review Output Format

[SEVERITY] file/line — issue description
Suggestion: how to fix

Severity levels:

  • [CRITICAL] — crash, leak, video API in audio-only project, or incorrect behavior
  • [WARNING] — convention violation or subtle bug risk
  • [INFO] — style or minor improvement

Audio-Specific iOS Checks

  • AVAudioSession category should be .playAndRecord with .defaultToSpeaker option for most audio cases
  • Background audio: verify UIBackgroundModes includes audio in Info.plist if background playback is needed
  • In-ear monitoring (enable(inEarMonitoring:)) only works with wired headphones — document this limitation in the case if relevant
  • [weak self] required in all closures capturing self to avoid retain cycles
Install via CLI
npx skills add https://github.com/AgoraIO/API-Examples --skill review-case
Repository Details
star Stars 343
call_split Forks 229
navigation Branch main
article Path SKILL.md
More from Creator