Audio Processing Module: add play-out audio device runtime information

Add a runtime setting that notifies play-out audio device changes.
The payload is a pair indicating a device id and its maximum play-out
volume.

kPlayoutVolumeChange is now forwarded not only to capture, but also
render (required by render_pre_processor).

Bug: webrtc:10608
Change-Id: I8997c207422c1dcd1d53775397d6290939ef3db8
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/159002
Commit-Queue: Alessio Bazzica <alessiob@webrtc.org>
Reviewed-by: Per Ã…hgren <peah@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#29725}
diff --git a/modules/audio_processing/aec_dump/aec_dump_impl.cc b/modules/audio_processing/aec_dump/aec_dump_impl.cc
index a7ac552..37e9ec2 100644
--- a/modules/audio_processing/aec_dump/aec_dump_impl.cc
+++ b/modules/audio_processing/aec_dump/aec_dump_impl.cc
@@ -204,6 +204,14 @@
       setting->set_playout_volume_change(x);
       break;
     }
+    case AudioProcessing::RuntimeSetting::Type::kPlayoutAudioDeviceChange: {
+      AudioProcessing::RuntimeSetting::PlayoutAudioDeviceInfo src;
+      runtime_setting.GetPlayoutAudioDeviceInfo(&src);
+      auto* dst = setting->mutable_playout_audio_device_change();
+      dst->set_id(src.id);
+      dst->set_max_volume(src.max_volume);
+      break;
+    }
     case AudioProcessing::RuntimeSetting::Type::kNotSpecified:
       RTC_NOTREACHED();
       break;
diff --git a/modules/audio_processing/audio_processing_impl.cc b/modules/audio_processing/audio_processing_impl.cc
index cab7677..c718838 100644
--- a/modules/audio_processing/audio_processing_impl.cc
+++ b/modules/audio_processing/audio_processing_impl.cc
@@ -801,16 +801,20 @@
 void AudioProcessingImpl::SetRuntimeSetting(RuntimeSetting setting) {
   switch (setting.type()) {
     case RuntimeSetting::Type::kCustomRenderProcessingRuntimeSetting:
+    case RuntimeSetting::Type::kPlayoutAudioDeviceChange:
       render_runtime_settings_enqueuer_.Enqueue(setting);
       return;
-    case RuntimeSetting::Type::kNotSpecified:
-      RTC_NOTREACHED();
-      return;
     case RuntimeSetting::Type::kCapturePreGain:
     case RuntimeSetting::Type::kCaptureCompressionGain:
     case RuntimeSetting::Type::kCaptureFixedPostGain:
+      capture_runtime_settings_enqueuer_.Enqueue(setting);
+      return;
     case RuntimeSetting::Type::kPlayoutVolumeChange:
       capture_runtime_settings_enqueuer_.Enqueue(setting);
+      render_runtime_settings_enqueuer_.Enqueue(setting);
+      return;
+    case RuntimeSetting::Type::kNotSpecified:
+      RTC_NOTREACHED();
       return;
   }
   // The language allows the enum to have a non-enumerator
@@ -947,6 +951,9 @@
         capture_.playout_volume = value;
         break;
       }
+      case RuntimeSetting::Type::kPlayoutAudioDeviceChange:
+        RTC_NOTREACHED();
+        break;
       case RuntimeSetting::Type::kCustomRenderProcessingRuntimeSetting:
         RTC_NOTREACHED();
         break;
@@ -964,6 +971,7 @@
       aec_dump_->WriteRuntimeSetting(setting);
     }
     switch (setting.type()) {
+      case RuntimeSetting::Type::kPlayoutAudioDeviceChange:  // fall-through
       case RuntimeSetting::Type::kCustomRenderProcessingRuntimeSetting:
         if (submodules_.render_pre_processor) {
           submodules_.render_pre_processor->SetRuntimeSetting(setting);
diff --git a/modules/audio_processing/debug.proto b/modules/audio_processing/debug.proto
index 0c50a65..af5e22c 100644
--- a/modules/audio_processing/debug.proto
+++ b/modules/audio_processing/debug.proto
@@ -80,11 +80,17 @@
   // Next field number 21.
 }
 
+message PlayoutAudioDeviceInfo {
+  optional int32 id = 1;
+  optional int32 max_volume = 2;
+}
+
 message RuntimeSetting {
   optional float capture_pre_gain = 1;
   optional float custom_render_processing_setting = 2;
   optional float capture_fixed_post_gain = 3;
   optional int32 playout_volume_change = 4;
+  optional PlayoutAudioDeviceInfo playout_audio_device_change = 5;
 }
 
 message Event {
diff --git a/modules/audio_processing/include/audio_processing.h b/modules/audio_processing/include/audio_processing.h
index 8c46155..52fbaba 100644
--- a/modules/audio_processing/include/audio_processing.h
+++ b/modules/audio_processing/include/audio_processing.h
@@ -414,7 +414,14 @@
       kCaptureCompressionGain,
       kCaptureFixedPostGain,
       kPlayoutVolumeChange,
-      kCustomRenderProcessingRuntimeSetting
+      kCustomRenderProcessingRuntimeSetting,
+      kPlayoutAudioDeviceChange
+    };
+
+    // Play-out audio device properties.
+    struct PlayoutAudioDeviceInfo {
+      int id;          // Identifies the audio device.
+      int max_volume;  // Maximum play-out volume.
     };
 
     RuntimeSetting() : type_(Type::kNotSpecified), value_(0.f) {}
@@ -441,6 +448,15 @@
       return {Type::kCaptureFixedPostGain, gain_db};
     }
 
