1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chromecast/media/cma/backend/android/volume_cache.h"
6 
7 #include <cmath>
8 
9 #include "testing/gtest/include/gtest/gtest.h"
10 
11 namespace chromecast {
12 namespace media {
13 
14 namespace {
15 const int kMaxVolumeIndex = 10;
16 
17 const float kTestVolumeTable[kMaxVolumeIndex + 1] = {
18     -100.0f, -88.0f, -82.0f, -70.0f, -62.5f, -49.9f,
19     -40.5f,  -30.0f, -28.2f, -10.0f, 0.0f};
20 
21 }  // namespace
22 
23 class VolumeCacheTest : protected SystemVolumeTableAccessApi,
24                         public testing::Test {
25  protected:
VolumeCacheTest()26   VolumeCacheTest() : volume_cache_(AudioContentType::kMedia, this) {}
27 
~VolumeCacheTest()28   ~VolumeCacheTest() override {}
29 
30   // SystemVolumeTableAccessApi implementation.
31   // We use kTestVolumeTable for kMedia and just return -1.0f for other types.
32   // That allows to test if the type is properly used in the c'tor.
GetMaxVolumeIndex(AudioContentType type)33   int GetMaxVolumeIndex(AudioContentType type) override {
34     return (type == AudioContentType::kMedia) ? kMaxVolumeIndex : 2;
35   }
VolumeToDbFS(AudioContentType type,float volume)36   float VolumeToDbFS(AudioContentType type, float volume) override {
37     if (type != AudioContentType::kMedia)
38       return -1.0f;
39 
40     int idx_vol = static_cast<int>(std::round(volume * kMaxVolumeIndex));
41     return kTestVolumeTable[idx_vol];
42   }
43 
44   VolumeCache volume_cache_;
45 };
46 
TEST_F(VolumeCacheTest,CachedValuesMatchesOriginalTable)47 TEST_F(VolumeCacheTest, CachedValuesMatchesOriginalTable) {
48   for (int i = 0; i <= kMaxVolumeIndex; i++) {
49     float v = static_cast<float>(i) / kMaxVolumeIndex;
50     EXPECT_FLOAT_EQ(kTestVolumeTable[i], volume_cache_.VolumeToDbFS(v));
51     float db = kTestVolumeTable[i];
52     EXPECT_FLOAT_EQ(v, volume_cache_.DbFSToVolume(db));
53   }
54 }
55 
TEST_F(VolumeCacheTest,BoundaryValues)56 TEST_F(VolumeCacheTest, BoundaryValues) {
57   EXPECT_FLOAT_EQ(kTestVolumeTable[0], volume_cache_.VolumeToDbFS(-100.0f));
58   EXPECT_FLOAT_EQ(kTestVolumeTable[0], volume_cache_.VolumeToDbFS(-1.0f));
59   EXPECT_FLOAT_EQ(kTestVolumeTable[0], volume_cache_.VolumeToDbFS(-0.1f));
60   EXPECT_FLOAT_EQ(kTestVolumeTable[0], volume_cache_.VolumeToDbFS(0.0f));
61 
62   EXPECT_FLOAT_EQ(kTestVolumeTable[kMaxVolumeIndex],
63                   volume_cache_.VolumeToDbFS(1.0f));
64   EXPECT_FLOAT_EQ(kTestVolumeTable[kMaxVolumeIndex],
65                   volume_cache_.VolumeToDbFS(1.1f));
66   EXPECT_FLOAT_EQ(kTestVolumeTable[kMaxVolumeIndex],
67                   volume_cache_.VolumeToDbFS(2.0f));
68   EXPECT_FLOAT_EQ(kTestVolumeTable[kMaxVolumeIndex],
69                   volume_cache_.VolumeToDbFS(100.0f));
70 
71   float min_db = kTestVolumeTable[0];
72   EXPECT_FLOAT_EQ(0.0f, volume_cache_.DbFSToVolume(min_db - 100.0f));
73   EXPECT_FLOAT_EQ(0.0f, volume_cache_.DbFSToVolume(min_db - 1.0f));
74   EXPECT_FLOAT_EQ(0.0f, volume_cache_.DbFSToVolume(min_db - 0.1f));
75   EXPECT_FLOAT_EQ(0.0f, volume_cache_.DbFSToVolume(min_db - 0.0f));
76 
77   float max_db = kTestVolumeTable[kMaxVolumeIndex];
78   EXPECT_FLOAT_EQ(1.0f, volume_cache_.DbFSToVolume(max_db + 0.0f));
79   EXPECT_FLOAT_EQ(1.0f, volume_cache_.DbFSToVolume(max_db + 0.1f));
80   EXPECT_FLOAT_EQ(1.0f, volume_cache_.DbFSToVolume(max_db + 1.0f));
81   EXPECT_FLOAT_EQ(1.0f, volume_cache_.DbFSToVolume(max_db + 100.0f));
82 }
83 
TEST_F(VolumeCacheTest,Volume2DbFSInterpolatesCorrectly)84 TEST_F(VolumeCacheTest, Volume2DbFSInterpolatesCorrectly) {
85   int i_low = 0, i_high = 1;
86   for (; i_high <= kMaxVolumeIndex; ++i_high, ++i_low) {
87     float v_low = static_cast<float>(i_low) / kMaxVolumeIndex;
88     float v_high = static_cast<float>(i_high) / kMaxVolumeIndex;
89     float db_low = kTestVolumeTable[i_low];
90     float db_high = kTestVolumeTable[i_high];
91     float m = (db_high - db_low) / (v_high - v_low);
92     for (float v = v_low; v <= v_high; v += 0.1f) {
93       float expected_db = db_low + m * (v - v_low);
94       EXPECT_FLOAT_EQ(expected_db, volume_cache_.VolumeToDbFS(v));
95     }
96   }
97 }
98 
TEST_F(VolumeCacheTest,DbFSToVolumeInterpolatesCorrectly)99 TEST_F(VolumeCacheTest, DbFSToVolumeInterpolatesCorrectly) {
100   int i_low = 0, i_high = 1;
101   for (; i_high <= kMaxVolumeIndex; ++i_high, ++i_low) {
102     float v_low = static_cast<float>(i_low) / kMaxVolumeIndex;
103     float v_high = static_cast<float>(i_high) / kMaxVolumeIndex;
104     float db_low = kTestVolumeTable[i_low];
105     float db_high = kTestVolumeTable[i_high];
106     float m = (v_high - v_low) / (db_high - db_low);
107     for (float db = db_low; db <= db_high; db += 0.1f) {
108       float expected_v = v_low + m * (db - db_low);
109       EXPECT_FLOAT_EQ(expected_v, volume_cache_.DbFSToVolume(db));
110     }
111   }
112 }
113 
TEST_F(VolumeCacheTest,CacheHonorsAudioContentType)114 TEST_F(VolumeCacheTest, CacheHonorsAudioContentType) {
115   VolumeCache volume_cache(AudioContentType::kAlarm, this);
116   EXPECT_FLOAT_EQ(-1.0f, volume_cache.VolumeToDbFS(0.0f));
117   EXPECT_FLOAT_EQ(-1.0f, volume_cache.VolumeToDbFS(1.0f));
118 }
119 
120 }  // namespace media
121 }  // namespace chromecast
122