mirror of
https://github.com/aler9/gortsplib
synced 2025-10-05 15:16:51 +08:00
add base class for tracks
This commit is contained in:
42
track.go
42
track.go
@@ -18,13 +18,22 @@ type Track interface {
|
|||||||
GetControl() string
|
GetControl() string
|
||||||
// SetControl sets the track control.
|
// SetControl sets the track control.
|
||||||
SetControl(string)
|
SetControl(string)
|
||||||
// MediaDescription returns the media description in SDP format.
|
// MediaDescription returns the track media description in SDP format.
|
||||||
MediaDescription() *psdp.MediaDescription
|
MediaDescription() *psdp.MediaDescription
|
||||||
clone() Track
|
clone() Track
|
||||||
url(*base.URL) (*base.URL, error)
|
url(*base.URL) (*base.URL, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTrackFromMediaDescription(md *psdp.MediaDescription) (Track, error) {
|
func newTrackFromMediaDescription(md *psdp.MediaDescription) (Track, error) {
|
||||||
|
control := func() string {
|
||||||
|
for _, attr := range md.Attributes {
|
||||||
|
if attr.Key == "control" {
|
||||||
|
return attr.Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}()
|
||||||
|
|
||||||
rtpmapPart1, payloadType := func() (string, uint8) {
|
rtpmapPart1, payloadType := func() (string, uint8) {
|
||||||
rtpmap, ok := md.Attribute("rtpmap")
|
rtpmap, ok := md.Attribute("rtpmap")
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -49,35 +58,40 @@ func newTrackFromMediaDescription(md *psdp.MediaDescription) (Track, error) {
|
|||||||
switch {
|
switch {
|
||||||
case md.MediaName.Media == "video":
|
case md.MediaName.Media == "video":
|
||||||
if rtpmapPart1 == "H264/90000" {
|
if rtpmapPart1 == "H264/90000" {
|
||||||
return newTrackH264FromMediaDescription(payloadType, md)
|
return newTrackH264FromMediaDescription(control, payloadType, md)
|
||||||
}
|
}
|
||||||
|
|
||||||
case md.MediaName.Media == "audio":
|
case md.MediaName.Media == "audio":
|
||||||
switch {
|
switch {
|
||||||
case len(md.MediaName.Formats) == 1 && md.MediaName.Formats[0] == "0":
|
case len(md.MediaName.Formats) == 1 && md.MediaName.Formats[0] == "0":
|
||||||
return newTrackPCMUFromMediaDescription(rtpmapPart1, md)
|
return newTrackPCMUFromMediaDescription(control, rtpmapPart1, md)
|
||||||
|
|
||||||
case strings.HasPrefix(strings.ToLower(rtpmapPart1), "mpeg4-generic/"):
|
case strings.HasPrefix(strings.ToLower(rtpmapPart1), "mpeg4-generic/"):
|
||||||
return newTrackAACFromMediaDescription(payloadType, md)
|
return newTrackAACFromMediaDescription(control, payloadType, md)
|
||||||
|
|
||||||
case strings.HasPrefix(rtpmapPart1, "opus/"):
|
case strings.HasPrefix(rtpmapPart1, "opus/"):
|
||||||
return newTrackOpusFromMediaDescription(payloadType, rtpmapPart1, md)
|
return newTrackOpusFromMediaDescription(control, payloadType, rtpmapPart1, md)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return newTrackGenericFromMediaDescription(md)
|
return newTrackGenericFromMediaDescription(control, md)
|
||||||
}
|
}
|
||||||
|
|
||||||
func trackFindControl(md *psdp.MediaDescription) string {
|
type trackBase struct {
|
||||||
for _, attr := range md.Attributes {
|
control string
|
||||||
if attr.Key == "control" {
|
|
||||||
return attr.Value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func trackURL(t Track, contentBase *base.URL) (*base.URL, error) {
|
// GetControl gets the track control.
|
||||||
|
func (t *trackBase) GetControl() string {
|
||||||
|
return t.control
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetControl sets the track control.
|
||||||
|
func (t *trackBase) SetControl(c string) {
|
||||||
|
t.control = c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *trackBase) url(contentBase *base.URL) (*base.URL, error) {
|
||||||
if contentBase == nil {
|
if contentBase == nil {
|
||||||
return nil, fmt.Errorf("Content-Base header not provided")
|
return nil, fmt.Errorf("Content-Base header not provided")
|
||||||
}
|
}
|
||||||
|
28
track_aac.go
28
track_aac.go
@@ -9,12 +9,11 @@ import (
|
|||||||
psdp "github.com/pion/sdp/v3"
|
psdp "github.com/pion/sdp/v3"
|
||||||
|
|
||||||
"github.com/aler9/gortsplib/pkg/aac"
|
"github.com/aler9/gortsplib/pkg/aac"
|
||||||
"github.com/aler9/gortsplib/pkg/base"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// TrackAAC is an AAC track.
|
// TrackAAC is an AAC track.
|
||||||
type TrackAAC struct {
|
type TrackAAC struct {
|
||||||
control string
|
trackBase
|
||||||
payloadType uint8
|
payloadType uint8
|
||||||
typ int
|
typ int
|
||||||
sampleRate int
|
sampleRate int
|
||||||
@@ -47,10 +46,9 @@ func NewTrackAAC(payloadType uint8, typ int, sampleRate int,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newTrackAACFromMediaDescription(
|
func newTrackAACFromMediaDescription(
|
||||||
|
control string,
|
||||||
payloadType uint8,
|
payloadType uint8,
|
||||||
md *psdp.MediaDescription) (*TrackAAC, error) {
|
md *psdp.MediaDescription) (*TrackAAC, error) {
|
||||||
control := trackFindControl(md)
|
|
||||||
|
|
||||||
v, ok := md.Attribute("fmtp")
|
v, ok := md.Attribute("fmtp")
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("fmtp attribute is missing")
|
return nil, fmt.Errorf("fmtp attribute is missing")
|
||||||
@@ -89,7 +87,9 @@ func newTrackAACFromMediaDescription(
|
|||||||
enc, _ = mpegConf.Encode()
|
enc, _ = mpegConf.Encode()
|
||||||
|
|
||||||
return &TrackAAC{
|
return &TrackAAC{
|
||||||
control: control,
|
trackBase: trackBase{
|
||||||
|
control: control,
|
||||||
|
},
|
||||||
payloadType: payloadType,
|
payloadType: payloadType,
|
||||||
typ: int(mpegConf.Type),
|
typ: int(mpegConf.Type),
|
||||||
sampleRate: mpegConf.SampleRate,
|
sampleRate: mpegConf.SampleRate,
|
||||||
@@ -125,7 +125,7 @@ func (t *TrackAAC) AOTSpecificConfig() []byte {
|
|||||||
|
|
||||||
func (t *TrackAAC) clone() Track {
|
func (t *TrackAAC) clone() Track {
|
||||||
return &TrackAAC{
|
return &TrackAAC{
|
||||||
control: t.control,
|
trackBase: t.trackBase,
|
||||||
payloadType: t.payloadType,
|
payloadType: t.payloadType,
|
||||||
typ: t.typ,
|
typ: t.typ,
|
||||||
sampleRate: t.sampleRate,
|
sampleRate: t.sampleRate,
|
||||||
@@ -135,21 +135,7 @@ func (t *TrackAAC) clone() Track {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetControl gets the track control.
|
// MediaDescription returns the track media description in SDP format.
|
||||||
func (t *TrackAAC) GetControl() string {
|
|
||||||
return t.control
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetControl sets the track control.
|
|
||||||
func (t *TrackAAC) SetControl(c string) {
|
|
||||||
t.control = c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *TrackAAC) url(contentBase *base.URL) (*base.URL, error) {
|
|
||||||
return trackURL(t, contentBase)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MediaDescription returns the media description in SDP format.
|
|
||||||
func (t *TrackAAC) MediaDescription() *psdp.MediaDescription {
|
func (t *TrackAAC) MediaDescription() *psdp.MediaDescription {
|
||||||
typ := strconv.FormatInt(int64(t.payloadType), 10)
|
typ := strconv.FormatInt(int64(t.payloadType), 10)
|
||||||
|
|
||||||
|
@@ -6,8 +6,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
psdp "github.com/pion/sdp/v3"
|
psdp "github.com/pion/sdp/v3"
|
||||||
|
|
||||||
"github.com/aler9/gortsplib/pkg/base"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func trackGenericGetClockRate(formats []string, rtpmap string) (int, error) {
|
func trackGenericGetClockRate(formats []string, rtpmap string) (int, error) {
|
||||||
@@ -63,7 +61,7 @@ func trackGenericGetClockRate(formats []string, rtpmap string) (int, error) {
|
|||||||
|
|
||||||
// TrackGeneric is a generic track.
|
// TrackGeneric is a generic track.
|
||||||
type TrackGeneric struct {
|
type TrackGeneric struct {
|
||||||
control string
|
trackBase
|
||||||
clockRate int
|
clockRate int
|
||||||
media string
|
media string
|
||||||
formats []string
|
formats []string
|
||||||
@@ -87,9 +85,9 @@ func NewTrackGeneric(media string, formats []string, rtpmap string, fmtp string)
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTrackGenericFromMediaDescription(md *psdp.MediaDescription) (*TrackGeneric, error) {
|
func newTrackGenericFromMediaDescription(
|
||||||
control := trackFindControl(md)
|
control string,
|
||||||
|
md *psdp.MediaDescription) (*TrackGeneric, error) {
|
||||||
rtpmap := func() string {
|
rtpmap := func() string {
|
||||||
for _, attr := range md.Attributes {
|
for _, attr := range md.Attributes {
|
||||||
if attr.Key == "rtpmap" {
|
if attr.Key == "rtpmap" {
|
||||||
@@ -114,7 +112,9 @@ func newTrackGenericFromMediaDescription(md *psdp.MediaDescription) (*TrackGener
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
return &TrackGeneric{
|
return &TrackGeneric{
|
||||||
control: control,
|
trackBase: trackBase{
|
||||||
|
control: control,
|
||||||
|
},
|
||||||
clockRate: clockRate,
|
clockRate: clockRate,
|
||||||
media: md.MediaName.Media,
|
media: md.MediaName.Media,
|
||||||
formats: md.MediaName.Formats,
|
formats: md.MediaName.Formats,
|
||||||
@@ -130,7 +130,7 @@ func (t *TrackGeneric) ClockRate() int {
|
|||||||
|
|
||||||
func (t *TrackGeneric) clone() Track {
|
func (t *TrackGeneric) clone() Track {
|
||||||
return &TrackGeneric{
|
return &TrackGeneric{
|
||||||
control: t.control,
|
trackBase: t.trackBase,
|
||||||
clockRate: t.clockRate,
|
clockRate: t.clockRate,
|
||||||
media: t.media,
|
media: t.media,
|
||||||
formats: t.formats,
|
formats: t.formats,
|
||||||
@@ -139,21 +139,7 @@ func (t *TrackGeneric) clone() Track {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetControl returns the track control.
|
// MediaDescription returns the track media description in SDP format.
|
||||||
func (t *TrackGeneric) GetControl() string {
|
|
||||||
return t.control
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetControl set the track control.
|
|
||||||
func (t *TrackGeneric) SetControl(c string) {
|
|
||||||
t.control = c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *TrackGeneric) url(contentBase *base.URL) (*base.URL, error) {
|
|
||||||
return trackURL(t, contentBase)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MediaDescription returns the media description in SDP format.
|
|
||||||
func (t *TrackGeneric) MediaDescription() *psdp.MediaDescription {
|
func (t *TrackGeneric) MediaDescription() *psdp.MediaDescription {
|
||||||
return &psdp.MediaDescription{
|
return &psdp.MediaDescription{
|
||||||
MediaName: psdp.MediaName{
|
MediaName: psdp.MediaName{
|
||||||
|
@@ -31,26 +31,13 @@ func TestTrackGenericNewErrors(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestTrackGenericClone(t *testing.T) {
|
func TestTrackGenericClone(t *testing.T) {
|
||||||
track, err := newTrackGenericFromMediaDescription(
|
track, err := NewTrackGeneric(
|
||||||
&psdp.MediaDescription{
|
"video",
|
||||||
MediaName: psdp.MediaName{
|
[]string{"100", "101"},
|
||||||
Media: "video",
|
"98 H265/90000",
|
||||||
Port: psdp.RangedPort{Value: 0},
|
"98 profile-id=1; sprop-vps=QAEMAf//AWAAAAMAAAMAAAMAAAMAlqwJ; "+
|
||||||
Protos: []string{"RTP", "AVP"},
|
"sprop-sps=QgEBAWAAAAMAAAMAAAMAAAMAlqADwIAQ5Za5JMmuWcBSSgAAB9AAAHUwgkA=; sprop-pps=RAHgdrAwxmQ=",
|
||||||
Formats: []string{"98", "96"},
|
)
|
||||||
},
|
|
||||||
Attributes: []psdp.Attribute{
|
|
||||||
{
|
|
||||||
Key: "rtpmap",
|
|
||||||
Value: "98 H265/90000",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Key: "fmtp",
|
|
||||||
Value: "98 profile-id=1; sprop-vps=QAEMAf//AWAAAAMAAAMAAAMAAAMAlqwJ; " +
|
|
||||||
"sprop-sps=QgEBAWAAAAMAAAMAAAMAAAMAlqADwIAQ5Za5JMmuWcBSSgAAB9AAAHUwgkA=; sprop-pps=RAHgdrAwxmQ=",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
clone := track.clone()
|
clone := track.clone()
|
||||||
|
@@ -9,8 +9,6 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
psdp "github.com/pion/sdp/v3"
|
psdp "github.com/pion/sdp/v3"
|
||||||
|
|
||||||
"github.com/aler9/gortsplib/pkg/base"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func trackH264GetSPSPPS(md *psdp.MediaDescription) ([]byte, []byte, error) {
|
func trackH264GetSPSPPS(md *psdp.MediaDescription) ([]byte, []byte, error) {
|
||||||
@@ -61,7 +59,7 @@ func trackH264GetSPSPPS(md *psdp.MediaDescription) ([]byte, []byte, error) {
|
|||||||
|
|
||||||
// TrackH264 is a H264 track.
|
// TrackH264 is a H264 track.
|
||||||
type TrackH264 struct {
|
type TrackH264 struct {
|
||||||
control string
|
trackBase
|
||||||
payloadType uint8
|
payloadType uint8
|
||||||
sps []byte
|
sps []byte
|
||||||
pps []byte
|
pps []byte
|
||||||
@@ -80,12 +78,13 @@ func NewTrackH264(payloadType uint8, sps []byte, pps []byte, extradata []byte) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newTrackH264FromMediaDescription(
|
func newTrackH264FromMediaDescription(
|
||||||
|
control string,
|
||||||
payloadType uint8,
|
payloadType uint8,
|
||||||
md *psdp.MediaDescription) (*TrackH264, error) {
|
md *psdp.MediaDescription) (*TrackH264, error) {
|
||||||
control := trackFindControl(md)
|
|
||||||
|
|
||||||
t := &TrackH264{
|
t := &TrackH264{
|
||||||
control: control,
|
trackBase: trackBase{
|
||||||
|
control: control,
|
||||||
|
},
|
||||||
payloadType: payloadType,
|
payloadType: payloadType,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,7 +104,7 @@ func (t *TrackH264) ClockRate() int {
|
|||||||
|
|
||||||
func (t *TrackH264) clone() Track {
|
func (t *TrackH264) clone() Track {
|
||||||
return &TrackH264{
|
return &TrackH264{
|
||||||
control: t.control,
|
trackBase: t.trackBase,
|
||||||
payloadType: t.payloadType,
|
payloadType: t.payloadType,
|
||||||
sps: t.sps,
|
sps: t.sps,
|
||||||
pps: t.pps,
|
pps: t.pps,
|
||||||
@@ -113,20 +112,6 @@ func (t *TrackH264) clone() Track {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetControl gets the track control.
|
|
||||||
func (t *TrackH264) GetControl() string {
|
|
||||||
return t.control
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetControl sets the track control.
|
|
||||||
func (t *TrackH264) SetControl(c string) {
|
|
||||||
t.control = c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *TrackH264) url(contentBase *base.URL) (*base.URL, error) {
|
|
||||||
return trackURL(t, contentBase)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SPS returns the track SPS.
|
// SPS returns the track SPS.
|
||||||
func (t *TrackH264) SPS() []byte {
|
func (t *TrackH264) SPS() []byte {
|
||||||
t.mutex.RLock()
|
t.mutex.RLock()
|
||||||
@@ -160,7 +145,7 @@ func (t *TrackH264) SetPPS(v []byte) {
|
|||||||
t.pps = v
|
t.pps = v
|
||||||
}
|
}
|
||||||
|
|
||||||
// MediaDescription returns the media description in SDP format.
|
// MediaDescription returns the track media description in SDP format.
|
||||||
func (t *TrackH264) MediaDescription() *psdp.MediaDescription {
|
func (t *TrackH264) MediaDescription() *psdp.MediaDescription {
|
||||||
t.mutex.RLock()
|
t.mutex.RLock()
|
||||||
defer t.mutex.RUnlock()
|
defer t.mutex.RUnlock()
|
||||||
|
@@ -6,13 +6,11 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
psdp "github.com/pion/sdp/v3"
|
psdp "github.com/pion/sdp/v3"
|
||||||
|
|
||||||
"github.com/aler9/gortsplib/pkg/base"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// TrackOpus is a Opus track.
|
// TrackOpus is a Opus track.
|
||||||
type TrackOpus struct {
|
type TrackOpus struct {
|
||||||
control string
|
trackBase
|
||||||
payloadType uint8
|
payloadType uint8
|
||||||
sampleRate int
|
sampleRate int
|
||||||
channelCount int
|
channelCount int
|
||||||
@@ -28,11 +26,10 @@ func NewTrackOpus(payloadType uint8, sampleRate int, channelCount int) (*TrackOp
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newTrackOpusFromMediaDescription(
|
func newTrackOpusFromMediaDescription(
|
||||||
|
control string,
|
||||||
payloadType uint8,
|
payloadType uint8,
|
||||||
rtpmapPart1 string,
|
rtpmapPart1 string,
|
||||||
md *psdp.MediaDescription) (*TrackOpus, error) {
|
md *psdp.MediaDescription) (*TrackOpus, error) {
|
||||||
control := trackFindControl(md)
|
|
||||||
|
|
||||||
tmp := strings.SplitN(rtpmapPart1, "/", 3)
|
tmp := strings.SplitN(rtpmapPart1, "/", 3)
|
||||||
if len(tmp) != 3 {
|
if len(tmp) != 3 {
|
||||||
return nil, fmt.Errorf("invalid rtpmap (%v)", rtpmapPart1)
|
return nil, fmt.Errorf("invalid rtpmap (%v)", rtpmapPart1)
|
||||||
@@ -49,7 +46,9 @@ func newTrackOpusFromMediaDescription(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &TrackOpus{
|
return &TrackOpus{
|
||||||
control: control,
|
trackBase: trackBase{
|
||||||
|
control: control,
|
||||||
|
},
|
||||||
payloadType: payloadType,
|
payloadType: payloadType,
|
||||||
sampleRate: int(sampleRate),
|
sampleRate: int(sampleRate),
|
||||||
channelCount: int(channelCount),
|
channelCount: int(channelCount),
|
||||||
@@ -63,33 +62,19 @@ func (t *TrackOpus) ClockRate() int {
|
|||||||
|
|
||||||
func (t *TrackOpus) clone() Track {
|
func (t *TrackOpus) clone() Track {
|
||||||
return &TrackOpus{
|
return &TrackOpus{
|
||||||
control: t.control,
|
trackBase: t.trackBase,
|
||||||
payloadType: t.payloadType,
|
payloadType: t.payloadType,
|
||||||
sampleRate: t.sampleRate,
|
sampleRate: t.sampleRate,
|
||||||
channelCount: t.channelCount,
|
channelCount: t.channelCount,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetControl returns the track control.
|
|
||||||
func (t *TrackOpus) GetControl() string {
|
|
||||||
return t.control
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetControl sets the track control.
|
|
||||||
func (t *TrackOpus) SetControl(c string) {
|
|
||||||
t.control = c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *TrackOpus) url(contentBase *base.URL) (*base.URL, error) {
|
|
||||||
return trackURL(t, contentBase)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ChannelCount returns the channel count.
|
// ChannelCount returns the channel count.
|
||||||
func (t *TrackOpus) ChannelCount() int {
|
func (t *TrackOpus) ChannelCount() int {
|
||||||
return t.channelCount
|
return t.channelCount
|
||||||
}
|
}
|
||||||
|
|
||||||
// MediaDescription returns the media description in SDP format.
|
// MediaDescription returns the track media description in SDP format.
|
||||||
func (t *TrackOpus) MediaDescription() *psdp.MediaDescription {
|
func (t *TrackOpus) MediaDescription() *psdp.MediaDescription {
|
||||||
typ := strconv.FormatInt(int64(t.payloadType), 10)
|
typ := strconv.FormatInt(int64(t.payloadType), 10)
|
||||||
|
|
||||||
|
@@ -5,13 +5,11 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
psdp "github.com/pion/sdp/v3"
|
psdp "github.com/pion/sdp/v3"
|
||||||
|
|
||||||
"github.com/aler9/gortsplib/pkg/base"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// TrackPCMU is a PCMU track.
|
// TrackPCMU is a PCMU track.
|
||||||
type TrackPCMU struct {
|
type TrackPCMU struct {
|
||||||
control string
|
trackBase
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTrackPCMU allocates a TrackPCMU.
|
// NewTrackPCMU allocates a TrackPCMU.
|
||||||
@@ -19,18 +17,20 @@ func NewTrackPCMU() *TrackPCMU {
|
|||||||
return &TrackPCMU{}
|
return &TrackPCMU{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTrackPCMUFromMediaDescription(rtpmapPart1 string,
|
func newTrackPCMUFromMediaDescription(
|
||||||
|
control string,
|
||||||
|
rtpmapPart1 string,
|
||||||
md *psdp.MediaDescription) (*TrackPCMU, error,
|
md *psdp.MediaDescription) (*TrackPCMU, error,
|
||||||
) {
|
) {
|
||||||
control := trackFindControl(md)
|
|
||||||
|
|
||||||
tmp := strings.Split(rtpmapPart1, "/")
|
tmp := strings.Split(rtpmapPart1, "/")
|
||||||
if len(tmp) >= 3 && tmp[2] != "1" {
|
if len(tmp) >= 3 && tmp[2] != "1" {
|
||||||
return nil, fmt.Errorf("PCMU tracks must have only one channel")
|
return nil, fmt.Errorf("PCMU tracks must have only one channel")
|
||||||
}
|
}
|
||||||
|
|
||||||
return &TrackPCMU{
|
return &TrackPCMU{
|
||||||
control: control,
|
trackBase: trackBase{
|
||||||
|
control: control,
|
||||||
|
},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,24 +40,12 @@ func (t *TrackPCMU) ClockRate() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *TrackPCMU) clone() Track {
|
func (t *TrackPCMU) clone() Track {
|
||||||
return &TrackPCMU{}
|
return &TrackPCMU{
|
||||||
|
trackBase: t.trackBase,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetControl returns the track control.
|
// MediaDescription returns the track media description in SDP format.
|
||||||
func (t *TrackPCMU) GetControl() string {
|
|
||||||
return t.control
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetControl sets the track control.
|
|
||||||
func (t *TrackPCMU) SetControl(c string) {
|
|
||||||
t.control = c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *TrackPCMU) url(contentBase *base.URL) (*base.URL, error) {
|
|
||||||
return trackURL(t, contentBase)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MediaDescription returns the media description in SDP format.
|
|
||||||
func (t *TrackPCMU) MediaDescription() *psdp.MediaDescription {
|
func (t *TrackPCMU) MediaDescription() *psdp.MediaDescription {
|
||||||
return &psdp.MediaDescription{
|
return &psdp.MediaDescription{
|
||||||
MediaName: psdp.MediaName{
|
MediaName: psdp.MediaName{
|
||||||
|
@@ -71,13 +71,17 @@ func TestTracksReadSkipGenericTracksWithoutClockRate(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, Tracks{
|
require.Equal(t, Tracks{
|
||||||
&TrackH264{
|
&TrackH264{
|
||||||
control: "rtsp://10.0.100.50/profile5/media.smp/trackID=v",
|
trackBase: trackBase{
|
||||||
|
control: "rtsp://10.0.100.50/profile5/media.smp/trackID=v",
|
||||||
|
},
|
||||||
payloadType: 97,
|
payloadType: 97,
|
||||||
sps: []byte{0x67, 0x64, 0x00, 0x28, 0xac, 0xb4, 0x03, 0xc0, 0x11, 0x3f, 0x2a},
|
sps: []byte{0x67, 0x64, 0x00, 0x28, 0xac, 0xb4, 0x03, 0xc0, 0x11, 0x3f, 0x2a},
|
||||||
pps: []byte{0x68, 0xee, 0x01, 0x9e, 0x2c},
|
pps: []byte{0x68, 0xee, 0x01, 0x9e, 0x2c},
|
||||||
},
|
},
|
||||||
&TrackPCMU{
|
&TrackPCMU{
|
||||||
control: "rtsp://10.0.100.50/profile5/media.smp/trackID=a",
|
trackBase: trackBase{
|
||||||
|
control: "rtsp://10.0.100.50/profile5/media.smp/trackID=a",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}, tracks)
|
}, tracks)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user