Skip to content

fix: play recording sounds regardless of mute system audio setting#112

Closed
Mgtantheta wants to merge 1 commit intoamicalhq:mainfrom
Mgtantheta:feature/fix-105
Closed

fix: play recording sounds regardless of mute system audio setting#112
Mgtantheta wants to merge 1 commit intoamicalhq:mainfrom
Mgtantheta:feature/fix-105

Conversation

@Mgtantheta
Copy link
Contributor

@Mgtantheta Mgtantheta commented Mar 1, 2026

Summary

  • Introduce a dedicated playSound RPC method, decoupling sound playback from muteSystemAudio / restoreSystemAudio
  • Recording start/stop chimes now play unconditionally, regardless of the "Mute system audio" setting
  • rec-start is awaited before muting so the chime isn't cut off; rec-stop is fire-and-forget

Additional fixes

  • AudioService: completion handler is now always called (even on playback failure/interruption), preventing RPC requests from hanging
  • AudioService: completion handler signature changed to (Bool) -> Void so callers receive accurate success/failure status
  • NativeBridge: playSound log level changed from INFO to DEBUG (less critical than audio routing operations)

Closes #105

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Recording sessions now include audio feedback with distinct sounds for start and stop events.
    • System ensures audio feedback completes before applying mute settings.

Decouple sound playback from muteSystemAudio/restoreSystemAudio by
introducing a dedicated playSound RPC method. Sounds now play
unconditionally on recording start/stop, fixing the regression where
chimes were silenced when "Mute system audio" was disabled.

Also fix AudioService to always invoke the completion handler (even on
failure/interruption) and propagate playback success via a Bool flag.

Closes amicalhq#105

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Mar 1, 2026

📝 Walkthrough

Walkthrough

Introduces a new playSound RPC method that enables recording start/stop sound effects independent of the "Mute system audio" setting. Changes span the desktop manager, native bridge, RPC infrastructure, and Swift audio service implementation, with completion callbacks added to track sound playback success.

Changes

Cohort / File(s) Summary
Recording Manager Integration
apps/desktop/src/main/managers/recording-manager.ts
Integrates playSound calls to play rec-start sound before muting (if enabled) and rec-stop sound after restoring audio, with error handling and await/fire-and-forget patterns.
RPC Type & Schema Definitions
packages/types/src/schemas/methods/play-sound.ts, packages/types/src/schemas/rpc/request.ts, packages/types/src/index.ts
Adds PlaySoundParamsSchema and PlaySoundResultSchema with zod validation; defines sound parameter as enum ("rec-start", "rec-stop"); exports playSound as an allowed RPC method name.
RPC Service Registration
apps/desktop/src/services/platform/native-bridge-service.ts
Registers playSound method in RPCMethods interface with PlaySoundParams/PlaySoundResult types; adds playSound entry to RPC_RESULT_SCHEMAS mapping.
Swift Audio & RPC Handler
packages/native-helpers/swift-helper/Sources/SwiftHelper/AudioService.swift, packages/native-helpers/swift-helper/Sources/SwiftHelper/RpcHandler.swift
Enhances AudioService.playSound() to accept completion handler with boolean success flag; reworkes error paths to immediately invoke completion(false); adds playSound RPC case to dispatch requests, validate params, and send structured PlaySoundResult responses. Refactors muteSystemAudio to remove dependent audio completion flow.

Sequence Diagram

sequenceDiagram
    participant RM as Recording Manager
    participant NB as Native Bridge
    participant RH as RPC Handler
    participant AS as Audio Service
    
    RM->>NB: playSound("rec-start")
    NB->>RH: RPC dispatch playSound
    RH->>RH: Validate & decode params
    RH->>AS: playSound(named: "rec-start")
    AS->>AS: Load & play audio
    AS-->>RH: completion(success: Bool)
    RH-->>NB: Send PlaySoundResult
    NB-->>RM: Result received
    
    Note over RM,AS: Recording completes...
    
    RM->>NB: playSound("rec-stop")
    NB->>RH: RPC dispatch playSound
    RH->>AS: playSound(named: "rec-stop")
    AS->>AS: Load & play audio
    AS-->>RH: completion(success: Bool)
    RH-->>NB: Send PlaySoundResult
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • haritabh-z01

Poem

