mirror of
https://github.com/pacnpal/Roo-Code.git
synced 2025-12-22 13:21:07 -05:00
Play sound effects for notifications and events (#38)
Co-authored-by: HeavenOSK <heavenosk@gmail.com>
This commit is contained in:
@@ -20,6 +20,7 @@ import { Cline } from "../Cline"
|
||||
import { openMention } from "../mentions"
|
||||
import { getNonce } from "./getNonce"
|
||||
import { getUri } from "./getUri"
|
||||
import { playSound, setSoundEnabled } from "../../utils/sound"
|
||||
|
||||
/*
|
||||
https://github.com/microsoft/vscode-webview-ui-toolkit-samples/blob/main/default/weather-webview/src/providers/WeatherViewProvider.ts
|
||||
@@ -61,6 +62,7 @@ type GlobalStateKey =
|
||||
| "openRouterModelId"
|
||||
| "openRouterModelInfo"
|
||||
| "allowedCommands"
|
||||
| "soundEnabled"
|
||||
|
||||
export const GlobalFileNames = {
|
||||
apiConversationHistory: "api_conversation_history.json",
|
||||
@@ -520,6 +522,18 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
||||
break;
|
||||
// Add more switch case statements here as more webview message commands
|
||||
// are created within the webview context (i.e. inside media/main.js)
|
||||
case "playSound":
|
||||
if (message.audioType) {
|
||||
const soundPath = path.join(this.context.extensionPath, "audio", `${message.audioType}.wav`)
|
||||
playSound(soundPath)
|
||||
}
|
||||
break
|
||||
case "soundEnabled":
|
||||
const enabled = message.bool ?? true
|
||||
await this.updateGlobalState("soundEnabled", enabled)
|
||||
setSoundEnabled(enabled)
|
||||
await this.postStateToWebview()
|
||||
break
|
||||
}
|
||||
},
|
||||
null,
|
||||
@@ -825,6 +839,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
||||
alwaysAllowWrite,
|
||||
alwaysAllowExecute,
|
||||
alwaysAllowBrowser,
|
||||
soundEnabled,
|
||||
taskHistory,
|
||||
} = await this.getState()
|
||||
|
||||
@@ -845,6 +860,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
||||
taskHistory: (taskHistory || [])
|
||||
.filter((item) => item.ts && item.task)
|
||||
.sort((a, b) => b.ts - a.ts),
|
||||
soundEnabled: soundEnabled ?? true,
|
||||
shouldShowAnnouncement: lastShownAnnouncementId !== this.latestAnnouncementId,
|
||||
allowedCommands,
|
||||
}
|
||||
@@ -935,6 +951,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
||||
alwaysAllowBrowser,
|
||||
taskHistory,
|
||||
allowedCommands,
|
||||
soundEnabled,
|
||||
] = await Promise.all([
|
||||
this.getGlobalState("apiProvider") as Promise<ApiProvider | undefined>,
|
||||
this.getGlobalState("apiModelId") as Promise<string | undefined>,
|
||||
@@ -968,6 +985,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
||||
this.getGlobalState("alwaysAllowBrowser") as Promise<boolean | undefined>,
|
||||
this.getGlobalState("taskHistory") as Promise<HistoryItem[] | undefined>,
|
||||
this.getGlobalState("allowedCommands") as Promise<string[] | undefined>,
|
||||
this.getGlobalState("soundEnabled") as Promise<boolean | undefined>,
|
||||
])
|
||||
|
||||
let apiProvider: ApiProvider
|
||||
@@ -1019,6 +1037,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
||||
alwaysAllowBrowser: alwaysAllowBrowser ?? false,
|
||||
taskHistory,
|
||||
allowedCommands,
|
||||
soundEnabled,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ export interface ExtensionState {
|
||||
alwaysAllowBrowser?: boolean
|
||||
uriScheme?: string
|
||||
allowedCommands?: string[]
|
||||
soundEnabled?: boolean
|
||||
}
|
||||
|
||||
export interface ClineMessage {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { ApiConfiguration, ApiProvider } from "./api"
|
||||
|
||||
export type AudioType = "notification" | "celebration" | "progress_loop"
|
||||
|
||||
export interface WebviewMessage {
|
||||
type:
|
||||
| "apiConfiguration"
|
||||
@@ -27,12 +29,15 @@ export interface WebviewMessage {
|
||||
| "cancelTask"
|
||||
| "refreshOpenRouterModels"
|
||||
| "alwaysAllowBrowser"
|
||||
| "playSound"
|
||||
| "soundEnabled"
|
||||
text?: string
|
||||
askResponse?: ClineAskResponse
|
||||
apiConfiguration?: ApiConfiguration
|
||||
images?: string[]
|
||||
bool?: boolean
|
||||
commands?: string[]
|
||||
audioType?: AudioType
|
||||
}
|
||||
|
||||
export type ClineAskResponse = "yesButtonClicked" | "noButtonClicked" | "messageResponse"
|
||||
|
||||
68
src/utils/sound.ts
Normal file
68
src/utils/sound.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import * as vscode from "vscode"
|
||||
import * as path from "path"
|
||||
|
||||
/**
|
||||
* Minimum interval (in milliseconds) to prevent continuous playback
|
||||
*/
|
||||
const MIN_PLAY_INTERVAL = 500
|
||||
|
||||
/**
|
||||
* Timestamp of when sound was last played
|
||||
*/
|
||||
let lastPlayedTime = 0
|
||||
|
||||
/**
|
||||
* Determine if a file is a WAV file
|
||||
* @param filepath string
|
||||
* @returns boolean
|
||||
*/
|
||||
export const isWAV = (filepath: string): boolean => {
|
||||
return path.extname(filepath).toLowerCase() === ".wav"
|
||||
}
|
||||
|
||||
let isSoundEnabled = true
|
||||
|
||||
/**
|
||||
* Set sound configuration
|
||||
* @param enabled boolean
|
||||
*/
|
||||
export const setSoundEnabled = (enabled: boolean): void => {
|
||||
isSoundEnabled = enabled
|
||||
}
|
||||
|
||||
/**
|
||||
* Play a sound file
|
||||
* @param filepath string
|
||||
* @return void
|
||||
*/
|
||||
export const playSound = (filepath: string): void => {
|
||||
try {
|
||||
if (!isSoundEnabled) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!filepath) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!isWAV(filepath)) {
|
||||
throw new Error("Only wav files are supported.")
|
||||
}
|
||||
|
||||
const currentTime = Date.now()
|
||||
if (currentTime - lastPlayedTime < MIN_PLAY_INTERVAL) {
|
||||
return // Skip playback within minimum interval to prevent continuous playback
|
||||
}
|
||||
|
||||
const player = require("play-sound")()
|
||||
player.play(filepath, function (err: any) {
|
||||
if (err) {
|
||||
throw new Error("Failed to play sound effect")
|
||||
}
|
||||
})
|
||||
|
||||
lastPlayedTime = currentTime
|
||||
} catch (error: any) {
|
||||
vscode.window.showErrorMessage(error.message)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user