mirror of
https://github.com/pion/mediadevices.git
synced 2025-10-03 15:56:28 +08:00
Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
3bec69bbf8 | ||
![]() |
58dc90d03a |
@@ -119,3 +119,41 @@ func VideoEncoderCloseTwiceTest(t *testing.T, c codec.VideoEncoderBuilder, p pro
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func AudioEncoderReadAfterCloseTest(t *testing.T, c codec.AudioEncoderBuilder, p prop.Media, w wave.Audio) {
|
||||||
|
enc, err := c.BuildAudioEncoder(audio.ReaderFunc(func() (wave.Audio, func(), error) {
|
||||||
|
return w, nil, nil
|
||||||
|
}), p)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := assertNoPanic(t, enc.Close, "on Close()"); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := assertNoPanic(t, func() error {
|
||||||
|
_, _, err := enc.Read()
|
||||||
|
return err
|
||||||
|
}, "on Read()"); err != io.EOF {
|
||||||
|
t.Fatalf("Expected: %v, got: %v", io.EOF, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func VideoEncoderReadAfterCloseTest(t *testing.T, c codec.VideoEncoderBuilder, p prop.Media, img image.Image) {
|
||||||
|
enc, err := c.BuildVideoEncoder(video.ReaderFunc(func() (image.Image, func(), error) {
|
||||||
|
return img, nil, nil
|
||||||
|
}), p)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := assertNoPanic(t, enc.Close, "on Close()"); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := assertNoPanic(t, func() error {
|
||||||
|
_, _, err := enc.Read()
|
||||||
|
return err
|
||||||
|
}, "on Read()"); err != io.EOF {
|
||||||
|
t.Fatalf("Expected: %v, got: %v", io.EOF, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -44,6 +44,25 @@ func TestEncoder(t *testing.T) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
t.Run("ReadAfterClose", func(t *testing.T) {
|
||||||
|
p, err := NewParams()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
codectest.VideoEncoderReadAfterCloseTest(t, &p,
|
||||||
|
prop.Media{
|
||||||
|
Video: prop.Video{
|
||||||
|
Width: 256,
|
||||||
|
Height: 144,
|
||||||
|
FrameFormat: frame.FormatI420,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
image.NewYCbCr(
|
||||||
|
image.Rect(0, 0, 256, 144),
|
||||||
|
image.YCbCrSubsampleRatio420,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestShouldImplementBitRateControl(t *testing.T) {
|
func TestShouldImplementBitRateControl(t *testing.T) {
|
||||||
|
@@ -60,4 +60,23 @@ func TestEncoder(t *testing.T) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
t.Run("ReadAfterClose", func(t *testing.T) {
|
||||||
|
p, err := NewParams()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
codectest.VideoEncoderReadAfterCloseTest(t, &p,
|
||||||
|
prop.Media{
|
||||||
|
Video: prop.Video{
|
||||||
|
Width: 256,
|
||||||
|
Height: 144,
|
||||||
|
FrameFormat: frame.FormatI420,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
image.NewYCbCr(
|
||||||
|
image.Rect(0, 0, 256, 144),
|
||||||
|
image.YCbCrSubsampleRatio420,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@@ -3,6 +3,8 @@ package opus
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/pion/mediadevices/pkg/codec"
|
"github.com/pion/mediadevices/pkg/codec"
|
||||||
"github.com/pion/mediadevices/pkg/io/audio"
|
"github.com/pion/mediadevices/pkg/io/audio"
|
||||||
@@ -25,6 +27,8 @@ type encoder struct {
|
|||||||
inBuff wave.Audio
|
inBuff wave.Audio
|
||||||
reader audio.Reader
|
reader audio.Reader
|
||||||
engine *C.OpusEncoder
|
engine *C.OpusEncoder
|
||||||
|
|
||||||
|
mu sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func newEncoder(r audio.Reader, p prop.Media, params Params) (codec.ReadCloser, error) {
|
func newEncoder(r audio.Reader, p prop.Media, params Params) (codec.ReadCloser, error) {
|
||||||
@@ -79,6 +83,12 @@ func (e *encoder) Read() ([]byte, func(), error) {
|
|||||||
return nil, func() {}, err
|
return nil, func() {}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
e.mu.Lock()
|
||||||
|
defer e.mu.Unlock()
|
||||||
|
if e.engine == nil {
|
||||||
|
return nil, nil, io.EOF
|
||||||
|
}
|
||||||
|
|
||||||
encoded := make([]byte, 1024)
|
encoded := make([]byte, 1024)
|
||||||
var n C.opus_int32
|
var n C.opus_int32
|
||||||
switch b := buff.(type) {
|
switch b := buff.(type) {
|
||||||
@@ -126,6 +136,8 @@ func (e *encoder) Controller() codec.EncoderController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *encoder) Close() error {
|
func (e *encoder) Close() error {
|
||||||
|
e.mu.Lock()
|
||||||
|
defer e.mu.Unlock()
|
||||||
if e.engine == nil {
|
if e.engine == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@@ -57,4 +57,23 @@ func TestEncoder(t *testing.T) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
t.Run("ReadAfterClose", func(t *testing.T) {
|
||||||
|
p, err := NewParams()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
codectest.AudioEncoderReadAfterCloseTest(t, &p,
|
||||||
|
prop.Media{
|
||||||
|
Audio: prop.Audio{
|
||||||
|
SampleRate: 48000,
|
||||||
|
ChannelCount: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wave.NewInt16Interleaved(wave.ChunkInfo{
|
||||||
|
Len: 960,
|
||||||
|
SamplingRate: 48000,
|
||||||
|
Channels: 2,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@@ -65,6 +65,25 @@ func TestEncoder(t *testing.T) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
t.Run("ReadAfterClose", func(t *testing.T) {
|
||||||
|
p, err := factory()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
codectest.VideoEncoderReadAfterCloseTest(t, p,
|
||||||
|
prop.Media{
|
||||||
|
Video: prop.Video{
|
||||||
|
Width: 256,
|
||||||
|
Height: 144,
|
||||||
|
FrameFormat: frame.FormatI420,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
image.NewYCbCr(
|
||||||
|
image.Rect(0, 0, 256, 144),
|
||||||
|
image.YCbCrSubsampleRatio420,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -60,6 +60,25 @@ func TestEncoder(t *testing.T) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
t.Run("ReadAfterClose", func(t *testing.T) {
|
||||||
|
p, err := factory()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
codectest.VideoEncoderReadAfterCloseTest(t, p,
|
||||||
|
prop.Media{
|
||||||
|
Video: prop.Video{
|
||||||
|
Width: 256,
|
||||||
|
Height: 144,
|
||||||
|
FrameFormat: frame.FormatI420,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
image.NewYCbCr(
|
||||||
|
image.Rect(0, 0, 256, 144),
|
||||||
|
image.YCbCrSubsampleRatio420,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -46,6 +46,26 @@ func TestEncoder(t *testing.T) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
t.Run("ReadAfterClose", func(t *testing.T) {
|
||||||
|
p, err := NewParams()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
p.BitRate = 200000
|
||||||
|
codectest.VideoEncoderReadAfterCloseTest(t, &p,
|
||||||
|
prop.Media{
|
||||||
|
Video: prop.Video{
|
||||||
|
Width: 256,
|
||||||
|
Height: 144,
|
||||||
|
FrameFormat: frame.FormatI420,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
image.NewYCbCr(
|
||||||
|
image.Rect(0, 0, 256, 144),
|
||||||
|
image.YCbCrSubsampleRatio420,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestShouldImplementKeyFrameControl(t *testing.T) {
|
func TestShouldImplementKeyFrameControl(t *testing.T) {
|
||||||
|
@@ -113,6 +113,7 @@ func (m *microphone) AudioRecord(inputProp prop.Media) (audio.Reader, error) {
|
|||||||
config.PerformanceProfile = malgo.LowLatency
|
config.PerformanceProfile = malgo.LowLatency
|
||||||
config.Capture.Channels = uint32(inputProp.ChannelCount)
|
config.Capture.Channels = uint32(inputProp.ChannelCount)
|
||||||
config.SampleRate = uint32(inputProp.SampleRate)
|
config.SampleRate = uint32(inputProp.SampleRate)
|
||||||
|
config.PeriodSizeInMilliseconds = uint32(inputProp.Latency.Milliseconds())
|
||||||
//FIX: Turn on the microphone with the current device id
|
//FIX: Turn on the microphone with the current device id
|
||||||
config.Capture.DeviceID = m.ID.Pointer()
|
config.Capture.DeviceID = m.ID.Pointer()
|
||||||
if inputProp.SampleSize == 4 && inputProp.IsFloat {
|
if inputProp.SampleSize == 4 && inputProp.IsFloat {
|
||||||
|
Reference in New Issue
Block a user