+    // Creates a runtime setting to notify play-out (aka render) audio device
+    // changes.
+    static RuntimeSetting CreatePlayoutAudioDeviceChange(
+        PlayoutAudioDeviceInfo audio_device) {
+      return {Type::kPlayoutAudioDeviceChange, audio_device};
+    }
+
+    // Creates a runtime setting to notify play-out (aka render) volume changes.
+    // |volume| is the unnormalized volume, the maximum of which
     static RuntimeSetting CreatePlayoutVolumeChange(int volume) {
       return {Type::kPlayoutVolumeChange, volume};
     }
@@ -450,6 +466,8 @@
     }
 
     Type type() const { return type_; }
+    // Getters do not return a value but instead modify the argument to protect
+    // from implicit casting.
     void GetFloat(float* value) const {
       RTC_DCHECK(value);
       *value = value_.float_value;
@@ -458,17 +476,25 @@
       RTC_DCHECK(value);
       *value = value_.int_value;
     }
+    void GetPlayoutAudioDeviceInfo(PlayoutAudioDeviceInfo* value) const {
+      RTC_DCHECK(value);
+      *value = value_.playout_audio_device_info;
+    }
 
    private:
     RuntimeSetting(Type id, float value) : type_(id), value_(value) {}
     RuntimeSetting(Type id, int value) : type_(id), value_(value) {}
+    RuntimeSetting(Type id, PlayoutAudioDeviceInfo value)
+        : type_(id), value_(value) {}
     Type type_;
     union U {
       U() {}
       U(int value) : int_value(value) {}
       U(float value) : float_value(value) {}
+      U(PlayoutAudioDeviceInfo value) : playout_audio_device_info(value) {}
       float float_value;
       int int_value;
+      PlayoutAudioDeviceInfo playout_audio_device_info;
     } value_;
   };
 
diff --git a/modules/audio_processing/test/aec_dump_based_simulator.cc b/modules/audio_processing/test/aec_dump_based_simulator.cc
index e56694e..d9bd5bc 100644
--- a/modules/audio_processing/test/aec_dump_based_simulator.cc
+++ b/modules/audio_processing/test/aec_dump_based_simulator.cc
@@ -597,6 +597,11 @@
     ap_->SetRuntimeSetting(
         AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(
             msg.playout_volume_change()));
+  } else if (msg.has_playout_audio_device_change()) {
+    ap_->SetRuntimeSetting(
+        AudioProcessing::RuntimeSetting::CreatePlayoutAudioDeviceChange(
+            {msg.playout_audio_device_change().id(),
+             msg.playout_audio_device_change().max_volume()}));
   }
 }
 
diff --git a/modules/audio_processing/test/runtime_setting_util.cc b/modules/audio_processing/test/runtime_setting_util.cc
index a78ca18..8876187 100644
--- a/modules/audio_processing/test/runtime_setting_util.cc
+++ b/modules/audio_processing/test/runtime_setting_util.cc
@@ -36,6 +36,11 @@
     apm->SetRuntimeSetting(
         AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(
             setting.playout_volume_change()));
+  } else if (setting.has_playout_audio_device_change()) {
+    apm->SetRuntimeSetting(
+        AudioProcessing::RuntimeSetting::CreatePlayoutAudioDeviceChange(
+            {setting.playout_audio_device_change().id(),
+             setting.playout_audio_device_change().max_volume()}));
   }
 }
 }  // namespace webrtc