-
-
Notifications
You must be signed in to change notification settings - Fork 91
fix: play recording sounds regardless of mute system audio setting #112
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -95,50 +95,29 @@ class IOBridge: NSObject { | |||||||||||||||||||||||||||
| case .muteSystemAudio: | ||||||||||||||||||||||||||||
| logToStderr("[IOBridge] Handling muteSystemAudio for ID: \(request.id)") | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| audioService.playSound(named: "rec-start") { [weak self] in | ||||||||||||||||||||||||||||
| guard let self = self else { | ||||||||||||||||||||||||||||
| HelperLogger.logToStderr( | ||||||||||||||||||||||||||||
| "[IOBridge] self is nil in playSound completion for muteSystemAudio. ID: \(request.id)" | ||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| let muteSuccess = accessibilityService.muteSystemAudio() | ||||||||||||||||||||||||||||
| let muteResultPayload = MuteSystemAudioResultSchema( | ||||||||||||||||||||||||||||
| message: muteSuccess ? "Mute command sent" : "Failed to send mute command", | ||||||||||||||||||||||||||||
| success: muteSuccess) | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| self.logToStderr( | ||||||||||||||||||||||||||||
| "[IOBridge] rec-start.mp3 finished playing successfully. Proceeding to mute system audio. ID: \(request.id)" | ||||||||||||||||||||||||||||
| do { | ||||||||||||||||||||||||||||
| let resultData = try jsonEncoder.encode(muteResultPayload) | ||||||||||||||||||||||||||||
| let resultAsJsonAny = try jsonDecoder.decode(JSONAny.self, from: resultData) | ||||||||||||||||||||||||||||
| rpcResponse = RPCResponseSchema(error: nil, id: request.id, result: resultAsJsonAny) | ||||||||||||||||||||||||||||
| } catch { | ||||||||||||||||||||||||||||
| logToStderr( | ||||||||||||||||||||||||||||
| "[IOBridge] Error encoding muteSystemAudio result: \(error.localizedDescription) for ID: \(request.id)" | ||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||
| let success = self.accessibilityService.muteSystemAudio() | ||||||||||||||||||||||||||||
| let resultPayload = MuteSystemAudioResultSchema( | ||||||||||||||||||||||||||||
| message: success ? "Mute command sent" : "Failed to send mute command", | ||||||||||||||||||||||||||||
| success: success) | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| var responseToSend: RPCResponseSchema | ||||||||||||||||||||||||||||
| do { | ||||||||||||||||||||||||||||
| let resultData = try self.jsonEncoder.encode(resultPayload) | ||||||||||||||||||||||||||||
| let resultAsJsonAny = try self.jsonDecoder.decode( | ||||||||||||||||||||||||||||
| JSONAny.self, from: resultData) | ||||||||||||||||||||||||||||
| responseToSend = RPCResponseSchema( | ||||||||||||||||||||||||||||
| error: nil, id: request.id, result: resultAsJsonAny) | ||||||||||||||||||||||||||||
| } catch { | ||||||||||||||||||||||||||||
| self.logToStderr( | ||||||||||||||||||||||||||||
| "[IOBridge] Error encoding muteSystemAudio result: \(error.localizedDescription) for ID: \(request.id)" | ||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||
| let errPayload = Error( | ||||||||||||||||||||||||||||
| code: -32603, data: nil, | ||||||||||||||||||||||||||||
| message: "Error encoding result: \(error.localizedDescription)") | ||||||||||||||||||||||||||||
| responseToSend = RPCResponseSchema( | ||||||||||||||||||||||||||||
| error: errPayload, id: request.id, result: nil) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| self.sendRpcResponse(responseToSend) | ||||||||||||||||||||||||||||
| let errPayload = Error( | ||||||||||||||||||||||||||||
| code: -32603, data: nil, | ||||||||||||||||||||||||||||
| message: "Error encoding result: \(error.localizedDescription)") | ||||||||||||||||||||||||||||
| rpcResponse = RPCResponseSchema(error: errPayload, id: request.id, result: nil) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| case .restoreSystemAudio: | ||||||||||||||||||||||||||||
| logToStderr("[IOBridge] Handling restoreSystemAudio for ID: \(request.id)") | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| let success = accessibilityService.restoreSystemAudio() | ||||||||||||||||||||||||||||
| if success { // Play sound only if restore was successful | ||||||||||||||||||||||||||||
| audioService.playSound(named: "rec-stop") | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| let resultPayload = RestoreSystemAudioResultSchema( | ||||||||||||||||||||||||||||
| message: success ? "Restore command sent" : "Failed to send restore command", | ||||||||||||||||||||||||||||
| success: success) | ||||||||||||||||||||||||||||
|
|
@@ -230,6 +209,44 @@ class IOBridge: NSObject { | |||||||||||||||||||||||||||
| rpcResponse = RPCResponseSchema(error: errPayload, id: request.id, result: nil) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| case .playSound: | ||||||||||||||||||||||||||||
| logToStderr("[IOBridge] Handling playSound for ID: \(request.id)") | ||||||||||||||||||||||||||||
| guard let paramsAnyCodable = request.params else { | ||||||||||||||||||||||||||||
| let errPayload = Error( | ||||||||||||||||||||||||||||
| code: -32602, data: nil, message: "Missing params for playSound") | ||||||||||||||||||||||||||||
| rpcResponse = RPCResponseSchema(error: errPayload, id: request.id, result: nil) | ||||||||||||||||||||||||||||
| sendRpcResponse(rpcResponse) | ||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| do { | ||||||||||||||||||||||||||||
| let paramsData = try jsonEncoder.encode(paramsAnyCodable) | ||||||||||||||||||||||||||||
| let playSoundParams = try jsonDecoder.decode( | ||||||||||||||||||||||||||||
| PlaySoundParamsSchema.self, from: paramsData) | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| 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 | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
Comment on lines
+227
to
+232
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do not drop the RPC response when At Line [228], the nil-self branch returns without 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
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||
| self.sendResult( | ||||||||||||||||||||||||||||
| id: request.id, | ||||||||||||||||||||||||||||
| result: PlaySoundResultSchema( | ||||||||||||||||||||||||||||
| message: success ? "Sound playback completed" : "Sound playback failed", | ||||||||||||||||||||||||||||
| success: success)) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||
| } catch { | ||||||||||||||||||||||||||||
| logToStderr( | ||||||||||||||||||||||||||||
| "[IOBridge] Error processing playSound params: \(error.localizedDescription) for ID: \(request.id)" | ||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||
| let errPayload = Error( | ||||||||||||||||||||||||||||
| code: -32602, data: request.params, | ||||||||||||||||||||||||||||
| message: "Invalid params: \(error.localizedDescription)") | ||||||||||||||||||||||||||||
| rpcResponse = RPCResponseSchema(error: errPayload, id: request.id, result: nil) | ||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| default: | ||||||||||||||||||||||||||||
| logToStderr("[IOBridge] Method not found: \(request.method) for ID: \(request.id)") | ||||||||||||||||||||||||||||
| let errPayload = Error( | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| import { z } from "zod"; | ||
|
|
||
| // Request params | ||
| export const PlaySoundParamsSchema = z.object({ | ||
| sound: z.enum(["rec-start", "rec-stop"]), | ||
| }); | ||
| export type PlaySoundParams = z.infer<typeof PlaySoundParamsSchema>; | ||
|
|
||
| // Response result | ||
| export const PlaySoundResultSchema = z.object({ | ||
| success: z.boolean(), | ||
| message: z.string().optional(), | ||
| }); | ||
| export type PlaySoundResult = z.infer<typeof PlaySoundResultSchema>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Handle
playSoundbusiness 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
Also applies to: 381-387
🤖 Prompt for AI Agents