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}
This commit is contained in:
hjon 2016-03-14 20:55:22 -07:00 committed by Commit bot
parent e5d5e51a82
commit a1cf366ea9
8 changed files with 89 additions and 20 deletions

View File

@ -46,6 +46,10 @@
return [super initWithMediaSource:source];
}
- (BOOL)canUseBackCamera {
return self.capturer->CanUseBackCamera();
}
- (BOOL)useBackCamera {
return self.capturer->GetUseBackCamera();
}

View File

@ -56,6 +56,10 @@ class AVFoundationVideoCapturer : public cricket::VideoCapturer {
// 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;

View File

@ -34,6 +34,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;
@ -52,6 +53,7 @@ static cricket::VideoFormat const kDefaultFormat =
@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
@ -105,10 +107,19 @@ static cricket::VideoFormat const kDefaultFormat =
_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];
}
@ -203,10 +214,15 @@ static cricket::VideoFormat const kDefaultFormat =
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;
@ -218,18 +234,21 @@ static cricket::VideoFormat const kDefaultFormat =
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;
}
@ -353,6 +372,10 @@ AVCaptureSession* AVFoundationVideoCapturer::GetCaptureSession() {
return _capturer.captureSession;
}
bool AVFoundationVideoCapturer::CanUseBackCamera() const {
return _capturer.canUseBackCamera;
}
void AVFoundationVideoCapturer::SetUseBackCamera(bool useBackCamera) {
_capturer.useBackCamera = useBackCamera;
}

View File

@ -41,6 +41,8 @@
- (instancetype)initWithFactory:(RTCPeerConnectionFactory*)factory
constraints:(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;
// Returns the active capture session.

View File

@ -28,6 +28,9 @@ NS_ASSUME_NONNULL_BEGIN
- (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;

View File

@ -27,6 +27,10 @@
return [super initWithNativeVideoSource:source];
}
- (BOOL)canUseBackCamera {
return self.capturer->CanUseBackCamera();
}
- (BOOL)useBackCamera {
return self.capturer->GetUseBackCamera();
}

View File

@ -40,6 +40,12 @@ class AVFoundationVideoCapturer : public cricket::VideoCapturer {
/** 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;

View File

@ -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 @@ static cricket::VideoFormat const kDefaultFormat =
@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 @@ static cricket::VideoFormat const kDefaultFormat =
_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 @@ static cricket::VideoFormat const kDefaultFormat =
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 @@ static cricket::VideoFormat const kDefaultFormat =
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 @@ AVCaptureSession* AVFoundationVideoCapturer::GetCaptureSession() {
return _capturer.captureSession;
}
bool AVFoundationVideoCapturer::CanUseBackCamera() const {
return _capturer.canUseBackCamera;
}
void AVFoundationVideoCapturer::SetUseBackCamera(bool useBackCamera) {
_capturer.useBackCamera = useBackCamera;
}