CRAS: float_buffer - Fix readable count

Fix a bug in float_buffer when passing non-zero offset. Without
the fix, the result readable frames count could be incorrectly
larger and cause crash.

BUG=chromium:892608
TEST=unittest

Change-Id: I2d5f1724a032bc3264e4c178bf2b4e488686cde4
Reviewed-on: https://chromium-review.googlesource.com/1265215
Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com>
Tested-by: Hsinyu Chao <hychao@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
diff --git a/cras/src/Makefile.am b/cras/src/Makefile.am
index 18e5510..ddb53fa 100644
--- a/cras/src/Makefile.am
+++ b/cras/src/Makefile.am
@@ -354,6 +354,7 @@
 	edid_utils_unittest \
 	expr_unittest \
 	file_wait_unittest \
+	float_buffer_unittest \
 	fmt_conv_unittest \
 	hfp_info_unittest \
 	buffer_share_unittest \
@@ -715,6 +716,12 @@
 	$(CRAS_UT_TMPDIR_CFLAGS)
 file_wait_unittest_LDADD = -lgtest -lpthread
 
+
+float_buffer_unittest_SOURCES = tests/float_buffer_unittest.cc
+float_buffer_unittest_CPPFLAGS = $(COMMON_CPPFLAGS) -I$(top_srcdir)/src/common \
+	-I$(top_srcdir)/src/server
+float_buffer_unittest_LDADD = -lgtest -lpthread
+
 fmt_conv_unittest_SOURCES = tests/fmt_conv_unittest.cc server/cras_fmt_conv.c
 fmt_conv_unittest_CPPFLAGS = $(COMMON_CPPFLAGS) -I$(top_srcdir)/src/common \
 	 -I$(top_srcdir)/src/server
diff --git a/cras/src/server/float_buffer.h b/cras/src/server/float_buffer.h
index 9b82c04..55e176e 100644
--- a/cras/src/server/float_buffer.h
+++ b/cras/src/server/float_buffer.h
@@ -97,8 +97,8 @@
 		offset = offset + b->buf->read_idx - b->buf->max_size;
 		*readable = MIN(*readable, b->buf->write_idx - offset);
 	} else {
+		*readable = MIN(*readable, nread - offset);
 		offset += b->buf->read_idx;
-		*readable = MIN(*readable, nread);
 	}
 
 	for (i = 0; i < b->num_channels; i++, data += b->buf->max_size)
diff --git a/cras/src/tests/float_buffer_unittest.cc b/cras/src/tests/float_buffer_unittest.cc
new file mode 100644
index 0000000..20d392e
--- /dev/null
+++ b/cras/src/tests/float_buffer_unittest.cc
@@ -0,0 +1,53 @@
+// Copyright 2018 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <gtest/gtest.h>
+
+#include "float_buffer.h"
+
+namespace {
+TEST(FloatBuffer, ReadWrite) {
+  unsigned int readable = 10;
+  struct float_buffer *b = float_buffer_create(10, 2);
+  EXPECT_EQ(10, float_buffer_writable(b));
+
+  // (w, r)=(8, 0)
+  float_buffer_written(b, 8);
+  EXPECT_EQ(8, float_buffer_level(b));
+
+  float_buffer_read_pointer(b, 0, &readable);
+  EXPECT_EQ(8, readable);
+  EXPECT_EQ(2, float_buffer_writable(b));
+
+  readable = 10;
+  float_buffer_read_pointer(b, 3, &readable);
+  EXPECT_EQ(5, readable);
+
+  // (w, r)=(8, 6)
+  float_buffer_read(b, 6);
+  EXPECT_EQ(2, float_buffer_writable(b));
+
+  // (w, r)=(0, 6)
+  float_buffer_written(b, 2);
+  EXPECT_EQ(6, float_buffer_writable(b));
+
+  // (w, r)=(3, 6)
+  readable = 10;
+  float_buffer_written(b, 3);
+  float_buffer_read_pointer(b, 0, &readable);
+  EXPECT_EQ(4, readable);
+
+  readable = 10;
+  float_buffer_read_pointer(b, 1, &readable);
+  EXPECT_EQ(3, readable);
+
+  float_buffer_destroy(&b);
+}
+
+} // namespace
+
+int main(int argc, char **argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}