Skip to content

Commit

Permalink
Slice buffer on last frame
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexEidt committed Sep 14, 2022
1 parent dea7fa1 commit a8d029f
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 24 deletions.
8 changes: 4 additions & 4 deletions aio_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ func TestAudioBuffer(t *testing.T) {
// buffer[0:10] = [209 252 172 253 82 255 5 0 94 0]
buffer := audio.Buffer()

assertEquals(len(buffer), audio.SampleRate()*audio.Channels()*audio.BitsPerSample()/8)
assertEquals(len(buffer), 512)
assertEquals(buffer[0], byte(209))
assertEquals(buffer[1], byte(252))
assertEquals(buffer[2], byte(172))
Expand Down Expand Up @@ -212,6 +212,8 @@ func TestAudioPlayback(t *testing.T) {
}
defer player.Close()

audio.SetBuffer(make([]byte, audio.Total()*4))

for audio.Read() {
player.Play(audio.Buffer())
}
Expand All @@ -236,11 +238,9 @@ func TestAudioCopying(t *testing.T) {
panic(err2)
}

data := make([]int16, audio.SampleRate()*audio.Channels()*audio.BitsPerSample()/8/2)
for audio.Read() {
samples := audio.Samples().([]int16)
copy(data, samples)
writer.Write(data)
writer.Write(samples)
}

defer writer.Close()
Expand Down
19 changes: 15 additions & 4 deletions audio.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type Audio struct {
codec string // Codec used for video encoding.
bps int // Bits per sample.
stream int // Stream Index.
ended bool // Flag storing whether Audio reading has ended.
buffer []byte // Raw audio data.
metadata map[string]string // Audio Metadata.
pipe *io.ReadCloser // Stdout pipe for ffmpeg process.
Expand Down Expand Up @@ -229,6 +230,7 @@ func (audio *Audio) init() error {
return err
}
audio.pipe = &pipe

if err := cmd.Start(); err != nil {
return err
}
Expand All @@ -240,9 +242,13 @@ func (audio *Audio) init() error {
return nil
}

// Reads the next frame from of audio and stores it in the buffer.
// If the last frame has been read, returns false, otherwise true.
// Reads the next frame of audio and stores it in the buffer.
// If the last audio frame has been read, returns false, otherwise true.
func (audio *Audio) Read() bool {
if audio.ended {
return false
}

// If cmd is nil, video reading has not been initialized.
if audio.cmd == nil {
if err := audio.init(); err != nil {
Expand All @@ -253,18 +259,23 @@ func (audio *Audio) Read() bool {
total := 0
for total < len(audio.buffer) {
n, err := (*audio.pipe).Read(audio.buffer[total:])
total += n
if err == io.EOF {
// When the user reaches the end of the audio stream, the buffer will have to be shortened
// such that the audio stream is accurately represented.
// The rest of this sliced array is not garbage collected.
audio.buffer = audio.buffer[:total]
audio.Close()
return false
break
}
total += n
}

return true
}

// Closes the pipe and stops the ffmpeg process.
func (audio *Audio) Close() {
audio.ended = true
if audio.pipe != nil {
(*audio.pipe).Close()
}
Expand Down
2 changes: 2 additions & 0 deletions audiowriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ func (writer *AudioWriter) Write(samples interface{}) error {
return err
}
}

total := 0
for total < len(buffer) {
n, err := (*writer.pipe).Write(buffer[total:])
Expand All @@ -186,6 +187,7 @@ func (writer *AudioWriter) Write(samples interface{}) error {
}
total += n
}

return nil
}

Expand Down
2 changes: 2 additions & 0 deletions microphone.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,11 +243,13 @@ func (mic *Microphone) Read() bool {
return false
}
}

total := 0
for total < len(mic.buffer) {
n, _ := (*mic.pipe).Read(mic.buffer[total:])
total += n
}

return true
}

Expand Down
Binary file modified test/output.mp3
Binary file not shown.
35 changes: 19 additions & 16 deletions utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,11 @@ func exists(filename string) bool {
// Checks if the given program is installed.
func installed(program string) error {
cmd := exec.Command(program, "-version")
errmsg := fmt.Errorf("%s is not installed", program)
if err := cmd.Start(); err != nil {
return errmsg
}
if err := cmd.Wait(); err != nil {
return errmsg

if err := cmd.Run(); err != nil {
return fmt.Errorf("%s is not installed", program)
}

return nil
}

Expand Down Expand Up @@ -164,6 +162,7 @@ func parseDevices(buffer string) []string {
devices = append(devices, pair.name)
}
}

return devices
}

Expand All @@ -176,16 +175,6 @@ func contains(list []string, item string) bool {
return false
}

// Check audio format string.
func checkFormat(format string) error {
match := regexp.MustCompile(`^(([us]8)|([us]((16)|(24)|(32))[bl]e)|(f((32)|(64))[bl]e))$`)
if len(match.FindString(format)) == 0 {
formats := "u8, s8, u16, s16, u24, s24, u32, s32, f32, or f64"
return fmt.Errorf("audio format %s is not supported, must be one of %s", format[:len(format)-2], formats)
}
return nil
}

// Returns the microphone device name.
// On windows, ffmpeg output from the -list_devices command is parsed to find the device name.
func getDevicesWindows() ([]string, error) {
Expand All @@ -197,10 +186,13 @@ func getDevicesWindows() ([]string, error) {
"-f", "dshow",
"-i", "dummy",
)

pipe, err := cmd.StderrPipe()
if err != nil {
return nil, err
}

// Start the command and immediately continue so that the pipe can be read.
if err := cmd.Start(); err != nil {
return nil, err
}
Expand All @@ -216,12 +208,23 @@ func getDevicesWindows() ([]string, error) {
}
}

// Wait for the command to finish.
cmd.Wait()

devices := parseDevices(builder.String())
return devices, nil
}

// Check audio format string.
func checkFormat(format string) error {
match := regexp.MustCompile(`^(([us]8)|([us]((16)|(24)|(32))[bl]e)|(f((32)|(64))[bl]e))$`)
if len(match.FindString(format)) == 0 {
formats := "u8, s8, u16, s16, u24, s24, u32, s32, f32, or f64"
return fmt.Errorf("audio format %s is not supported, must be one of %s", format[:len(format)-2], formats)
}
return nil
}

func createFormat(format string) string {
switch format {
case "u8", "s8":
Expand Down

0 comments on commit a8d029f

Please sign in to comment.