mirror of
https://github.com/pion/mediadevices.git
synced 2026-04-23 00:07:29 +08:00
171 lines
3.8 KiB
Go
171 lines
3.8 KiB
Go
package prop
|
|
|
|
import (
|
|
"reflect"
|
|
"time"
|
|
|
|
"github.com/pion/mediadevices/pkg/frame"
|
|
)
|
|
|
|
type MediaConstraints struct {
|
|
DeviceID string
|
|
VideoConstraints
|
|
AudioConstraints
|
|
}
|
|
|
|
type Media struct {
|
|
DeviceID string
|
|
Video
|
|
Audio
|
|
}
|
|
|
|
// Merge merges all the field values from o to p, except zero values.
|
|
func (p *Media) Merge(o MediaConstraints) {
|
|
rp := reflect.ValueOf(p).Elem()
|
|
ro := reflect.ValueOf(o)
|
|
|
|
// merge b fields to a recursively
|
|
var merge func(a, b reflect.Value)
|
|
merge = func(a, b reflect.Value) {
|
|
numFields := a.NumField()
|
|
for i := 0; i < numFields; i++ {
|
|
fieldA := a.Field(i)
|
|
fieldB := b.Field(i)
|
|
|
|
// if b is a struct, a is also a struct. Then,
|
|
// we recursively merge them
|
|
if fieldB.Kind() == reflect.Struct {
|
|
merge(fieldA, fieldB)
|
|
continue
|
|
}
|
|
|
|
// TODO: Replace this with fieldB.IsZero() when we move to go1.13
|
|
// If non-boolean or non-discrete values are zeroes we skip them
|
|
if fieldB.Interface() == reflect.Zero(fieldB.Type()).Interface() &&
|
|
fieldB.Kind() != reflect.Bool {
|
|
continue
|
|
}
|
|
|
|
switch c := fieldB.Interface().(type) {
|
|
case IntConstraint:
|
|
if v, ok := c.Value(); ok {
|
|
fieldA.Set(reflect.ValueOf(v))
|
|
}
|
|
case FloatConstraint:
|
|
if v, ok := c.Value(); ok {
|
|
fieldA.Set(reflect.ValueOf(v))
|
|
}
|
|
case DurationConstraint:
|
|
if v, ok := c.Value(); ok {
|
|
fieldA.Set(reflect.ValueOf(v))
|
|
}
|
|
case FrameFormatConstraint:
|
|
if v, ok := c.Value(); ok {
|
|
fieldA.Set(reflect.ValueOf(v))
|
|
}
|
|
default:
|
|
panic("unsupported property type")
|
|
}
|
|
}
|
|
}
|
|
|
|
merge(rp, ro)
|
|
}
|
|
|
|
func (p *MediaConstraints) FitnessDistance(o Media) (float64, bool) {
|
|
cmps := comparisons{}
|
|
cmps.add(p.Width, o.Width)
|
|
cmps.add(p.Height, o.Height)
|
|
cmps.add(p.FrameFormat, o.FrameFormat)
|
|
cmps.add(p.SampleRate, o.SampleRate)
|
|
cmps.add(p.Latency, o.Latency)
|
|
|
|
return cmps.fitnessDistance()
|
|
}
|
|
|
|
type comparisons []struct {
|
|
desired, actual interface{}
|
|
}
|
|
|
|
func (c *comparisons) add(desired, actual interface{}) {
|
|
if desired != nil {
|
|
*c = append(*c,
|
|
struct{ desired, actual interface{} }{
|
|
desired, actual,
|
|
},
|
|
)
|
|
}
|
|
}
|
|
|
|
// fitnessDistance is an implementation for https://w3c.github.io/mediacapture-main/#dfn-fitness-distance
|
|
func (c *comparisons) fitnessDistance() (float64, bool) {
|
|
var dist float64
|
|
for _, field := range *c {
|
|
var d float64
|
|
var ok bool
|
|
switch c := field.desired.(type) {
|
|
case IntConstraint:
|
|
if actual, typeOK := field.actual.(int); typeOK {
|
|
d, ok = c.Compare(actual)
|
|
} else {
|
|
panic("wrong type of actual value")
|
|
}
|
|
case FloatConstraint:
|
|
if actual, typeOK := field.actual.(float32); typeOK {
|
|
d, ok = c.Compare(actual)
|
|
} else {
|
|
panic("wrong type of actual value")
|
|
}
|
|
case DurationConstraint:
|
|
if actual, typeOK := field.actual.(time.Duration); typeOK {
|
|
d, ok = c.Compare(actual)
|
|
} else {
|
|
panic("wrong type of actual value")
|
|
}
|
|
case FrameFormatConstraint:
|
|
if actual, typeOK := field.actual.(frame.Format); typeOK {
|
|
d, ok = c.Compare(actual)
|
|
} else {
|
|
panic("wrong type of actual value")
|
|
}
|
|
default:
|
|
panic("unsupported constraint type")
|
|
}
|
|
dist += d
|
|
if !ok {
|
|
return 0, false
|
|
}
|
|
}
|
|
return dist, true
|
|
}
|
|
|
|
// VideoConstraints represents a video's constraints
|
|
type VideoConstraints struct {
|
|
Width, Height IntConstraint
|
|
FrameRate FloatConstraint
|
|
FrameFormat FrameFormatConstraint
|
|
}
|
|
|
|
// Video represents a video's constraints
|
|
type Video struct {
|
|
Width, Height int
|
|
FrameRate float32
|
|
FrameFormat frame.Format
|
|
}
|
|
|
|
// AudioConstraints represents an audio's constraints
|
|
type AudioConstraints struct {
|
|
ChannelCount IntConstraint
|
|
Latency DurationConstraint
|
|
SampleRate IntConstraint
|
|
SampleSize IntConstraint
|
|
}
|
|
|
|
// Audio represents an audio's constraints
|
|
type Audio struct {
|
|
ChannelCount int
|
|
Latency time.Duration
|
|
SampleRate int
|
|
SampleSize int
|
|
}
|