Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Properly close microphone before malgo chunk channel #436

Merged
merged 4 commits into from
Aug 9, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
}
Comment on lines +153 to +156
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As it's in Once,

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

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left that there because we don't check if we've called Open, so the channel may be nil, hypothetically

})
}

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