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