Home > Enterprise >  How to kill command Exec in difference Function in Golang
How to kill command Exec in difference Function in Golang

Time:07-26

i'm making screen record web based using command exec to run FFMPEG. here I created a startRecording function but I am still confused about stopping the command process in the stopRecording function, because the command is executed in the startRecording function. How to stop a process that is already running in the srartRecording function in the stopRecording function?

here my code

//Handler to create room/start record
func RoomCreate(c *fiber.Ctx) error {
    fileName := "out.mp4"
    fmt.Println(fileName)
    if len(os.Args) > 1 {
        fileName = os.Args[1]
    }

    

    errCh := make(chan error, 2)
    ctx, cancelFn := context.WithCancel(context.Background())
    // Call to function startRecording
    go func() { errCh <- startRecording(ctx, fileName) }()

    go func() {
        errCh <- nil
    }()
    err := <-errCh
    cancelFn()
    if err != nil && err != context.Canceled {
        log.Fatalf("Execution failed: %v", err)
    }
    
    return c.Redirect(fmt.Sprintf("/room/%s", guuid.New().String()))
}



//Function to run command FFMPEG
func startRecording(ctx context.Context, fileName string) error {
    ctx, cancelFn := context.WithCancel(ctx)
    defer cancelFn()
    // Build ffmpeg
    ffmpeg := exec.Command("ffmpeg",
        "-f", "gdigrab",
        "-framerate", "30",
        "-i", "desktop",
        "-f", "mp4",
        fileName,
    )
    // Stdin for sending data
    stdin, err := ffmpeg.StdinPipe()
    if err != nil {
        return err
    }
    //var buf bytes.Buffer
    defer stdin.Close()
    // Run it in the background
    errCh := make(chan error, 1)

    go func() {
        fmt.Printf("Executing: %v\n", strings.Join(ffmpeg.Args, " "))
        
        if err := ffmpeg.Run(); err != nil {
            return
        }
        //fmt.Printf("FFMPEG output:\n%v\n", string(out))
        errCh <- err
    }()
    // Just start sending a bunch of frames
    for {
        
        // Check if we're done, otherwise go again
        select {
        case <-ctx.Done():
            return ctx.Err()
        case err := <-errCh:
            return err
        default:
        }
    }
}

//Here function to stop Recording
func stopRecording(ctx context.Context) error {
//Code stop recording in here
} 

Thanks for advance

CodePudding user response:

As requested from comments.

The basic idea is to use global storage to store your active commands. It doesn't necessarily be global but you need to have bigger scope so that your functions can access it.

var commands = map[string]*exec.Cmd{}

func startRecording(fileName string) error {
    ffmpeg := exec.Command("ffmpeg",
        "-f", "gdigrab",
        "-framerate", "30",
        "-i", "desktop",
        "-f", "mp4",
        fileName,
    )
    commands[fileName] = ffmpeg
    ...
}

func stopRecording(fileName string) error {
    cmd, ok := commands[fileName]
    if !ok {
        return errors.New("command not found")
    }
    defer func() {
        delete(commands, fileName)
    }()
    return cmd.Process.Kill()
}

You probably want to use sync.Mutex or sync.RWMutex to avoid concurrent map writes.

So your commands cloud look like:

type Commands struct {
    sync.RWMutex
    items map[string]*exec.Cmd
}
// use Commands.Lock() for writing, Commands.RLock() for reading
  • Related