Improves stereo/mono audio support on Android.

Fixes some issues related to calling WebRtcAudioManager.setStereoOutput(true)
and WebRtcAudioManager.setStereoInput(true) and ensures that the ADM reports
correct values related to stereo support given these settings.

Also makes it more clear that the OpenSLES audio implementation does not support
stereo (we now fail in Init()).

To summarize: this change ensures that the user can ask for stereo input
and/or stereo output audio on Android in combination with the Java based
audio layer. By default (if no WebRtcAudioManager.setStereoXXX() APIs are called), mono will be used.

BUG=webrtc:7962

Review-Url: https://codereview.webrtc.org/3009193002
Cr-Original-Commit-Position: refs/heads/master@{#19763}
Cr-Mirrored-From: https://chromium.googlesource.com/external/webrtc
Cr-Mirrored-Commit: 76535de14fa3d823b30f015d76b535887699dc8f
diff --git a/modules/audio_device/android/audio_device_template.h b/modules/audio_device/android/audio_device_template.h
index dc32fef..0970659 100644
--- a/modules/audio_device/android/audio_device_template.h
+++ b/modules/audio_device/android/audio_device_template.h
@@ -331,41 +331,48 @@
     return -1;
   }
 
+  // Returns true if the audio manager has been configured to support stereo
+  // and false otherwised. Default is mono.
   int32_t StereoPlayoutIsAvailable(bool& available) override {
     LOG(INFO) << __FUNCTION__;
-    available = false;
+    available = audio_manager_->IsStereoPlayoutSupported();
     return 0;
   }
 
-  // TODO(henrika): add support.
   int32_t SetStereoPlayout(bool enable) override {
     LOG(INFO) << __FUNCTION__;
-    // Allow disabling stereo playout, as that matches returning false(0) from
-    // StereoPlayoutIsAvailable and is the default case.
-    return enable ? -1 : 0;
+    bool available = audio_manager_->IsStereoPlayoutSupported();
+    // Android does not support changes between mono and stero on the fly.
+    // Instead, the native audio layer is configured via the audio manager
+    // to either support mono or stereo. It is allowed to call this method
+    // if that same state is not modified.
+    return (enable == available) ? 0 : -1;
   }
 
-  // TODO(henrika): add support.
   int32_t StereoPlayout(bool& enabled) const override {
-    enabled = false;
-    FATAL() << "Should never be called";
-    return -1;
+    enabled = audio_manager_->IsStereoPlayoutSupported();
+    return 0;
   }
 
   int32_t StereoRecordingIsAvailable(bool& available) override {
     LOG(INFO) << __FUNCTION__;
-    available = false;
+    available = audio_manager_->IsStereoRecordSupported();
     return 0;
   }
 
   int32_t SetStereoRecording(bool enable) override {
     LOG(INFO) << __FUNCTION__;
-    return -1;
+    bool available = audio_manager_->IsStereoRecordSupported();
+    // Android does not support changes between mono and stero on the fly.
+    // Instead, the native audio layer is configured via the audio manager
+    // to either support mono or stereo. It is allowed to call this method
+    // if that same state is not modified.
+    return (enable == available) ? 0 : -1;
   }
 
   int32_t StereoRecording(bool& enabled) const override {
     LOG(INFO) << __FUNCTION__;
-    enabled = false;
+    enabled = audio_manager_->IsStereoRecordSupported();
     return 0;
   }
 
diff --git a/modules/audio_device/android/audio_manager.cc b/modules/audio_device/android/audio_manager.cc
index da348d2..60a1d9a 100644
--- a/modules/audio_device/android/audio_manager.cc
+++ b/modules/audio_device/android/audio_manager.cc
@@ -220,6 +220,18 @@
   return pro_audio_;
 }
 
+bool AudioManager::IsStereoPlayoutSupported() const {
+  RTC_DCHECK(thread_checker_.CalledOnValidThread());
+  ALOGD("IsStereoPlayoutSupported()");
+  return (playout_parameters_.channels() == 2);
+}
+
+bool AudioManager::IsStereoRecordSupported() const {
+  RTC_DCHECK(thread_checker_.CalledOnValidThread());
+  ALOGD("IsStereoRecordSupported()");
+  return (record_parameters_.channels() == 2);
+}
+
 int AudioManager::GetDelayEstimateInMilliseconds() const {
   return delay_estimate_in_milliseconds_;
 }
