Handle iOS devices with no rear-facing camera

Devices exist (specifically the 16GB 5th generation iPod Touch) that do not have
a rear-facing camera.

This CL:
- Adjusts RTCAVFoundationVideoCapturerInternal so initialization doesn't fail
because a rear-facing camera doesn't exist, but still logs a warning
- Provides a check for whether or not a rear-facing camera can be used (useful
for toggling UI elements)
- Turns an attempt to switch to the rear-facing camera into a no-op with a
warning.

BUG=

Review URL: https://codereview.webrtc.org/1416303003

Cr-Commit-Position: refs/heads/master@{#11992}
diff --git a/webrtc/api/objc/RTCAVFoundationVideoSource.h b/webrtc/api/objc/RTCAVFoundationVideoSource.h
index e340444..1d1eac0 100644
--- a/webrtc/api/objc/RTCAVFoundationVideoSource.h
+++ b/webrtc/api/objc/RTCAVFoundationVideoSource.h
@@ -28,6 +28,9 @@
 - (instancetype)initWithFactory:(RTCPeerConnectionFactory *)factory
                     constraints:(nullable RTCMediaConstraints *)constraints;
 
+/** Returns whether rear-facing camera is available for use. */
+@property(nonatomic, readonly) BOOL canUseBackCamera;
+
 /** Switches the camera being used (either front or back). */
 @property(nonatomic, assign) BOOL useBackCamera;
 
diff --git a/webrtc/api/objc/RTCAVFoundationVideoSource.mm b/webrtc/api/objc/RTCAVFoundationVideoSource.mm
index 0cd0155..1005c7d 100644
--- a/webrtc/api/objc/RTCAVFoundationVideoSource.mm
+++ b/webrtc/api/objc/RTCAVFoundationVideoSource.mm
@@ -27,6 +27,10 @@
   return [super initWithNativeVideoSource:source];
 }
 
+- (BOOL)canUseBackCamera {
+  return self.capturer->CanUseBackCamera();
+}
+
 - (BOOL)useBackCamera {
   return self.capturer->GetUseBackCamera();
 }
diff --git a/webrtc/api/objc/avfoundationvideocapturer.h b/webrtc/api/objc/avfoundationvideocapturer.h
index 2ee456d..83ee703 100644
--- a/webrtc/api/objc/avfoundationvideocapturer.h
+++ b/webrtc/api/objc/avfoundationvideocapturer.h
@@ -40,6 +40,12 @@
   /** Returns the active capture session. */
   AVCaptureSession* GetCaptureSession();
 
+  /**
+   * Returns whether the rear-facing camera can be used.
+   * e.g. It can't be used because it doesn't exist.
+   */
+  bool CanUseBackCamera() const;
+
   /** Switches the camera being used (either front or back). */
   void SetUseBackCamera(bool useBackCamera);
   bool GetUseBackCamera() const;
diff --git a/webrtc/api/objc/avfoundationvideocapturer.mm b/webrtc/api/objc/avfoundationvideocapturer.mm
index a3f0f44..c466512 100644
--- a/webrtc/api/objc/avfoundationvideocapturer.mm
+++ b/webrtc/api/objc/avfoundationvideocapturer.mm
@@ -17,6 +17,7 @@
 #import <UIKit/UIKit.h>
 
 #import "webrtc/base/objc/RTCDispatcher.h"
+#import "webrtc/base/objc/RTCLogging.h"
 
 // TODO(tkchin): support other formats.
 static NSString* const kDefaultPreset = AVCaptureSessionPreset640x480;
@@ -35,6 +36,7 @@
 
 @property(nonatomic, readonly) AVCaptureSession *captureSession;
 @property(nonatomic, readonly) BOOL isRunning;
+@property(nonatomic, readonly) BOOL canUseBackCamera;
 @property(nonatomic, assign) BOOL useBackCamera;  // Defaults to NO.
 
 // We keep a pointer back to AVFoundationVideoCapturer to make callbacks on it
@@ -88,10 +90,19 @@
   _capturer = nullptr;
 }
 
+- (BOOL)canUseBackCamera {
+  return _backDeviceInput != nil;
+}
+
 - (void)setUseBackCamera:(BOOL)useBackCamera {
   if (_useBackCamera == useBackCamera) {
     return;
   }
+  if (!self.canUseBackCamera) {
+    RTCLog(@"No rear-facing camera exists or it cannot be used;"
+           "not switching.");
+    return;
+  }
   _useBackCamera = useBackCamera;
   [self updateSessionInput];
 }
@@ -186,10 +197,15 @@
       frontCaptureDevice = captureDevice;
     }
   }
-  if (!frontCaptureDevice || !backCaptureDevice) {
-    NSLog(@"Failed to get capture devices.");
+  if (!frontCaptureDevice) {
+    RTCLog(@"Failed to get front capture device.");
     return NO;
   }
+  if (!backCaptureDevice) {
+    RTCLog(@"Failed to get back capture device");
+    // Don't return NO here because devices exist (16GB 5th generation iPod
+    // Touch) that don't have a rear-facing camera.
+  }
 
   // Set up the session inputs.
   NSError *error = nil;
@@ -201,18 +217,21 @@
           error.localizedDescription);
     return NO;
   }
-  _backDeviceInput =
-      [AVCaptureDeviceInput deviceInputWithDevice:backCaptureDevice
-                                            error:&error];
-  if (!_backDeviceInput) {
-    NSLog(@"Failed to get capture device input: %@",
-          error.localizedDescription);
-    return NO;
+  if (backCaptureDevice) {
+    error = nil;
+    _backDeviceInput =
+        [AVCaptureDeviceInput deviceInputWithDevice:backCaptureDevice
+                                              error:&error];
+    if (error) {
+      RTCLog(@"Failed to get capture device input: %@",
+            error.localizedDescription);
+      _backDeviceInput = nil;
+    }
   }
 
   // Add the inputs.
   if (![_captureSession canAddInput:_frontDeviceInput] ||
-      ![_captureSession canAddInput:_backDeviceInput]) {
+      (_backDeviceInput && ![_captureSession canAddInput:_backDeviceInput])) {
     NSLog(@"Session does not support capture inputs.");
     return NO;
   }
@@ -336,6 +355,10 @@
   return _capturer.captureSession;
 }
 
+bool AVFoundationVideoCapturer::CanUseBackCamera() const {
+  return _capturer.canUseBackCamera;
+}
+
 void AVFoundationVideoCapturer::SetUseBackCamera(bool useBackCamera) {
   _capturer.useBackCamera = useBackCamera;
 }