Reland "Add an optional override for AudioRecord device"

This is a reland of 1b8ef63876ebfa55a51c8ca9b1d8206bf8233e01. It was
previously reverted (https://webrtc-review.googlesource.com/c/src/+/175008)
but the revert was found to be unnecessary.

Original change's description:
> Add an optional override for AudioRecord device
>
> This is important when we have multiple named devices connected over
> USB (eg. "Webcam", "Microphone", "Headset") and there is some way to
> choose a specific input device to route from.
>
> Bug: b/154440591
> Change-Id: I8dc1801a5e4db7f7bb439e855d43897c1f7d8bc4
> Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/173748
> Commit-Queue: Robin Lee <rgl@google.com>
> Reviewed-by: Sami Kalliomäki <sakal@webrtc.org>
> Reviewed-by: Henrik Andreassson <henrika@webrtc.org>
> Cr-Commit-Position: refs/heads/master@{#31130}

TBR=henrika@webrtc.org,sakal@webrtc.org,rgl@google.com

Bug: b/154440591, b/155256727
Change-Id: Ic9bf8305c85552a0dc0d2cde6190988423e7fc70
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/175084
Reviewed-by: Henrik Lundin <henrik.lundin@webrtc.org>
Commit-Queue: Henrik Lundin <henrik.lundin@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#31255}
diff --git a/sdk/android/api/org/webrtc/audio/JavaAudioDeviceModule.java b/sdk/android/api/org/webrtc/audio/JavaAudioDeviceModule.java
index ece6f35..9ae00c5 100644
--- a/sdk/android/api/org/webrtc/audio/JavaAudioDeviceModule.java
+++ b/sdk/android/api/org/webrtc/audio/JavaAudioDeviceModule.java
@@ -10,8 +10,11 @@
 
 package org.webrtc.audio;
 
-import android.media.AudioManager;
 import android.content.Context;
+import android.media.AudioDeviceInfo;
+import android.media.AudioManager;
+import android.os.Build;
+import android.support.annotation.RequiresApi;
 import org.webrtc.JniCommon;
 import org.webrtc.Logging;
 
@@ -369,6 +372,18 @@
     audioInput.setMicrophoneMute(mute);
   }
 
+  /**
+   * Start to prefer a specific {@link AudioDeviceInfo} device for recording. Typically this should
+   * only be used if a client gives an explicit option for choosing a physical device to record
+   * from. Otherwise the best-matching device for other parameters will be used. Calling after
+   * recording is started may cause a temporary interruption if the audio routing changes.
+   */
+  @RequiresApi(Build.VERSION_CODES.M)
+  public void setPreferredInputDevice(AudioDeviceInfo preferredInputDevice) {
+    Logging.d(TAG, "setPreferredInputDevice: " + preferredInputDevice);
+    audioInput.setPreferredDevice(preferredInputDevice);
+  }
+
   private static native long nativeCreateAudioDeviceModule(Context context,
       AudioManager audioManager, WebRtcAudioRecord audioInput, WebRtcAudioTrack audioOutput,
       int inputSampleRate, int outputSampleRate, boolean useStereoInput, boolean useStereoOutput);
diff --git a/sdk/android/src/java/org/webrtc/audio/WebRtcAudioRecord.java b/sdk/android/src/java/org/webrtc/audio/WebRtcAudioRecord.java
index b7b78f7..018196b 100644
--- a/sdk/android/src/java/org/webrtc/audio/WebRtcAudioRecord.java
+++ b/sdk/android/src/java/org/webrtc/audio/WebRtcAudioRecord.java
@@ -21,6 +21,7 @@
 import android.os.Build;
 import android.os.Process;
 import android.support.annotation.Nullable;
+import android.support.annotation.RequiresApi;
 import java.lang.System;
 import java.nio.ByteBuffer;
 import java.util.Arrays;
@@ -87,6 +88,7 @@
 
   private @Nullable AudioRecord audioRecord;
   private @Nullable AudioRecordThread audioThread;
+  private @Nullable AudioDeviceInfo preferredDevice;
 
   private @Nullable ScheduledExecutorService executor;
   private @Nullable ScheduledFuture<String> future;
@@ -296,6 +298,9 @@
         // Throws IllegalArgumentException.
         audioRecord = createAudioRecordOnMOrHigher(
             audioSource, sampleRate, channelConfig, audioFormat, bufferSizeInBytes);
+        if (preferredDevice != null) {
+          setPreferredDevice(preferredDevice);
+        }
       } else {
         // Use the old AudioRecord constructor for API levels below 23.
         // Throws UnsupportedOperationException.
@@ -329,6 +334,23 @@
     return framesPerBuffer;
   }
 
+  /**
+   * Prefer a specific {@link AudioDeviceInfo} device for recording. Calling after recording starts
+   * is valid but may cause a temporary interruption if the audio routing changes.
+   */
+  @RequiresApi(Build.VERSION_CODES.M)
+  @TargetApi(Build.VERSION_CODES.M)
+  void setPreferredDevice(@Nullable AudioDeviceInfo preferredDevice) {
+    Logging.d(
+        TAG, "setPreferredDevice " + (preferredDevice != null ? preferredDevice.getId() : null));
+    this.preferredDevice = preferredDevice;
+    if (audioRecord != null) {
+      if (!audioRecord.setPreferredDevice(preferredDevice)) {
+        Logging.e(TAG, "setPreferredDevice failed");
+      }
+    }
+  }
+
   @CalledByNative
   private boolean startRecording() {
     Logging.d(TAG, "startRecording");