| | |
| | | ) |
| | | |
| | | const ( |
| | | sampleRate = 16000 |
| | | channels = 1 |
| | | bitsPerSample = 16 |
| | | sampleRate = 16000 |
| | | channels = 1 |
| | | bitsPerSample = 16 |
| | | silenceThreshold = 0.05 |
| | | ) |
| | | |
| | |
| | | type Recorder struct { |
| | | mu sync.Mutex |
| | | |
| | | ctx *malgo.AllocatedContext |
| | | device *malgo.Device |
| | | ctx *malgo.AllocatedContext |
| | | device *malgo.Device |
| | | |
| | | // PCM buffer (16-bit signed, little-endian) |
| | | pcmBuf []byte |
| | |
| | | preferredDevice string |
| | | |
| | | // State |
| | | isRecording bool |
| | | maxVolume float64 |
| | | currentVolume float64 |
| | | volumeCallback func(float64) |
| | | deviceChangeCb func(string) |
| | | isRecording bool |
| | | maxVolume float64 |
| | | currentVolume float64 |
| | | volumeCallback func(float64) |
| | | deviceChangeCb func(string) |
| | | } |
| | | |
| | | // NewRecorder creates a new audio recorder backed by malgo. |
| | |
| | | |
| | | // Stop stops recording and discards audio data. |
| | | func (r *Recorder) Stop() { |
| | | device := r.detachDevice() |
| | | stopAndUninitDevice(device) |
| | | |
| | | r.mu.Lock() |
| | | defer r.mu.Unlock() |
| | | |
| | | r.stopDevice() |
| | | r.pcmBuf = nil |
| | | } |
| | | |
| | | // StopAndGetSamples stops recording and returns the captured audio as float32 samples. |
| | | func (r *Recorder) StopAndGetSamples() []float32 { |
| | | device := r.detachDevice() |
| | | stopAndUninitDevice(device) |
| | | |
| | | r.mu.Lock() |
| | | defer r.mu.Unlock() |
| | | |
| | | r.stopDevice() |
| | | |
| | | if len(r.pcmBuf) < 2 { |
| | | return nil |
| | |
| | | |
| | | // Close releases all audio resources. |
| | | func (r *Recorder) Close() { |
| | | device := r.detachDevice() |
| | | stopAndUninitDevice(device) |
| | | |
| | | r.mu.Lock() |
| | | defer r.mu.Unlock() |
| | | |
| | | r.stopDevice() |
| | | if r.ctx != nil { |
| | | r.ctx.Free() |
| | | r.ctx = nil |
| | | } |
| | | } |
| | | |
| | | func (r *Recorder) stopDevice() { |
| | | if r.device != nil { |
| | | r.device.Stop() |
| | | r.device.Uninit() |
| | | r.device = nil |
| | | } |
| | | func (r *Recorder) detachDevice() *malgo.Device { |
| | | r.mu.Lock() |
| | | defer r.mu.Unlock() |
| | | |
| | | device := r.device |
| | | r.device = nil |
| | | r.isRecording = false |
| | | return device |
| | | } |
| | | |
| | | func stopAndUninitDevice(device *malgo.Device) { |
| | | if device == nil { |
| | | return |
| | | } |
| | | logger.Info("Stopping audio device") |
| | | device.Stop() |
| | | logger.Info("Audio device stopped") |
| | | device.Uninit() |
| | | logger.Info("Audio device uninitialized") |
| | | } |
| | | |
| | | func (r *Recorder) onData(input []byte) { |