🐰 Ding-dong! The rec sounds hop and play,
Through RPC paths, completion finds its way,
No muting can stop the cheer,
Swift audio—independent and clear! 🎵

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: play recording sounds regardless of mute system audio setting' directly and accurately summarizes the primary change: decoupling recording sound playback from the mute system audio setting.
Linked Issues check ✅ Passed The implementation fully addresses issue #105 by introducing a dedicated playSound RPC method and ensuring recording start/stop chimes play independently of the mute system audio setting.
Out of Scope Changes check ✅ Passed All changes directly support the core objective of decoupling recording sounds from mute settings. AudioService signature changes and completion handler improvements are necessary implementation details to prevent hanging RPC requests.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/desktop/src/main/managers/recording-manager.ts`:
- Around line 304-309: The nativeBridge.call("playSound", { sound: "rec-start"
}) invocation currently only catches rejected promises but ignores resolved
responses where playback failed (response.success === false); update the await
calls in RecordingManager (the rec-start playback and the later playSound usage)
to inspect the returned value, and if the response exists and has success ===
false, log a warning via logger.audio.warn (including the response/error
details) and treat it as a failure path (e.g., do not proceed to mute or
continue as if sound played); ensure both call sites that invoke playSound check
the response.success flag and handle/log accordingly.

In `@packages/native-helpers/swift-helper/Sources/SwiftHelper/RpcHandler.swift`:
- Around line 227-232: The completion handler for audioService.playSound in
RpcHandler.swift currently returns early when self is nil and thereby never
responds to the RPC; modify the nil-self branch to send a failure RPC response
(e.g., call sendError or sendResult with an error) using the request.id so the
caller is notified instead of hanging. Locate the closure passed to
audioService.playSound (the block capturing [weak self]) and ensure that when
guard let self fails you call the RpcHandler's response helper
(sendError/sendResult) with a descriptive message including request.id before
returning.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c847c35 and 4b75d0c.

📒 Files selected for processing (7)
  • apps/desktop/src/main/managers/recording-manager.ts
  • apps/desktop/src/services/platform/native-bridge-service.ts
  • packages/native-helpers/swift-helper/Sources/SwiftHelper/AudioService.swift
  • packages/native-helpers/swift-helper/Sources/SwiftHelper/RpcHandler.swift
  • packages/types/src/index.ts
  • packages/types/src/schemas/methods/play-sound.ts
  • packages/types/src/schemas/rpc/request.ts

Comment on lines +304 to +309
// Always play rec-start sound, await completion before muting (so chime isn't cut off)
try {
await nativeBridge.call("playSound", { sound: "rec-start" });
} catch (error) {
logger.audio.warn("Failed to play rec-start sound", { error });
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Handle playSound business failures (success: false) explicitly.

At Line [306] and Line [384], the call can resolve successfully while playback still fails (success: false). Today only rejected promises are logged, so silent playback failures are missed.

Suggested patch
-      try {
-        await nativeBridge.call("playSound", { sound: "rec-start" });
+      try {
+        const startSound = await nativeBridge.call("playSound", {
+          sound: "rec-start",
+        });
+        if (!startSound.success) {
+          logger.audio.warn("rec-start playback reported failure", {
+            message: startSound.message,
+          });
+        }
       } catch (error) {
         logger.audio.warn("Failed to play rec-start sound", { error });
       }
@@
       this.serviceManager
         .getService("nativeBridge")
         .call("playSound", { sound: "rec-stop" })
+        .then((stopSound) => {
+          if (!stopSound.success) {
+            logger.audio.warn("rec-stop playback reported failure", {
+              message: stopSound.message,
+            });
+          }
+        })
         .catch((error) => {
           logger.audio.warn("Failed to play rec-stop sound", { error });
         });

Also applies to: 381-387

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/main/managers/recording-manager.ts` around lines 304 - 309,
The nativeBridge.call("playSound", { sound: "rec-start" }) invocation currently
only catches rejected promises but ignores resolved responses where playback
failed (response.success === false); update the await calls in RecordingManager
(the rec-start playback and the later playSound usage) to inspect the returned
value, and if the response exists and has success === false, log a warning via
logger.audio.warn (including the response/error details) and treat it as a
failure path (e.g., do not proceed to mute or continue as if sound played);
ensure both call sites that invoke playSound check the response.success flag and
handle/log accordingly.

Comment on lines +227 to +232
audioService.playSound(named: playSoundParams.sound) { [weak self] success in
guard let self = self else {
HelperLogger.logToStderr(
"[IOBridge] self is nil in playSound completion. ID: \(request.id)")
return
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Do not drop the RPC response when self is nil in playSound completion.

At Line [228], the nil-self branch returns without sendResult/sendError, so the request can hang until timeout.

Suggested patch
-                audioService.playSound(named: playSoundParams.sound) { [weak self] success in
-                    guard let self = self else {
-                        HelperLogger.logToStderr(
-                            "[IOBridge] self is nil in playSound completion. ID: \(request.id)")
-                        return
-                    }
-                    self.sendResult(
+                audioService.playSound(named: playSoundParams.sound) { success in
+                    self.sendResult(
                         id: request.id,
                         result: PlaySoundResultSchema(
                             message: success ? "Sound playback completed" : "Sound playback failed",
                             success: success))
                 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
audioService.playSound(named: playSoundParams.sound) { [weak self] success in
guard let self = self else {
HelperLogger.logToStderr(
"[IOBridge] self is nil in playSound completion. ID: \(request.id)")
return
}
audioService.playSound(named: playSoundParams.sound) { success in
self.sendResult(
id: request.id,
result: PlaySoundResultSchema(
message: success ? "Sound playback completed" : "Sound playback failed",
success: success))
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/native-helpers/swift-helper/Sources/SwiftHelper/RpcHandler.swift`
around lines 227 - 232, The completion handler for audioService.playSound in
RpcHandler.swift currently returns early when self is nil and thereby never
responds to the RPC; modify the nil-self branch to send a failure RPC response
(e.g., call sendError or sendResult with an error) using the request.id so the
caller is notified instead of hanging. Locate the closure passed to
audioService.playSound (the block capturing [weak self]) and ensure that when
guard let self fails you call the RpcHandler's response helper
(sendError/sendResult) with a descriptive message including request.id before
returning.

@Mgtantheta Mgtantheta closed this Mar 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Keep recording start/stop sound effects active even when "Mute system audio" is disabled

1 participant