// Copyright 2023 LiveKit, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package buffer import ( "testing" "github.com/stretchr/testify/require" "github.com/livekit/protocol/livekit" ) func TestRidConversion(t *testing.T) { type RidAndLayer struct { rid string layer int32 } tests := []struct { name string trackInfo *livekit.TrackInfo ridToLayer map[string]RidAndLayer }{ { "no track info", nil, map[string]RidAndLayer{ "": {rid: QuarterResolution, layer: 0}, QuarterResolution: {rid: QuarterResolution, layer: 0}, HalfResolution: {rid: HalfResolution, layer: 1}, FullResolution: {rid: FullResolution, layer: 2}, }, }, { "no layers", &livekit.TrackInfo{}, map[string]RidAndLayer{ "": {rid: QuarterResolution, layer: 0}, QuarterResolution: {rid: QuarterResolution, layer: 0}, HalfResolution: {rid: HalfResolution, layer: 1}, FullResolution: {rid: FullResolution, layer: 2}, }, }, { "single layer, low", &livekit.TrackInfo{ Layers: []*livekit.VideoLayer{ {Quality: livekit.VideoQuality_LOW}, }, }, map[string]RidAndLayer{ "": {rid: QuarterResolution, layer: 0}, QuarterResolution: {rid: QuarterResolution, layer: 0}, HalfResolution: {rid: QuarterResolution, layer: 0}, FullResolution: {rid: QuarterResolution, layer: 0}, }, }, { "single layer, medium", &livekit.TrackInfo{ Layers: []*livekit.VideoLayer{ {Quality: livekit.VideoQuality_MEDIUM}, }, }, map[string]RidAndLayer{ "": {rid: QuarterResolution, layer: 0}, QuarterResolution: {rid: QuarterResolution, layer: 0}, HalfResolution: {rid: QuarterResolution, layer: 0}, FullResolution: {rid: QuarterResolution, layer: 0}, }, }, { "single layer, high", &livekit.TrackInfo{ Layers: []*livekit.VideoLayer{ {Quality: livekit.VideoQuality_HIGH}, }, }, map[string]RidAndLayer{ "": {rid: QuarterResolution, layer: 0}, QuarterResolution: {rid: QuarterResolution, layer: 0}, HalfResolution: {rid: QuarterResolution, layer: 0}, FullResolution: {rid: QuarterResolution, layer: 0}, }, }, { "two layers, low and medium", &livekit.TrackInfo{ Layers: []*livekit.VideoLayer{ {Quality: livekit.VideoQuality_LOW}, {Quality: livekit.VideoQuality_MEDIUM}, }, }, map[string]RidAndLayer{ "": {rid: QuarterResolution, layer: 0}, QuarterResolution: {rid: QuarterResolution, layer: 0}, HalfResolution: {rid: HalfResolution, layer: 1}, FullResolution: {rid: HalfResolution, layer: 1}, }, }, { "two layers, low and high", &livekit.TrackInfo{ Layers: []*livekit.VideoLayer{ {Quality: livekit.VideoQuality_LOW}, {Quality: livekit.VideoQuality_HIGH}, }, }, map[string]RidAndLayer{ "": {rid: QuarterResolution, layer: 0}, QuarterResolution: {rid: QuarterResolution, layer: 0}, HalfResolution: {rid: HalfResolution, layer: 1}, FullResolution: {rid: HalfResolution, layer: 1}, }, }, { "two layers, medium and high", &livekit.TrackInfo{ Layers: []*livekit.VideoLayer{ {Quality: livekit.VideoQuality_MEDIUM}, {Quality: livekit.VideoQuality_HIGH}, }, }, map[string]RidAndLayer{ "": {rid: QuarterResolution, layer: 0}, QuarterResolution: {rid: QuarterResolution, layer: 0}, HalfResolution: {rid: HalfResolution, layer: 1}, FullResolution: {rid: HalfResolution, layer: 1}, }, }, { "three layers", &livekit.TrackInfo{ Layers: []*livekit.VideoLayer{ {Quality: livekit.VideoQuality_LOW}, {Quality: livekit.VideoQuality_MEDIUM}, {Quality: livekit.VideoQuality_HIGH}, }, }, map[string]RidAndLayer{ "": {rid: QuarterResolution, layer: 0}, QuarterResolution: {rid: QuarterResolution, layer: 0}, HalfResolution: {rid: HalfResolution, layer: 1}, FullResolution: {rid: FullResolution, layer: 2}, }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { for testRid, expectedResult := range test.ridToLayer { actualLayer := RidToSpatialLayer(testRid, test.trackInfo) require.Equal(t, expectedResult.layer, actualLayer) actualRid := SpatialLayerToRid(actualLayer, test.trackInfo) require.Equal(t, expectedResult.rid, actualRid) } }) } } func TestQualityConversion(t *testing.T) { type QualityAndLayer struct { quality livekit.VideoQuality layer int32 } tests := []struct { name string trackInfo *livekit.TrackInfo qualityToLayer map[livekit.VideoQuality]QualityAndLayer }{ { "no track info", nil, map[livekit.VideoQuality]QualityAndLayer{ livekit.VideoQuality_LOW: {quality: livekit.VideoQuality_LOW, layer: 0}, livekit.VideoQuality_MEDIUM: {quality: livekit.VideoQuality_MEDIUM, layer: 1}, livekit.VideoQuality_HIGH: {quality: livekit.VideoQuality_HIGH, layer: 2}, }, }, { "no layers", &livekit.TrackInfo{}, map[livekit.VideoQuality]QualityAndLayer{ livekit.VideoQuality_LOW: {quality: livekit.VideoQuality_LOW, layer: 0}, livekit.VideoQuality_MEDIUM: {quality: livekit.VideoQuality_MEDIUM, layer: 1}, livekit.VideoQuality_HIGH: {quality: livekit.VideoQuality_HIGH, layer: 2}, }, }, { "single layer, low", &livekit.TrackInfo{ Layers: []*livekit.VideoLayer{ {Quality: livekit.VideoQuality_LOW}, }, }, map[livekit.VideoQuality]QualityAndLayer{ livekit.VideoQuality_LOW: {quality: livekit.VideoQuality_LOW, layer: 0}, livekit.VideoQuality_MEDIUM: {quality: livekit.VideoQuality_LOW, layer: 0}, livekit.VideoQuality_HIGH: {quality: livekit.VideoQuality_LOW, layer: 0}, }, }, { "single layer, medium", &livekit.TrackInfo{ Layers: []*livekit.VideoLayer{ {Quality: livekit.VideoQuality_MEDIUM}, }, }, map[livekit.VideoQuality]QualityAndLayer{ livekit.VideoQuality_LOW: {quality: livekit.VideoQuality_MEDIUM, layer: 0}, livekit.VideoQuality_MEDIUM: {quality: livekit.VideoQuality_MEDIUM, layer: 0}, livekit.VideoQuality_HIGH: {quality: livekit.VideoQuality_MEDIUM, layer: 0}, }, }, { "single layer, high", &livekit.TrackInfo{ Layers: []*livekit.VideoLayer{ {Quality: livekit.VideoQuality_HIGH}, }, }, map[livekit.VideoQuality]QualityAndLayer{ livekit.VideoQuality_LOW: {quality: livekit.VideoQuality_HIGH, layer: 0}, livekit.VideoQuality_MEDIUM: {quality: livekit.VideoQuality_HIGH, layer: 0}, livekit.VideoQuality_HIGH: {quality: livekit.VideoQuality_HIGH, layer: 0}, }, }, { "two layers, low and medium", &livekit.TrackInfo{ Layers: []*livekit.VideoLayer{ {Quality: livekit.VideoQuality_LOW}, {Quality: livekit.VideoQuality_MEDIUM}, }, }, map[livekit.VideoQuality]QualityAndLayer{ livekit.VideoQuality_LOW: {quality: livekit.VideoQuality_LOW, layer: 0}, livekit.VideoQuality_MEDIUM: {quality: livekit.VideoQuality_MEDIUM, layer: 1}, livekit.VideoQuality_HIGH: {quality: livekit.VideoQuality_MEDIUM, layer: 1}, }, }, { "two layers, low and high", &livekit.TrackInfo{ Layers: []*livekit.VideoLayer{ {Quality: livekit.VideoQuality_LOW}, {Quality: livekit.VideoQuality_HIGH}, }, }, map[livekit.VideoQuality]QualityAndLayer{ livekit.VideoQuality_LOW: {quality: livekit.VideoQuality_LOW, layer: 0}, livekit.VideoQuality_MEDIUM: {quality: livekit.VideoQuality_HIGH, layer: 1}, livekit.VideoQuality_HIGH: {quality: livekit.VideoQuality_HIGH, layer: 1}, }, }, { "two layers, medium and high", &livekit.TrackInfo{ Layers: []*livekit.VideoLayer{ {Quality: livekit.VideoQuality_MEDIUM}, {Quality: livekit.VideoQuality_HIGH}, }, }, map[livekit.VideoQuality]QualityAndLayer{ livekit.VideoQuality_LOW: {quality: livekit.VideoQuality_MEDIUM, layer: 0}, livekit.VideoQuality_MEDIUM: {quality: livekit.VideoQuality_MEDIUM, layer: 0}, livekit.VideoQuality_HIGH: {quality: livekit.VideoQuality_HIGH, layer: 1}, }, }, { "three layers", &livekit.TrackInfo{ Layers: []*livekit.VideoLayer{ {Quality: livekit.VideoQuality_LOW}, {Quality: livekit.VideoQuality_MEDIUM}, {Quality: livekit.VideoQuality_HIGH}, }, }, map[livekit.VideoQuality]QualityAndLayer{ livekit.VideoQuality_LOW: {quality: livekit.VideoQuality_LOW, layer: 0}, livekit.VideoQuality_MEDIUM: {quality: livekit.VideoQuality_MEDIUM, layer: 1}, livekit.VideoQuality_HIGH: {quality: livekit.VideoQuality_HIGH, layer: 2}, }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { for testQuality, expectedResult := range test.qualityToLayer { actualLayer := VideoQualityToSpatialLayer(testQuality, test.trackInfo) require.Equal(t, expectedResult.layer, actualLayer) actualQuality := SpatialLayerToVideoQuality(actualLayer, test.trackInfo) require.Equal(t, expectedResult.quality, actualQuality) } }) } } func TestVideoQualityToRidConversion(t *testing.T) { tests := []struct { name string trackInfo *livekit.TrackInfo qualityToRid map[livekit.VideoQuality]string }{ { "no track info", nil, map[livekit.VideoQuality]string{ livekit.VideoQuality_LOW: QuarterResolution, livekit.VideoQuality_MEDIUM: HalfResolution, livekit.VideoQuality_HIGH: FullResolution, }, }, { "no layers", &livekit.TrackInfo{}, map[livekit.VideoQuality]string{ livekit.VideoQuality_LOW: QuarterResolution, livekit.VideoQuality_MEDIUM: HalfResolution, livekit.VideoQuality_HIGH: FullResolution, }, }, { "single layer, low", &livekit.TrackInfo{ Layers: []*livekit.VideoLayer{ {Quality: livekit.VideoQuality_LOW}, }, }, map[livekit.VideoQuality]string{ livekit.VideoQuality_LOW: QuarterResolution, livekit.VideoQuality_MEDIUM: QuarterResolution, livekit.VideoQuality_HIGH: QuarterResolution, }, }, { "single layer, medium", &livekit.TrackInfo{ Layers: []*livekit.VideoLayer{ {Quality: livekit.VideoQuality_MEDIUM}, }, }, map[livekit.VideoQuality]string{ livekit.VideoQuality_LOW: QuarterResolution, livekit.VideoQuality_MEDIUM: QuarterResolution, livekit.VideoQuality_HIGH: QuarterResolution, }, }, { "single layer, high", &livekit.TrackInfo{ Layers: []*livekit.VideoLayer{ {Quality: livekit.VideoQuality_HIGH}, }, }, map[livekit.VideoQuality]string{ livekit.VideoQuality_LOW: QuarterResolution, livekit.VideoQuality_MEDIUM: QuarterResolution, livekit.VideoQuality_HIGH: QuarterResolution, }, }, { "two layers, low and medium", &livekit.TrackInfo{ Layers: []*livekit.VideoLayer{ {Quality: livekit.VideoQuality_LOW}, {Quality: livekit.VideoQuality_MEDIUM}, }, }, map[livekit.VideoQuality]string{ livekit.VideoQuality_LOW: QuarterResolution, livekit.VideoQuality_MEDIUM: HalfResolution, livekit.VideoQuality_HIGH: HalfResolution, }, }, { "two layers, low and high", &livekit.TrackInfo{ Layers: []*livekit.VideoLayer{ {Quality: livekit.VideoQuality_LOW}, {Quality: livekit.VideoQuality_HIGH}, }, }, map[livekit.VideoQuality]string{ livekit.VideoQuality_LOW: QuarterResolution, livekit.VideoQuality_MEDIUM: HalfResolution, livekit.VideoQuality_HIGH: HalfResolution, }, }, { "two layers, medium and high", &livekit.TrackInfo{ Layers: []*livekit.VideoLayer{ {Quality: livekit.VideoQuality_MEDIUM}, {Quality: livekit.VideoQuality_HIGH}, }, }, map[livekit.VideoQuality]string{ livekit.VideoQuality_LOW: QuarterResolution, livekit.VideoQuality_MEDIUM: QuarterResolution, livekit.VideoQuality_HIGH: HalfResolution, }, }, { "three layers", &livekit.TrackInfo{ Layers: []*livekit.VideoLayer{ {Quality: livekit.VideoQuality_LOW}, {Quality: livekit.VideoQuality_MEDIUM}, {Quality: livekit.VideoQuality_HIGH}, }, }, map[livekit.VideoQuality]string{ livekit.VideoQuality_LOW: QuarterResolution, livekit.VideoQuality_MEDIUM: HalfResolution, livekit.VideoQuality_HIGH: FullResolution, }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { for testQuality, expectedRid := range test.qualityToRid { actualRid := VideoQualityToRid(testQuality, test.trackInfo) require.Equal(t, expectedRid, actualRid) } }) } }