-
Notifications
You must be signed in to change notification settings - Fork 110
/
audio_input.go
146 lines (122 loc) · 4.48 KB
/
audio_input.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// Package audioinput defines an audio capturing device.
package audioinput
import (
"context"
"errors"
"github.com/edaniels/gostream"
"github.com/pion/mediadevices/pkg/prop"
pb "go.viam.com/api/component/audioinput/v1"
"go.viam.com/rdk/resource"
"go.viam.com/rdk/robot"
)
func init() {
resource.RegisterAPI(API, resource.APIRegistration[AudioInput]{
RPCServiceServerConstructor: NewRPCServiceServer,
RPCServiceHandler: pb.RegisterAudioInputServiceHandlerFromEndpoint,
RPCServiceDesc: &pb.AudioInputService_ServiceDesc,
RPCClient: NewClientFromConn,
})
// TODO(RSDK-562): Add RegisterCollector
}
// SubtypeName is a constant that identifies the audio input resource subtype string.
const SubtypeName = "audio_input"
// API is a variable that identifies the audio input resource API.
var API = resource.APINamespaceRDK.WithComponentType(SubtypeName)
// Named is a helper for getting the named audio inputs's typed resource name.
func Named(name string) resource.Name {
return resource.NewName(API, name)
}
// An AudioInput is a resource that can capture audio.
type AudioInput interface {
resource.Resource
AudioSource
}
// An AudioSource represents anything that can capture audio.
type AudioSource interface {
gostream.AudioSource
gostream.AudioPropertyProvider
}
// A LivenessMonitor is responsible for monitoring the liveness of an audio input. An example
// is connectivity. Since the model itself knows best about how to maintain this state,
// the reconfigurable offers a safe way to notify if a state needs to be reset due
// to some exceptional event (like a reconnect).
// It is expected that the monitoring code is tied to the lifetime of the resource
// and once the resource is closed, so should the monitor. That is, it should
// no longer send any resets once a Close on its associated resource has returned.
type LivenessMonitor interface {
Monitor(notifyReset func())
}
// FromDependencies is a helper for getting the named audio input from a collection of
// dependencies.
func FromDependencies(deps resource.Dependencies, name string) (AudioInput, error) {
return resource.FromDependencies[AudioInput](deps, Named(name))
}
// FromRobot is a helper for getting the named audio input from the given Robot.
func FromRobot(r robot.Robot, name string) (AudioInput, error) {
return robot.ResourceFromRobot[AudioInput](r, Named(name))
}
// NamesFromRobot is a helper for getting all audio input names from the given Robot.
func NamesFromRobot(r robot.Robot) []string {
return robot.NamesByAPI(r, API)
}
type audioPropertiesFunc func(ctx context.Context) (prop.Audio, error)
func (apf audioPropertiesFunc) MediaProperties(ctx context.Context) (prop.Audio, error) {
return apf(ctx)
}
// NewAudioSourceFromReader creates an AudioSource from a reader.
func NewAudioSourceFromReader(reader gostream.AudioReader, props prop.Audio) (AudioSource, error) {
if reader == nil {
return nil, errors.New("cannot have a nil reader")
}
as := gostream.NewAudioSource(reader, props)
return &audioSource{
as: as,
prov: audioPropertiesFunc(func(ctx context.Context) (prop.Audio, error) {
return props, nil
}),
}, nil
}
// FromAudioSource creates an AudioInput resource either from a AudioSource.
func FromAudioSource(name resource.Name, src AudioSource) (AudioInput, error) {
return &sourceBasedInput{
Named: name.AsNamed(),
AudioSource: src,
}, nil
}
type sourceBasedInput struct {
resource.Named
resource.AlwaysRebuild
AudioSource
}
// NewAudioSourceFromGostreamSource creates an AudioSource from a gostream.AudioSource.
func NewAudioSourceFromGostreamSource(audSrc gostream.AudioSource) (AudioSource, error) {
if audSrc == nil {
return nil, errors.New("cannot have a nil audio source")
}
provider, ok := audSrc.(gostream.AudioPropertyProvider)
if !ok {
return nil, errors.New("source must have property provider")
}
return &audioSource{
as: audSrc,
prov: provider,
}, nil
}
// AudioSource implements an AudioInput with a gostream.AudioSource.
type audioSource struct {
as gostream.AudioSource
prov gostream.AudioPropertyProvider
}
func (as *audioSource) Stream(
ctx context.Context,
errHandlers ...gostream.ErrorHandler,
) (gostream.AudioStream, error) {
return as.as.Stream(ctx, errHandlers...)
}
func (as *audioSource) MediaProperties(ctx context.Context) (prop.Audio, error) {
return as.prov.MediaProperties(ctx)
}
// Close closes the underlying AudioSource.
func (as *audioSource) Close(ctx context.Context) error {
return as.as.Close(ctx)
}