Skip to content

Commit

Permalink
Properly close microphone before malgo chunk channel (#436)
Browse files Browse the repository at this point in the history
  • Loading branch information
edaniels authored Aug 9, 2022
1 parent 5215057 commit 6f204fa
Showing 1 changed file with 27 additions and 7 deletions.
34 changes: 27 additions & 7 deletions pkg/driver/microphone/microphone.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package microphone

import (
"context"
"encoding/binary"
"errors"
"fmt"
"io"
"sync"
"time"
"unsafe"

Expand Down Expand Up @@ -32,7 +34,8 @@ var (

type microphone struct {
malgo.DeviceInfo
chunkChan chan []byte
chunkChan chan []byte
deviceCloseFunc func()
}

func init() {
Expand Down Expand Up @@ -87,9 +90,8 @@ func (m *microphone) Open() error {
}

func (m *microphone) Close() error {
if m.chunkChan != nil {
close(m.chunkChan)
m.chunkChan = nil
if m.deviceCloseFunc != nil {
m.deviceCloseFunc()
}
return nil
}
Expand Down Expand Up @@ -121,26 +123,44 @@ func (m *microphone) AudioRecord(inputProp prop.Media) (audio.Reader, error) {
return nil, errUnsupportedFormat
}

cancelCtx, cancel := context.WithCancel(context.Background())
onRecvChunk := func(_, chunk []byte, framecount uint32) {
m.chunkChan <- chunk
select {
case <-cancelCtx.Done():
case m.chunkChan <- chunk:
}
}
callbacks.Data = onRecvChunk

device, err := malgo.InitDevice(ctx.Context, config, callbacks)
if err != nil {
cancel()
return nil, err
}

err = device.Start()
if err != nil {
cancel()
return nil, err
}

var closeDeviceOnce sync.Once
m.deviceCloseFunc = func() {
closeDeviceOnce.Do(func() {
cancel() // Unblock onRecvChunk
device.Uninit()

if m.chunkChan != nil {
close(m.chunkChan)
m.chunkChan = nil
}
})
}

var reader audio.Reader = audio.ReaderFunc(func() (wave.Audio, func(), error) {
chunk, ok := <-m.chunkChan
if !ok {
device.Stop()
device.Uninit()
m.deviceCloseFunc()
return nil, func() {}, io.EOF
}

Expand Down

0 comments on commit 6f204fa

Please sign in to comment.