Intégration de libsoxr pour le rééchantillonnage audio
This commit is contained in:
139
pmostream/buffer.go
Normal file
139
pmostream/buffer.go
Normal file
@@ -0,0 +1,139 @@
|
||||
package pmostream
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type AudioBuffer struct {
|
||||
mu sync.Mutex
|
||||
cond *sync.Cond
|
||||
chunks [][]byte
|
||||
size int
|
||||
available int
|
||||
format SampleFormat
|
||||
readPos int
|
||||
writePos int
|
||||
closed bool
|
||||
}
|
||||
|
||||
func NewAudioBuffer(size int, format SampleFormat) *AudioBuffer {
|
||||
log.Infof("New AudioBuffer with size %d", size)
|
||||
ab := &AudioBuffer{
|
||||
chunks: make([][]byte, size),
|
||||
size: size,
|
||||
format: format,
|
||||
}
|
||||
ab.cond = sync.NewCond(&ab.mu)
|
||||
return ab
|
||||
}
|
||||
|
||||
func (ab *AudioBuffer) Available() int {
|
||||
ab.mu.Lock()
|
||||
defer ab.mu.Unlock()
|
||||
return ab.available
|
||||
}
|
||||
|
||||
// Write ajoute un chunk dans le buffer (écrase le plus ancien si plein)
|
||||
func (ab *AudioBuffer) Write(chunk []byte) {
|
||||
ab.mu.Lock()
|
||||
defer ab.mu.Unlock()
|
||||
if ab.closed {
|
||||
return
|
||||
}
|
||||
|
||||
ab.chunks[ab.writePos] = chunk
|
||||
ab.writePos = (ab.writePos + 1) % ab.size
|
||||
|
||||
if ab.available < ab.size {
|
||||
ab.available++
|
||||
} else {
|
||||
// tampon plein, on écrase → avancer readPos
|
||||
ab.readPos = (ab.readPos + 1) % ab.size
|
||||
}
|
||||
|
||||
ab.cond.Broadcast()
|
||||
}
|
||||
|
||||
func (ab *AudioBuffer) Read() []byte {
|
||||
ab.mu.Lock()
|
||||
defer ab.mu.Unlock()
|
||||
|
||||
if ab.available == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
chunk := ab.chunks[ab.readPos]
|
||||
ab.chunks[ab.readPos] = nil
|
||||
ab.readPos = (ab.readPos + 1) % ab.size
|
||||
ab.available--
|
||||
|
||||
return chunk
|
||||
}
|
||||
|
||||
// WaitForData attend qu'au moins n chunks soient disponibles ou timeout/closed
|
||||
func (ab *AudioBuffer) WaitForData(n int, timeout time.Duration) bool {
|
||||
ab.mu.Lock()
|
||||
defer ab.mu.Unlock()
|
||||
|
||||
if n <= 0 {
|
||||
n = 1
|
||||
}
|
||||
|
||||
if timeout <= 0 {
|
||||
for ab.available < n && !ab.closed {
|
||||
ab.cond.Wait()
|
||||
}
|
||||
return ab.available >= n && !ab.closed
|
||||
}
|
||||
|
||||
deadline := time.Now().Add(timeout)
|
||||
for ab.available < n && !ab.closed {
|
||||
remaining := time.Until(deadline)
|
||||
if remaining <= 0 {
|
||||
return false
|
||||
}
|
||||
waitCondWithTimeout(ab.cond, remaining)
|
||||
}
|
||||
|
||||
return ab.available >= n && !ab.closed
|
||||
}
|
||||
|
||||
// Wait est un raccourci pour WaitForData(1, 0)
|
||||
func (ab *AudioBuffer) Wait() {
|
||||
ab.WaitForData(1, 0)
|
||||
}
|
||||
|
||||
func (ab *AudioBuffer) Close() {
|
||||
ab.mu.Lock()
|
||||
defer ab.mu.Unlock()
|
||||
if !ab.closed {
|
||||
ab.closed = true
|
||||
ab.cond.Broadcast()
|
||||
}
|
||||
}
|
||||
|
||||
// Fonction helper pour attendre une sync.Cond avec timeout
|
||||
func waitCondWithTimeout(c *sync.Cond, d time.Duration) bool {
|
||||
timer := time.NewTimer(d)
|
||||
done := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
c.L.Lock()
|
||||
defer c.L.Unlock()
|
||||
c.Wait()
|
||||
close(done)
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
if !timer.Stop() {
|
||||
<-timer.C
|
||||
}
|
||||
return true
|
||||
case <-timer.C:
|
||||
return false
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user