diff --git a/modules/audio_device/android/audio_manager.h b/modules/audio_device/android/audio_manager.h
index e15e4aa..638b085 100644
--- a/modules/audio_device/android/audio_manager.h
+++ b/modules/audio_device/android/audio_manager.h
@@ -103,6 +103,14 @@
   bool IsLowLatencyPlayoutSupported() const;
   bool IsLowLatencyRecordSupported() const;
 
+  // Returns true if the device supports (and has been configured for) stereo.
+  // Call the Java API WebRtcAudioManager.setStereoOutput/Input() with true as
+  // paramter to enable stereo. Default is mono in both directions and the
+  // setting is set once and for all when the audio manager object is created.
+  // TODO(henrika): stereo is not supported in combination with OpenSL ES.
+  bool IsStereoPlayoutSupported() const;
+  bool IsStereoRecordSupported() const;
+
   // Returns true if the device supports pro-audio features in combination with
   // OpenSL ES.
   bool IsProAudioSupported() const;
diff --git a/modules/audio_device/android/audio_manager_unittest.cc b/modules/audio_device/android/audio_manager_unittest.cc
index 0ebc662..e82376d 100644
--- a/modules/audio_device/android/audio_manager_unittest.cc
+++ b/modules/audio_device/android/audio_manager_unittest.cc
@@ -136,6 +136,16 @@
         audio_manager()->IsProAudioSupported() ? "Yes" : "No");
 }
 
+// Verify that playout side is configured for mono by default.
+TEST_F(AudioManagerTest, IsStereoPlayoutSupported) {
+  EXPECT_FALSE(audio_manager()->IsStereoPlayoutSupported());
+}
+
+// Verify that recording side is configured for mono by default.
+TEST_F(AudioManagerTest, IsStereoRecordSupported) {
+  EXPECT_FALSE(audio_manager()->IsStereoRecordSupported());
+}
+
 TEST_F(AudioManagerTest, ShowAudioParameterInfo) {
   const bool low_latency_out = audio_manager()->IsLowLatencyPlayoutSupported();
   const bool low_latency_in = audio_manager()->IsLowLatencyRecordSupported();
diff --git a/modules/audio_device/android/opensles_player.cc b/modules/audio_device/android/opensles_player.cc
index 513f823..3a40bf4 100644
--- a/modules/audio_device/android/opensles_player.cc
+++ b/modules/audio_device/android/opensles_player.cc
@@ -79,6 +79,11 @@
 int OpenSLESPlayer::Init() {
   ALOGD("Init%s", GetThreadInfo().c_str());
   RTC_DCHECK(thread_checker_.CalledOnValidThread());
+  if (audio_parameters_.channels() == 2) {
+    // TODO(henrika): FineAudioBuffer needs more work to support stereo.
+    ALOGE("OpenSLESPlayer does not support stereo");
+    return -1;
+  }
   return 0;
 }
 
diff --git a/modules/audio_device/android/opensles_recorder.cc b/modules/audio_device/android/opensles_recorder.cc
index e3a6e61..df94ba8 100644
--- a/modules/audio_device/android/opensles_recorder.cc
+++ b/modules/audio_device/android/opensles_recorder.cc
@@ -76,6 +76,11 @@
 int OpenSLESRecorder::Init() {
   ALOGD("Init%s", GetThreadInfo().c_str());
   RTC_DCHECK(thread_checker_.CalledOnValidThread());
+  if (audio_parameters_.channels() == 2) {
+    // TODO(henrika): FineAudioBuffer needs more work to support stereo.
+    ALOGE("OpenSLESRecorder does not support stereo");
+    return -1;
+  }
   return 0;
 }
 
diff --git a/modules/audio_device/audio_device_buffer.cc b/modules/audio_device/audio_device_buffer.cc
index 79a0ebc..063c65f 100644
--- a/modules/audio_device/audio_device_buffer.cc
+++ b/modules/audio_device/audio_device_buffer.cc
@@ -376,8 +376,8 @@
   }
   // Update playout stats which is used as base for periodic logging of the
   // audio output state.
-  UpdatePlayStats(max_abs, num_samples_out);
-  return static_cast<int32_t>(num_samples_out);
+  UpdatePlayStats(max_abs, num_samples_out / play_channels_);
+  return static_cast<int32_t>(num_samples_out / play_channels_);
 }
 
 int32_t AudioDeviceBuffer::GetPlayoutData(void* audio_buffer) {