• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium OS 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 <stdio.h>
6 #include <gtest/gtest.h>
7 
8 extern "C" {
9 #include "cras_shm.h"
10 #include "cras_types.h"
11 }
12 
13 namespace {
14 
15 class ShmTestSuite : public testing::Test{
16   protected:
SetUp()17     virtual void SetUp() {
18       memset(&shm_, 0, sizeof(shm_));
19       shm_.area =
20           static_cast<cras_audio_shm_area *>(
21               calloc(1, sizeof(*shm_.area) + 2048));
22       cras_shm_set_frame_bytes(&shm_, 4);
23       cras_shm_set_used_size(&shm_, 1024);
24       memcpy(&shm_.area->config, &shm_.config, sizeof(shm_.config));
25 
26       frames_ = 0;
27     }
28 
TearDown()29     virtual void TearDown() {
30       free(shm_.area);
31     }
32 
33     struct cras_audio_shm shm_;
34     uint8_t *buf_;
35     size_t frames_;
36 };
37 
38 // Test that and empty buffer returns 0 readable bytes.
TEST_F(ShmTestSuite,NoneReadableWhenEmpty)39 TEST_F(ShmTestSuite, NoneReadableWhenEmpty) {
40   buf_ = cras_shm_get_readable_frames(&shm_, 0, &frames_);
41   EXPECT_EQ(0, frames_);
42   cras_shm_buffer_read(&shm_, frames_);
43   EXPECT_EQ(0, shm_.area->read_offset[0]);
44 }
45 
46 // Buffer with 100 frames filled.
TEST_F(ShmTestSuite,OneHundredFilled)47 TEST_F(ShmTestSuite, OneHundredFilled) {
48   shm_.area->write_offset[0] = 100 * shm_.area->config.frame_bytes;
49   buf_ = cras_shm_get_readable_frames(&shm_, 0, &frames_);
50   EXPECT_EQ(100, frames_);
51   EXPECT_EQ(shm_.area->samples, buf_);
52   cras_shm_buffer_read(&shm_, frames_ - 9);
53   EXPECT_EQ((frames_ - 9) * shm_.config.frame_bytes, shm_.area->read_offset[0]);
54   cras_shm_buffer_read(&shm_, 9);
55   EXPECT_EQ(0, shm_.area->read_offset[0]);
56   EXPECT_EQ(1, shm_.area->read_buf_idx);
57 }
58 
59 // Buffer with 100 frames filled, 50 read.
TEST_F(ShmTestSuite,OneHundredFilled50Read)60 TEST_F(ShmTestSuite, OneHundredFilled50Read) {
61   shm_.area->write_offset[0] = 100 * shm_.config.frame_bytes;
62   shm_.area->read_offset[0] = 50 * shm_.config.frame_bytes;
63   buf_ = cras_shm_get_readable_frames(&shm_, 0, &frames_);
64   EXPECT_EQ(50, frames_);
65   EXPECT_EQ((shm_.area->samples + shm_.area->read_offset[0]), buf_);
66   cras_shm_buffer_read(&shm_, frames_ - 10);
67   EXPECT_EQ(shm_.area->write_offset[0] - 10 * shm_.config.frame_bytes,
68             shm_.area->read_offset[0]);
69   cras_shm_buffer_read(&shm_, 10);
70   EXPECT_EQ(0, shm_.area->read_offset[0]);
71 }
72 
73 // Buffer with 100 frames filled, 50 read, offset by 25.
TEST_F(ShmTestSuite,OneHundredFilled50Read25offset)74 TEST_F(ShmTestSuite, OneHundredFilled50Read25offset) {
75   shm_.area->write_offset[0] = 100 * shm_.config.frame_bytes;
76   shm_.area->read_offset[0] = 50 * shm_.config.frame_bytes;
77   buf_ = cras_shm_get_readable_frames(&shm_, 25, &frames_);
78   EXPECT_EQ(25, frames_);
79   EXPECT_EQ(shm_.area->samples + shm_.area->read_offset[0] +
80                 25 * shm_.area->config.frame_bytes,
81             (uint8_t *)buf_);
82 }
83 
84 // Test wrapping across buffers.
TEST_F(ShmTestSuite,WrapToNextBuffer)85 TEST_F(ShmTestSuite, WrapToNextBuffer) {
86   shm_.config.used_size = 480 * shm_.config.frame_bytes;
87   shm_.area->write_offset[0] = 240 * shm_.config.frame_bytes;
88   shm_.area->read_offset[0] = 120 * shm_.config.frame_bytes;
89   shm_.area->write_offset[1] = 240 * shm_.config.frame_bytes;
90   buf_ = cras_shm_get_readable_frames(&shm_, 0, &frames_);
91   EXPECT_EQ(120, frames_);
92   EXPECT_EQ(shm_.area->samples + shm_.area->read_offset[0], (uint8_t *)buf_);
93   buf_ = cras_shm_get_readable_frames(&shm_, frames_, &frames_);
94   EXPECT_EQ(240, frames_);
95   EXPECT_EQ(shm_.area->samples + shm_.config.used_size, (uint8_t *)buf_);
96   cras_shm_buffer_read(&shm_, 350); /* Mark all-10 as read */
97   EXPECT_EQ(0, shm_.area->read_offset[0]);
98   EXPECT_EQ(230 * shm_.config.frame_bytes, shm_.area->read_offset[1]);
99 }
100 
101 // Test wrapping across buffers reading all samples.
TEST_F(ShmTestSuite,WrapToNextBufferReadAll)102 TEST_F(ShmTestSuite, WrapToNextBufferReadAll) {
103   shm_.config.used_size = 480 * shm_.config.frame_bytes;
104   shm_.area->write_offset[0] = 240 * shm_.config.frame_bytes;
105   shm_.area->read_offset[0] = 120 * shm_.config.frame_bytes;
106   shm_.area->write_offset[1] = 240 * shm_.config.frame_bytes;
107   buf_ = cras_shm_get_readable_frames(&shm_, 0, &frames_);
108   EXPECT_EQ(120, frames_);
109   EXPECT_EQ(shm_.area->samples + shm_.area->read_offset[0], (uint8_t *)buf_);
110   buf_ = cras_shm_get_readable_frames(&shm_, frames_, &frames_);
111   EXPECT_EQ(240, frames_);
112   EXPECT_EQ(shm_.area->samples + shm_.config.used_size, (uint8_t *)buf_);
113   cras_shm_buffer_read(&shm_, 360); /* Mark all as read */
114   EXPECT_EQ(0, shm_.area->read_offset[0]);
115   EXPECT_EQ(0, shm_.area->read_offset[1]);
116   EXPECT_EQ(0, shm_.area->read_buf_idx);
117 }
118 
119 // Test wrapping last buffer.
TEST_F(ShmTestSuite,WrapFromFinalBuffer)120 TEST_F(ShmTestSuite, WrapFromFinalBuffer) {
121   shm_.area->read_buf_idx = CRAS_NUM_SHM_BUFFERS - 1;
122   shm_.config.used_size = 480 * shm_.config.frame_bytes;
123   shm_.area->write_offset[shm_.area->read_buf_idx] =
124       240 * shm_.config.frame_bytes;
125   shm_.area->read_offset[shm_.area->read_buf_idx] =
126       120 * shm_.config.frame_bytes;
127   shm_.area->write_offset[0] = 240 * shm_.config.frame_bytes;
128   buf_ = cras_shm_get_readable_frames(&shm_, 0, &frames_);
129   EXPECT_EQ(120, frames_);
130   EXPECT_EQ((uint8_t *)buf_, shm_.area->samples +
131       shm_.config.used_size * shm_.area->read_buf_idx +
132       shm_.area->read_offset[shm_.area->read_buf_idx]);
133   buf_ = cras_shm_get_readable_frames(&shm_, frames_, &frames_);
134   EXPECT_EQ(240, frames_);
135   EXPECT_EQ(shm_.area->samples, (uint8_t *)buf_);
136   cras_shm_buffer_read(&shm_, 350); /* Mark all-10 as read */
137   EXPECT_EQ(0, shm_.area->read_offset[1]);
138   EXPECT_EQ(230 * shm_.config.frame_bytes, shm_.area->read_offset[0]);
139 }
140 
141 // Test Check available to write returns 0 if not free buffer.
TEST_F(ShmTestSuite,WriteAvailNotFree)142 TEST_F(ShmTestSuite, WriteAvailNotFree) {
143   size_t ret;
144   shm_.area->write_buf_idx = 0;
145   shm_.area->write_offset[0] = 100 * shm_.config.frame_bytes;
146   shm_.area->read_offset[0] = 50 * shm_.config.frame_bytes;
147   ret = cras_shm_get_num_writeable(&shm_);
148   EXPECT_EQ(0, ret);
149 }
150 
151 // Test Check available to write returns num_frames if free buffer.
TEST_F(ShmTestSuite,WriteAvailValid)152 TEST_F(ShmTestSuite, WriteAvailValid) {
153   size_t ret;
154   shm_.area->write_buf_idx = 0;
155   shm_.config.used_size = 480 * shm_.config.frame_bytes;
156   shm_.area->write_offset[0] = 0;
157   shm_.area->read_offset[0] = 0;
158   ret = cras_shm_get_num_writeable(&shm_);
159   EXPECT_EQ(480, ret);
160 }
161 
162 // Test get frames_written returns the number of frames written.
TEST_F(ShmTestSuite,GetNumWritten)163 TEST_F(ShmTestSuite, GetNumWritten) {
164   size_t ret;
165   shm_.area->write_buf_idx = 0;
166   shm_.config.used_size = 480 * shm_.config.frame_bytes;
167   shm_.area->write_offset[0] = 200 * shm_.config.frame_bytes;
168   shm_.area->read_offset[0] = 0;
169   ret = cras_shm_frames_written(&shm_);
170   EXPECT_EQ(200, ret);
171 }
172 
173 // Test that getting the base of the write buffer returns the correct pointer.
TEST_F(ShmTestSuite,GetWriteBufferBase)174 TEST_F(ShmTestSuite, GetWriteBufferBase) {
175   uint8_t* ret;
176 
177   shm_.area->write_buf_idx = 0;
178   shm_.config.used_size = 480 * shm_.config.frame_bytes;
179   shm_.area->write_offset[0] = 200 * shm_.config.frame_bytes;
180   shm_.area->write_offset[1] = 200 * shm_.config.frame_bytes;
181   shm_.area->read_offset[0] = 0;
182   shm_.area->read_offset[1] = 0;
183   ret = cras_shm_get_write_buffer_base(&shm_);
184   EXPECT_EQ(shm_.area->samples, ret);
185 
186   shm_.area->write_buf_idx = 1;
187   ret = cras_shm_get_write_buffer_base(&shm_);
188   EXPECT_EQ(shm_.area->samples + shm_.config.used_size, ret);
189 }
190 
TEST_F(ShmTestSuite,SetVolume)191 TEST_F(ShmTestSuite, SetVolume) {
192   cras_shm_set_volume_scaler(&shm_, 1.0);
193   EXPECT_EQ(shm_.area->volume_scaler, 1.0);
194   cras_shm_set_volume_scaler(&shm_, 1.4);
195   EXPECT_EQ(shm_.area->volume_scaler, 1.0);
196   cras_shm_set_volume_scaler(&shm_, -0.5);
197   EXPECT_EQ(shm_.area->volume_scaler, 0.0);
198   cras_shm_set_volume_scaler(&shm_, 0.5);
199   EXPECT_EQ(shm_.area->volume_scaler, 0.5);
200 }
201 
202 // Test that invalid read/write offsets are detected.
203 
TEST_F(ShmTestSuite,InvalidWriteOffset)204 TEST_F(ShmTestSuite, InvalidWriteOffset) {
205   shm_.area->write_offset[0] = shm_.config.used_size + 50;
206   shm_.area->read_offset[0] = 0;
207   buf_ = cras_shm_get_readable_frames(&shm_, 0, &frames_);
208   EXPECT_EQ(shm_.config.used_size / 4, frames_);
209 }
210 
TEST_F(ShmTestSuite,InvalidReadOffset)211 TEST_F(ShmTestSuite, InvalidReadOffset) {
212   // Should ignore read+_offset and assume 0.
213   shm_.area->write_offset[0] = 44;
214   shm_.area->read_offset[0] = shm_.config.used_size + 25;
215   buf_ = cras_shm_get_readable_frames(&shm_, 0, &frames_);
216   EXPECT_EQ(shm_.area->write_offset[0] / shm_.config.frame_bytes, frames_);
217   EXPECT_EQ(shm_.area->samples, (uint8_t *)buf_);
218 }
219 
TEST_F(ShmTestSuite,InvalidReadAndWriteOffset)220 TEST_F(ShmTestSuite, InvalidReadAndWriteOffset) {
221   shm_.area->write_offset[0] = shm_.config.used_size + 50;
222   shm_.area->read_offset[0] = shm_.config.used_size + 25;
223   buf_ = cras_shm_get_readable_frames(&shm_, 0, &frames_);
224   EXPECT_EQ(shm_.config.used_size / 4, frames_);
225 }
226 
TEST_F(ShmTestSuite,InputBufferOverrun)227 TEST_F(ShmTestSuite, InputBufferOverrun) {
228   int rc;
229   shm_.area->write_offset[0] = 0;
230   shm_.area->read_offset[0] = 0;
231   shm_.area->write_offset[1] = 0;
232   shm_.area->read_offset[1] = 0;
233 
234   shm_.area->write_buf_idx = 0;
235   shm_.area->read_buf_idx = 0;
236 
237   EXPECT_EQ(0, cras_shm_num_overruns(&shm_));
238   rc = cras_shm_check_write_overrun(&shm_);
239   EXPECT_EQ(0, rc);
240   cras_shm_buffer_written(&shm_, 100);
241   cras_shm_buffer_write_complete(&shm_);
242 
243   rc = cras_shm_check_write_overrun(&shm_);
244   EXPECT_EQ(0, rc);
245   cras_shm_buffer_written(&shm_, 100);
246   cras_shm_buffer_write_complete(&shm_);
247 
248   // Assert two consecutive writes causes overrun.
249   rc = cras_shm_check_write_overrun(&shm_);
250   EXPECT_EQ(1, rc);
251   EXPECT_EQ(1, cras_shm_num_overruns(&shm_));
252 }
253 
TEST_F(ShmTestSuite,GetWritableFramesNeedToWrite)254 TEST_F(ShmTestSuite, GetWritableFramesNeedToWrite) {
255   unsigned buffer_size = 480;
256   unsigned limit = 480;
257   unsigned written = 200;
258   unsigned frames;
259   shm_.area->write_buf_idx = 0;
260   shm_.config.used_size = buffer_size * shm_.config.frame_bytes;
261   shm_.area->write_offset[0] = written * shm_.config.frame_bytes;
262   buf_ = cras_shm_get_writeable_frames(&shm_, limit, &frames);
263   EXPECT_EQ(limit - written, frames);
264   EXPECT_EQ(shm_.area->samples + shm_.area->write_offset[0], buf_);
265 }
266 
TEST_F(ShmTestSuite,GetWritableFramesNoNeedToWrite)267 TEST_F(ShmTestSuite, GetWritableFramesNoNeedToWrite) {
268   unsigned buffer_size = 480;
269   unsigned limit = 240;
270   unsigned written = 300;
271   unsigned frames;
272   shm_.area->write_buf_idx = 0;
273   shm_.config.used_size = buffer_size * shm_.config.frame_bytes;
274   shm_.area->write_offset[0] = written * shm_.config.frame_bytes;
275   buf_ = cras_shm_get_writeable_frames(&shm_, limit, &frames);
276   EXPECT_EQ(0, frames);
277   EXPECT_EQ(shm_.area->samples + shm_.area->write_offset[0], buf_);
278 }
279 
280 }  //  namespace
281 
main(int argc,char ** argv)282 int main(int argc, char **argv) {
283   ::testing::InitGoogleTest(&argc, argv);
284   return RUN_ALL_TESTS();
285 }
286