CRAS: client - Don't read repeated data

CRAS client could handles multiple messages from server about
capture data ready. We should check if the read offset of stream
shm reaches write offset, to avoid reading repeated data.

BUG=chromium:662886
TEST=Execute 'cras_test_client --capture_file /tmp/1' and then
hit 'p', 'enter', 'p', 'enter'... repeat 10 times while making
some sound to internal mic.
Inspect the recorded /tmp/1 file using Audacity to verify there
are no repeated samples, but with several short discontinuity
instead.

Change-Id: I40bf34cbae31f76bd013ec855a4d5ef4055399f2
Reviewed-on: https://chromium-review.googlesource.com/411668
Commit-Ready: Nicolas Boichat <drinkcat@chromium.org>
Tested-by: Hsinyu Chao <hychao@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
diff --git a/cras/src/common/cras_shm.h b/cras/src/common/cras_shm.h
index 03a4247..849c368 100644
--- a/cras/src/common/cras_shm.h
+++ b/cras/src/common/cras_shm.h
@@ -108,12 +108,24 @@
 
 /* Get a pointer to the current read buffer */
 static inline
-uint8_t *cras_shm_get_curr_read_buffer(const struct cras_audio_shm *shm)
+uint8_t *cras_shm_get_curr_read_buffer(const struct cras_audio_shm *shm,
+				       unsigned *frames)
 {
 	unsigned i = shm->area->read_buf_idx & CRAS_SHM_BUFFERS_MASK;
+	unsigned read_offset, write_offset;
 
-	return cras_shm_buff_for_idx(shm, i) +
+	read_offset =
 		cras_shm_check_read_offset(shm, shm->area->read_offset[i]);
+	write_offset =
+		cras_shm_check_write_offset(shm, shm->area->write_offset[i]);
+
+	if (read_offset > write_offset)
+		*frames = 0;
+	else
+		*frames = (write_offset - read_offset) /
+				shm->config.frame_bytes;
+
+	return cras_shm_buff_for_idx(shm, i) + read_offset;
 }
 
 /* Get the base of the current write buffer. */
diff --git a/cras/src/libcras/cras_client.c b/cras/src/libcras/cras_client.c
index 795b33e..443490c 100644
--- a/cras/src/libcras/cras_client.c
+++ b/cras/src/libcras/cras_client.c
@@ -1034,7 +1034,11 @@
 				       uint8_t **captured_frames,
 				       unsigned int num_frames)
 {
-	*captured_frames = cras_shm_get_curr_read_buffer(&stream->capture_shm);
+	unsigned int readable;
+
+	*captured_frames = cras_shm_get_curr_read_buffer(&stream->capture_shm,
+						         &readable);
+	num_frames = MIN(num_frames, readable);
 
 	/* Don't ask for more frames than the client desires. */
 	if (stream->flags & BULK_AUDIO_OK)
@@ -1076,6 +1080,9 @@
 	}
 
 	num_frames = config_capture_buf(stream, &captured_frames, num_frames);
+	if (num_frames == 0)
+		return 0;
+
 	cras_timespec_to_timespec(&ts, &stream->capture_shm.area->ts);
 
 	if (config->unified_cb)
diff --git a/cras/src/tests/cras_test_client.c b/cras/src/tests/cras_test_client.c
index 830b02b..983a42f 100644
--- a/cras/src/tests/cras_test_client.c
+++ b/cras/src/tests/cras_test_client.c
@@ -129,6 +129,9 @@
 	int write_size;
 	int frame_bytes;
 
+	while (pause_client)
+		usleep(10000);
+
 	cras_client_calc_capture_latency(captured_time, &last_latency);
 
 	frame_bytes = cras_client_format_bytes_per_frame(aud_format);