From 175dd9ca0295b103f6ff90899c40d2e064eb6a1a Mon Sep 17 00:00:00 2001 From: "Tomi P. Hakala" Date: Sat, 4 Jan 2025 10:33:25 +0200 Subject: [PATCH] Revert "feat: enhance AudioBuffer with sample tracking and segment extraction" This reverts commit a433fa62ddd00bfb11d4235c297e81932a9ff8b3. --- internal/myaudio/audiobuffer.go | 105 ++++---------------------------- 1 file changed, 13 insertions(+), 92 deletions(-) diff --git a/internal/myaudio/audiobuffer.go b/internal/myaudio/audiobuffer.go index 1853f9c..2d32323 100644 --- a/internal/myaudio/audiobuffer.go +++ b/internal/myaudio/audiobuffer.go @@ -11,20 +11,9 @@ import ( "github.com/tphakala/birdnet-go/internal/conf" ) -// SegmentInfo contains audio segment data and sample tracking information -type SegmentInfo struct { - Data []byte - StartSampleIdx uint64 - EndSampleIdx uint64 - HasDiscontinuity bool - DiscontinuityAt []int -} - // AudioBuffer represents a circular buffer for storing PCM audio data, with timestamp tracking. type AudioBuffer struct { data []byte - sampleIndices []uint64 - lastSampleIdx uint64 writeIndex int sampleRate int bytesPerSample int @@ -48,20 +37,16 @@ func InitAudioBuffers(durationSeconds int, sampleRate, bytesPerSample int, sourc // NewAudioBuffer initializes a new AudioBuffer with timestamp tracking func NewAudioBuffer(durationSeconds int, sampleRate, bytesPerSample int) *AudioBuffer { bufferSize := durationSeconds * sampleRate * bytesPerSample - alignedBufferSize := ((bufferSize + 2047) / 2048) * 2048 - numSamples := alignedBufferSize / bytesPerSample - + alignedBufferSize := ((bufferSize + 2047) / 2048) * 2048 // Round up to the nearest multiple of 2048 ab := &AudioBuffer{ data: make([]byte, alignedBufferSize), - sampleIndices: make([]uint64, numSamples), - lastSampleIdx: 0, sampleRate: sampleRate, bytesPerSample: bytesPerSample, bufferSize: alignedBufferSize, - bufferDuration: time.Second * time.Duration(durationSeconds), initialized: false, } + return ab } @@ -77,7 +62,7 @@ func WriteToCaptureBuffer(source string, data []byte) { } // ReadSegment extracts a segment of audio data from the buffer for a given source. -func ReadSegmentFromCaptureBuffer(source string, requestedStartTime time.Time, duration int) (*SegmentInfo, error) { +func ReadSegmentFromCaptureBuffer(source string, requestedStartTime time.Time, duration int) ([]byte, error) { ab, exists := audioBuffers[source] if !exists { return nil, fmt.Errorf("No audio buffer found for source: %s", source) @@ -100,32 +85,14 @@ func (ab *AudioBuffer) Write(data []byte) { // Store the current write index to determine if we've wrapped around the buffer. prevWriteIndex := ab.writeIndex - samplesWritten := 0 - - // Write data and sample indices - for i := 0; i < len(data); i += ab.bytesPerSample { - dataIdx := ab.writeIndex + i - if dataIdx >= ab.bufferSize { - dataIdx -= ab.bufferSize - } - - // Copy audio data - for j := 0; j < ab.bytesPerSample && i+j < len(data); j++ { - ab.data[dataIdx+j] = data[i+j] - } - // Update sample index - sampleIdx := (ab.writeIndex + i) / ab.bytesPerSample - if sampleIdx >= len(ab.sampleIndices) { - sampleIdx -= len(ab.sampleIndices) - } - ab.sampleIndices[sampleIdx] = ab.lastSampleIdx + uint64(samplesWritten) - samplesWritten++ - } + // Copy the incoming data into the buffer starting at the current write index. + bytesWritten := copy(ab.data[ab.writeIndex:], data) - ab.writeIndex = (ab.writeIndex + len(data)) % ab.bufferSize - ab.lastSampleIdx += uint64(samplesWritten) + // Update the write index, wrapping around the buffer if necessary. + ab.writeIndex = (ab.writeIndex + bytesWritten) % ab.bufferSize + // Determine if the write operation has overwritten old data. if ab.writeIndex <= prevWriteIndex { // If old data has been overwritten, adjust startTime to maintain accurate timekeeping. ab.startTime = time.Now().Add(-ab.bufferDuration) @@ -137,7 +104,7 @@ func (ab *AudioBuffer) Write(data []byte) { // ReadSegment extracts a segment of audio data based on precise start and end times, handling wraparounds. // It waits until the current time is past the requested end time. -func (ab *AudioBuffer) ReadSegment(requestedStartTime time.Time, duration int) (*SegmentInfo, error) { +func (ab *AudioBuffer) ReadSegment(requestedStartTime time.Time, duration int) ([]byte, error) { requestedEndTime := requestedStartTime.Add(time.Duration(duration) * time.Second) for { @@ -168,9 +135,6 @@ func (ab *AudioBuffer) ReadSegment(requestedStartTime time.Time, duration int) ( // Wait until the current time is past the requested end time if time.Now().After(requestedEndTime) { var segment []byte - var startSampleIdx, endSampleIdx uint64 - discontinuities := make([]int, 0) - if startIndex < endIndex { if conf.Setting().Realtime.Audio.Export.Debug { log.Printf("Reading segment from %d to %d", startIndex, endIndex) @@ -178,17 +142,6 @@ func (ab *AudioBuffer) ReadSegment(requestedStartTime time.Time, duration int) ( segmentSize := endIndex - startIndex segment = make([]byte, segmentSize) copy(segment, ab.data[startIndex:endIndex]) - - // Track sample indices - startSampleIdx = ab.sampleIndices[startIndex/ab.bytesPerSample] - endSampleIdx = ab.sampleIndices[(endIndex/ab.bytesPerSample)-1] + 1 - - // Check for discontinuities - for i := startIndex/ab.bytesPerSample + 1; i < endIndex/ab.bytesPerSample; i++ { - if ab.sampleIndices[i] != ab.sampleIndices[i-1]+1 { - discontinuities = append(discontinuities, (i*ab.bytesPerSample)-startIndex) - } - } } else { if conf.Setting().Realtime.Audio.Export.Debug { log.Printf("Buffer wrapped during read, reading segment from %d to %d", startIndex, endIndex) @@ -198,46 +151,14 @@ func (ab *AudioBuffer) ReadSegment(requestedStartTime time.Time, duration int) ( firstPartSize := ab.bufferSize - startIndex copy(segment[:firstPartSize], ab.data[startIndex:]) copy(segment[firstPartSize:], ab.data[:endIndex]) - - // Track sample indices for wrapped buffer - startSampleIdx = ab.sampleIndices[startIndex/ab.bytesPerSample] - endSampleIdx = ab.sampleIndices[(endIndex/ab.bytesPerSample)-1] + 1 - - // Check for discontinuities including wrap point - for i := startIndex / ab.bytesPerSample; i < ab.bufferSize/ab.bytesPerSample; i++ { - if i > startIndex/ab.bytesPerSample && i > 0 { - if ab.sampleIndices[i] != ab.sampleIndices[i-1]+1 { - discontinuities = append(discontinuities, (i*ab.bytesPerSample)-startIndex) - } - } - } - for i := 1; i < endIndex/ab.bytesPerSample; i++ { - if ab.sampleIndices[i] != ab.sampleIndices[i-1]+1 { - discontinuities = append(discontinuities, ((i*ab.bytesPerSample)+firstPartSize)-startIndex) - } - } } - - if conf.Setting().Realtime.Audio.Export.Debug { - if len(discontinuities) > 0 { - log.Printf("Found %d discontinuities in samples %d to %d at positions: %v", - len(discontinuities), startSampleIdx, endSampleIdx, discontinuities) - } else { - log.Printf("Sample sequence continuous from %d to %d", - startSampleIdx, endSampleIdx) - } - } - ab.lock.Unlock() - return &SegmentInfo{ - Data: segment, - StartSampleIdx: startSampleIdx, - EndSampleIdx: endSampleIdx, - HasDiscontinuity: len(discontinuities) > 0, - DiscontinuityAt: discontinuities, - }, nil + return segment, nil } + if conf.Setting().Realtime.Audio.Export.Debug { + log.Printf("Buffer is not filled yet, waiting for data to be available") + } ab.lock.Unlock() time.Sleep(1 * time.Second) // Sleep briefly to avoid busy waiting }