CRAS: iodev - Add method to query if a device should mute for volume

Add a method to query if a device should mute its samples because
adjusted node volume is zero.
This will be used when cras_iodev_list decides whether it should start
ramping down a device's samples.

BUG=chromium:697511
TEST=make check

Change-Id: I18b09cba5dc34c8419e0ee17ec7dae9128759731
Reviewed-on: https://chromium-review.googlesource.com/447851
Commit-Ready: Cheng-Yi Chiang <cychiang@chromium.org>
Tested-by: Cheng-Yi Chiang <cychiang@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
diff --git a/cras/src/server/cras_iodev.c b/cras/src/server/cras_iodev.c
index 54676e7..3eeeb74 100644
--- a/cras/src/server/cras_iodev.c
+++ b/cras/src/server/cras_iodev.c
@@ -160,14 +160,19 @@
  * system volume, and active node volume on the device. */
 static int output_should_mute(struct cras_iodev *odev)
 {
-	size_t system_volume;
-	unsigned int adjusted_node_volume;
-
 	/* System mute has highest priority. */
 	if (cras_system_get_mute())
 		return 1;
 
-	/* Then, consider system volume and active node volume. */
+	/* consider system volume and active node volume. */
+	return cras_iodev_is_zero_volume(odev);
+}
+
+int cras_iodev_is_zero_volume(const struct cras_iodev *odev)
+{
+	size_t system_volume;
+	unsigned int adjusted_node_volume;
+
 	system_volume = cras_system_get_volume();
 	if (odev->active_node) {
 		adjusted_node_volume = cras_iodev_adjust_node_volume(
diff --git a/cras/src/server/cras_iodev.h b/cras/src/server/cras_iodev.h
index 857038d..51a0003 100644
--- a/cras/src/server/cras_iodev.h
+++ b/cras/src/server/cras_iodev.h
@@ -690,4 +690,15 @@
  */
 int cras_iodev_set_mute(struct cras_iodev* iodev);
 
+/*
+ * Checks if an output iodev's volume is zero.
+ * If there is an active node, check the adjusted node volume.
+ * If there is no active node, check system volume.
+ * Args:
+ *    odev[in] - The device.
+ * Returns:
+ *    1 if device's volume is 0. 0 otherwise.
+ */
+int cras_iodev_is_zero_volume(const struct cras_iodev *odev);
+
 #endif /* CRAS_IODEV_H_ */
diff --git a/cras/src/tests/iodev_unittest.cc b/cras/src/tests/iodev_unittest.cc
index a1aa243..4c4358d 100644
--- a/cras/src/tests/iodev_unittest.cc
+++ b/cras/src/tests/iodev_unittest.cc
@@ -594,6 +594,39 @@
   EXPECT_EQ(20, rate_estimator_add_frames_num_frames);
 }
 
+TEST(IoDevPutOutputBuffer, MuteForVolume) {
+  struct cras_iodev iodev;
+  struct cras_ionode ionode;
+
+  ResetStubData();
+  memset(&iodev, 0, sizeof(iodev));
+  memset(&ionode, 0, sizeof(ionode));
+
+  iodev.nodes = &ionode;
+  iodev.active_node = &ionode;
+  iodev.active_node->dev = &iodev;
+
+  // Case: System volume 100; Node volume 0. => Mute
+  cras_system_get_volume_return = 100;
+  iodev.active_node->volume = 0;
+  EXPECT_EQ(1, cras_iodev_is_zero_volume(&iodev));
+
+  // Case: System volume 100; Node volume 50. => Not mute
+  cras_system_get_volume_return = 100;
+  iodev.active_node->volume = 50;
+  EXPECT_EQ(0, cras_iodev_is_zero_volume(&iodev));
+
+  // Case: System volume 0; Node volume 50. => Mute
+  cras_system_get_volume_return = 0;
+  iodev.active_node->volume = 50;
+  EXPECT_EQ(1, cras_iodev_is_zero_volume(&iodev));
+
+  // Case: System volume 50; Node volume 50. => Mute
+  cras_system_get_volume_return = 50;
+  iodev.active_node->volume = 50;
+  EXPECT_EQ(1, cras_iodev_is_zero_volume(&iodev));
+}
+
 TEST(IoDevPutOutputBuffer, NodeVolumeZeroShouldMute) {
   struct cras_audio_format fmt;
   struct cras_iodev iodev;