commit 34d647b964d037705c244de67dc552c4ce4615ca from: Arthur D via: Oliver Lowe date: Fri Nov 22 12:32:10 2024 UTC fix: play rate as decimal commit - b80fe72bf0cda6e47989801e6e86bb43a03bb2d7 commit + 34d647b964d037705c244de67dc552c4ce4615ca blob - bcc642c48bfe1dd82e61480b9e2d5039f6f4cfcf blob + 4322f741a1d5e112fd23905798979f462583b578 --- cmcd/cmcd.go +++ cmcd/cmcd.go @@ -177,10 +177,8 @@ type Session struct { // A GUID uniquely identifying the session, no longer than 64 // characters. ID string - // Type of the stream. If false, all playback segments are - // available. Otherwise, the stream is considered live, and - // segments become available over time. - Live bool + // Type of the stream. + StreamType // A unique identifier of the client's requested content, no // longer than 64 characters. ContentID string @@ -191,7 +189,7 @@ type Session struct { version int } -type PlayRate uint8 +type PlayRate float32 const ( Stopped PlayRate = iota @@ -199,6 +197,15 @@ const ( DoubleTime ) +type StreamType string + +const ( + StreamTypeLive = "l" + StreamTypeVOD = "v" +) + +func (st StreamType) Live() bool { return st == StreamTypeLive } + type StreamFormat byte const ( blob - ff0ea49c4660baa3cae04b5e4bea918c48b357cf blob + 43ce46bdbc9d6a0dffdb502cca309dde37f15a07 --- cmcd/encode.go +++ cmcd/encode.go @@ -74,7 +74,7 @@ func (s Session) Encode() string { } // "SHOULD only be sent if not equal to 1": CTA-5004 page 10. if s.PlayRate != RealTime { - attrs = append(attrs, fmt.Sprintf("pr=%d", s.PlayRate)) + attrs = append(attrs, fmt.Sprintf("pr=%v", s.PlayRate)) } switch s.Format { case FormatDASH, FormatHLS, FormatSmooth, FormatOther: blob - 9953bedc24fc87e74c1617770ec879ca933a5575 blob + 17b47b0646e4807d119c73cea84547a759baebe1 --- cmcd/parse.go +++ cmcd/parse.go @@ -132,21 +132,16 @@ func parseSession(attrs map[string]string) (Session, e ses.ID = strings.Trim(v, `"`) case "st": // TODO(otl): what if it's not "l"? - if v == "l" { - ses.Live = true - } + ses.StreamType = StreamType(v) case "cid": ses.ContentID = strings.Trim(v, `"`) case "pr": - i, err := strconv.Atoi(v) + i, err := strconv.ParseFloat(v, 32) if err != nil { return ses, fmt.Errorf("play rate: %w", err) } // TODO(otl): what is this max value? why? // Include in the error message. - if i > 2 { - return ses, fmt.Errorf("play rate: %d greater than max %d", i, 2) - } ses.PlayRate = PlayRate(i) case "sf": if len(v) != 1 { blob - c2237430c715ac2745d64bf9e4e87a57db4bc573 blob + 5bf1b26ece0d4e63f32e54c2948ad3bde85f309d --- cmcd/parse_test.go +++ cmcd/parse_test.go @@ -15,10 +15,10 @@ import ( ) var tests = map[string]Info{ - "testdata/simple": Info{ + "testdata/simple": { Session: Session{ID: "6e2fb550-c457-11e9-bb97-0800200c9a66", PlayRate: RealTime}, }, - "testdata/all_four": Info{ + "testdata/all_four": { Request: Request{Throughput: 25400}, Object: Object{ Bitrate: 3200, @@ -29,17 +29,17 @@ var tests = map[string]Info{ Status: Status{true, 15000}, Session: Session{ID: "6e2fb550-c457-11e9-bb97-0800200c9a66", PlayRate: RealTime}, }, - "testdata/booleans": Info{ + "testdata/booleans": { Status: Status{true, 0}, Request: Request{Startup: true}, Session: Session{PlayRate: RealTime}, }, - "testdata/range": Info{ + "testdata/range": { Request: Request{NextRange: [2]int{12323, 48763}}, Object: Object{Duration: 4004 * time.Millisecond}, Session: Session{PlayRate: RealTime}, }, - "testdata/custom": Info{ + "testdata/custom": { Object: Object{Duration: 4004 * time.Millisecond}, Session: Session{PlayRate: RealTime}, Custom: map[string]any{