diff --git a/mediadevices.go b/mediadevices.go index 2fd13ff..bf02b55 100644 --- a/mediadevices.go +++ b/mediadevices.go @@ -20,7 +20,7 @@ type MediaDevices interface { // NewMediaDevices creates MediaDevices interface that provides access to connected media input devices // like cameras and microphones, as well as screen sharing. // In essence, it lets you obtain access to any hardware source of media data. -func NewMediaDevices(pc *webrtc.PeerConnection) MediaDevices { +func NewMediaDevices(pc *webrtc.PeerConnection, opts ...MediaDevicesOption) MediaDevices { codecs := make(map[webrtc.RTPCodecType][]*webrtc.RTPCodec) for _, kind := range []webrtc.RTPCodecType{ webrtc.RTPCodecTypeAudio, @@ -28,20 +28,51 @@ func NewMediaDevices(pc *webrtc.PeerConnection) MediaDevices { } { codecs[kind] = pc.GetRegisteredRTPCodecs(kind) } - - return &mediaDevices{codecs} + return NewMediaDevicesFromCodecs(codecs, opts...) } // NewMediaDevicesFromCodecs creates MediaDevices interface from lists of the available codecs // that provides access to connected media input devices like cameras and microphones, // as well as screen sharing. // In essence, it lets you obtain access to any hardware source of media data. -func NewMediaDevicesFromCodecs(codecs map[webrtc.RTPCodecType][]*webrtc.RTPCodec) MediaDevices { - return &mediaDevices{codecs} +func NewMediaDevicesFromCodecs(codecs map[webrtc.RTPCodecType][]*webrtc.RTPCodec, opts ...MediaDevicesOption) MediaDevices { + mdo := MediaDevicesOptions{ + codecs: codecs, + trackGenerator: defaultTrackGenerator, + } + for _, o := range opts { + o(&mdo) + } + return &mediaDevices{ + MediaDevicesOptions: mdo, + } } +// TrackGenerator is a function to create new track. +type TrackGenerator func(payloadType uint8, ssrc uint32, id, label string, codec *webrtc.RTPCodec) (LocalTrack, error) + +var defaultTrackGenerator = TrackGenerator(func(pt uint8, ssrc uint32, id, label string, codec *webrtc.RTPCodec) (LocalTrack, error) { + return webrtc.NewTrack(pt, ssrc, id, label, codec) +}) + type mediaDevices struct { - codecs map[webrtc.RTPCodecType][]*webrtc.RTPCodec + MediaDevicesOptions +} + +// MediaDevicesOptions stores parameters used by MediaDevices. +type MediaDevicesOptions struct { + codecs map[webrtc.RTPCodecType][]*webrtc.RTPCodec + trackGenerator TrackGenerator +} + +// MediaDevicesOption is a type of MediaDevices functional option. +type MediaDevicesOption func(*MediaDevicesOptions) + +// WithTrackGenerator specifies a TrackGenerator to use customized track. +func WithTrackGenerator(gen TrackGenerator) MediaDevicesOption { + return func(o *MediaDevicesOptions) { + o.trackGenerator = gen + } } // GetUserMedia prompts the user for permission to use a media input which produces a MediaStream @@ -161,7 +192,7 @@ func (m *mediaDevices) selectAudio(constraints MediaTrackConstraints) (Tracker, return nil, err } - return newAudioTrack(m.codecs[webrtc.RTPCodecTypeAudio], d, c) + return newAudioTrack(&m.MediaDevicesOptions, d, c) } func (m *mediaDevices) selectVideo(constraints MediaTrackConstraints) (Tracker, error) { filter := driver.FilterVideoRecorder() @@ -178,7 +209,7 @@ func (m *mediaDevices) selectVideo(constraints MediaTrackConstraints) (Tracker, return nil, err } - return newVideoTrack(m.codecs[webrtc.RTPCodecTypeVideo], d, c) + return newVideoTrack(&m.MediaDevicesOptions, d, c) } func (m *mediaDevices) EnumerateDevices() []MediaDeviceInfo { diff --git a/sampler.go b/sampler.go index 40d1642..ee8f37a 100644 --- a/sampler.go +++ b/sampler.go @@ -3,17 +3,16 @@ package mediadevices import ( "time" - "github.com/pion/webrtc/v2" "github.com/pion/webrtc/v2/pkg/media" ) type sampler struct { - track *webrtc.Track + track LocalTrack clockRate float64 lastTimestamp time.Time } -func newSampler(track *webrtc.Track) *sampler { +func newSampler(track LocalTrack) *sampler { return &sampler{ track: track, clockRate: float64(track.Codec().ClockRate), diff --git a/track.go b/track.go index 888d2be..21eee41 100644 --- a/track.go +++ b/track.go @@ -21,14 +21,19 @@ type Tracker interface { OnEnded(func(error)) } +type LocalTrack interface { + WriteSample(s media.Sample) error + Codec() *webrtc.RTPCodec +} + type track struct { - t *webrtc.Track + t LocalTrack s *sampler onErrorHandler atomic.Value // func(error) } -func newTrack(codecs []*webrtc.RTPCodec, d driver.Driver, codecName string) (*track, error) { +func newTrack(codecs []*webrtc.RTPCodec, trackGenerator TrackGenerator, d driver.Driver, codecName string) (*track, error) { var selectedCodec *webrtc.RTPCodec for _, c := range codecs { if c.Name == codecName { @@ -40,7 +45,7 @@ func newTrack(codecs []*webrtc.RTPCodec, d driver.Driver, codecName string) (*tr return nil, fmt.Errorf("track: %s is not registered in media engine", codecName) } - t, err := webrtc.NewTrack( + t, err := trackGenerator( selectedCodec.PayloadType, rand.Uint32(), d.ID(), @@ -69,7 +74,7 @@ func (t *track) onError(err error) { } func (t *track) Track() *webrtc.Track { - return t.t + return t.t.(*webrtc.Track) } type videoTrack struct { @@ -81,9 +86,9 @@ type videoTrack struct { var _ Tracker = &videoTrack{} -func newVideoTrack(codecs []*webrtc.RTPCodec, d driver.Driver, constraints MediaTrackConstraints) (*videoTrack, error) { +func newVideoTrack(opts *MediaDevicesOptions, d driver.Driver, constraints MediaTrackConstraints) (*videoTrack, error) { codecName := constraints.CodecName - t, err := newTrack(codecs, d, codecName) + t, err := newTrack(opts.codecs[webrtc.RTPCodecTypeVideo], opts.trackGenerator, d, codecName) if err != nil { return nil, err } @@ -156,9 +161,9 @@ type audioTrack struct { var _ Tracker = &audioTrack{} -func newAudioTrack(codecs []*webrtc.RTPCodec, d driver.Driver, constraints MediaTrackConstraints) (*audioTrack, error) { +func newAudioTrack(opts *MediaDevicesOptions, d driver.Driver, constraints MediaTrackConstraints) (*audioTrack, error) { codecName := constraints.CodecName - t, err := newTrack(codecs, d, codecName) + t, err := newTrack(opts.codecs[webrtc.RTPCodecTypeAudio], opts.trackGenerator, d, codecName) if err != nil { return nil, err }