fix recorded audio truncation and rate mismatch
Accumulate incoming frames per source and consume fixed-size chunks. Each speaker's frames were queued whole and one frame was taken per tick, so a frame that did not match the recorder's frame size was truncated or padded and the recording drifted out of time with the audio. Frames of any size now append to a per-source buffer that is drained in exact chunks. Tell the recorder whether a frame is stereo instead of guessing from its length. Mono microphone frames were being interpreted as stereo, which halved their duration and produced static in the output. Let the recorder worker close ffmpeg's stdin. Stop closed it from the caller while the worker was still writing, turning a normal stop into a broken pipe and losing the tail of the recording. Reserve the output file exclusively and hand ffmpeg the descriptor. The path was generated, then reopened by name, so another process could take the name in between. The file is opened once with O_EXCL and passed to ffmpeg as an inherited descriptor. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
af37bcd5d6
commit
5ec82eb1fd
@@ -26,7 +26,7 @@ type FilePlayer interface {
|
||||
}
|
||||
|
||||
type Recorder interface {
|
||||
RecordAudioFrame(source uint32, samples []int16)
|
||||
RecordAudioFrame(source uint32, samples []int16, stereo bool)
|
||||
}
|
||||
|
||||
const recorderOutgoingSource uint32 = ^uint32(0)
|
||||
@@ -351,7 +351,7 @@ func (s *Stream) OnAudioStream(e *gumble.AudioStreamEvent) {
|
||||
}
|
||||
}
|
||||
if recorder != nil && recordPtr > 0 {
|
||||
recorder.RecordAudioFrame(e.User.Session, recordBuffer[:recordPtr])
|
||||
recorder.RecordAudioFrame(e.User.Session, recordBuffer[:recordPtr], true)
|
||||
}
|
||||
|
||||
reclaim()
|
||||
@@ -500,13 +500,13 @@ func (s *Stream) sourceRoutine(inputDevice *string) {
|
||||
// Send stereo buffer when file is playing
|
||||
outgoing <- gumble.AudioBuffer(outputBuffer)
|
||||
if recorder := s.getRecorder(); recorder != nil {
|
||||
recorder.RecordAudioFrame(recorderOutgoingSource, outputBuffer)
|
||||
recorder.RecordAudioFrame(recorderOutgoingSource, outputBuffer, true)
|
||||
}
|
||||
} else if hasMicInput {
|
||||
// Send mic when no file is playing
|
||||
outgoing <- gumble.AudioBuffer(int16Buffer)
|
||||
if recorder := s.getRecorder(); recorder != nil {
|
||||
recorder.RecordAudioFrame(recorderOutgoingSource, int16Buffer)
|
||||
recorder.RecordAudioFrame(recorderOutgoingSource, int16Buffer, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user