Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #Requires AutoHotkey v2.0+
- #SingleInstance Force
- #Warn All, Off
- ; ==============================================================================
- ; Script Name: Call Recorder for FFmpeg
- ; Synopsis:
- ; This script manages audio recordings using FFmpeg. It captures audio from a
- ; specified microphone and saves recordings with timestamped filenames.
- ; The user can control recording via a system tray menu or hotkeys:
- ; - Ctrl+Alt+R: Start recording
- ; - Ctrl+Alt+S: Stop recording
- ; - Ctrl+Alt+X: Exit the application gracefully
- ;
- ; Additional Features:
- ; - Automatically creates a log directory if it doesn’t exist.
- ; - Verifies the FFmpeg executable location.
- ; - Ensures only one instance is running.
- ; - Provides clear tooltips for user feedback.
- ;
- ; Prerequisites:
- ; - AutoHotkey v2.0+
- ; - FFmpeg installed at the specified location.
- ; - Correct microphone name matching the system device.
- ; ==============================================================================
- ; --------------------------------------------------------------
- ; CONFIGURATION
- ; --------------------------------------------------------------
- class Config {
- static FFmpegPath := "C:\Users\J2897\Programs\ffmpeg\bin\ffmpeg.exe"
- static MicName := "Microphone (Scarlett 2i2 USB)"
- static CallsDir := A_ScriptDir "\Calls" ; New directory
- static OutputDir := this.CallsDir ; Alias for clarity
- static LogDir := A_ScriptDir "\Logs"
- static StartDelay := 2000
- }
- ; --------------------------------------------------------------
- ; APPLICATION STATE
- ; --------------------------------------------------------------
- class State {
- static ffmpegPID := 0
- static IsRecording => this.ffmpegPID != 0 && ProcessExist(this.ffmpegPID)
- static Clear() {
- this.ffmpegPID := 0
- }
- }
- ; --------------------------------------------------------------
- ; TRAY MENU
- ; --------------------------------------------------------------
- CreateTrayMenu() {
- A_TrayMenu.Delete()
- A_TrayMenu.Add("&Start Recording", (*) => StartRecording())
- A_TrayMenu.Add("&Stop Recording", (*) => StopRecording())
- A_TrayMenu.Add()
- A_TrayMenu.Add("E&xit", (*) => ExitAppGracefully())
- UpdateTrayMenu()
- }
- UpdateTrayMenu() {
- ; Use separate Enable/Disable methods
- if State.IsRecording {
- A_TrayMenu.Disable("&Start Recording")
- A_TrayMenu.Enable("&Stop Recording")
- } else {
- A_TrayMenu.Enable("&Start Recording")
- A_TrayMenu.Disable("&Stop Recording")
- }
- }
- ; --------------------------------------------------------------
- ; HOTKEYS
- ; --------------------------------------------------------------
- ^!R:: StartRecording()
- ^!S:: StopRecording()
- ^!X:: ExitAppGracefully()
- ; --------------------------------------------------------------
- ; INITIALIZATION
- ; --------------------------------------------------------------
- CreateTrayMenu()
- ShowToolTip("Call Recorder Initialized."
- . "`nRight-click the tray icon for options."
- . "`nHotkeys available:"
- . "`n Ctrl+Alt+R: Start Recording"
- . "`n Ctrl+Alt+S: Stop Recording"
- . "`n Ctrl+Alt+X: Exit", 1, 5000)
- return
- ; --------------------------------------------------------------
- ; FUNCTIONS
- ; --------------------------------------------------------------
- StartRecording() {
- if State.IsRecording {
- ShowToolTip("Recording already in progress!", 2, 2000)
- return
- }
- if !FileExist(Config.FFmpegPath) {
- MsgBox("FFmpeg not found at:`n" Config.FFmpegPath, "Error", 0x30)
- return
- }
- ; Ensure both Logs and Calls directories exist
- if !DirExist(Config.LogDir)
- DirCreate(Config.LogDir)
- if !DirExist(Config.CallsDir) ; <-- Added this check
- DirCreate(Config.CallsDir)
- timestamp := FormatTime(, "yyyy-MM-dd_HH-mm-ss")
- outputFile := Config.OutputDir "\Call_" timestamp ".mp3"
- cmd := Format(
- 'cmd /c ""{1}" -hide_banner -f dshow -i audio="{2}" '
- '-acodec libmp3lame -b:a 192k -ac 2 -y "{3}" & pause"',
- Config.FFmpegPath,
- Config.MicName,
- outputFile
- )
- try {
- State.ffmpegPID := Run(cmd, Config.OutputDir,, &pid)
- ; Wait up to 5 seconds for FFmpeg to initialize
- startTime := A_TickCount
- while (A_TickCount - startTime < 5000) {
- if ProcessExist(pid) && FileExist(outputFile)
- break
- Sleep 500
- }
- if !ProcessExist(pid) || !FileExist(outputFile)
- throw Error("FFmpeg failed to initialize")
- State.ffmpegPID := pid
- UpdateTrayMenu()
- }
- catch Error as e {
- State.Clear()
- MsgBox("Startup Error: " e.Message, "Error", 0x30)
- return
- }
- ShowToolTip("RECORDING STARTED (PID: " State.ffmpegPID ")", 2, 2000)
- UpdateTrayMenu()
- }
- StopRecording() {
- if !State.IsRecording {
- ShowToolTip("No active recording to stop", 2, 2000)
- return
- }
- ShowToolTip("Stopping recording...", 2, 2000)
- try {
- ; Force focus to FFmpeg's console
- WinActivate("ahk_pid " State.ffmpegPID)
- WinWaitActive("ahk_pid " State.ffmpegPID,, 1) ; Wait 1 sec for activation
- Send "q" ; Send 'q' directly to the active window
- Sleep 500 ; Give FFmpeg time to process the command
- if ProcessWaitClose(State.ffmpegPID, 2) {
- ShowToolTip("Stopped gracefully", 2, 2000)
- } else {
- ProcessClose(State.ffmpegPID)
- ShowToolTip("Force-closed recording", 2, 2000)
- }
- }
- catch Error as e {
- MsgBox("Stop Error: " e.Message, "Error", 0x30)
- }
- State.Clear()
- UpdateTrayMenu()
- }
- ExitAppGracefully() {
- if State.IsRecording {
- result := MsgBox("Recording in progress. Stop and exit?", "Confirm Exit", 0x34)
- if result = "Yes"
- StopRecording()
- else
- return
- }
- ExitApp()
- }
- ShowToolTip(text, id := 1, timeout := 0) {
- ToolTip(text,,, id)
- if timeout > 0
- SetTimer(() => ToolTip(,,, id), -timeout)
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement