I am using a WKWebView
to display a fullscreen YouTube video in my app, and a AVCaptureSession to record audio and video in the background whilst browsing and playing videos on YouTube. The capture session begins when a button is pressed. However, whilst a recording is in process, when a YouTube video is selected and starts playing in fullscreen, it immediately ends the recording unexpectedly as the delegate method that handles the ending of a recording is called.
Please could someone explain to me how to solve this problem? Not too sure if this is completely related, but I got error messages such as _BSMachError: (os/kern) invalid capability (20) _BSMachError: (os/kern) invalid name (15) and Unable to simultaneously satisfy constraints.
, though the latter one seems to be referencing a separate AutoLayout issue. Any help would be greatly appreciated.
Also, I have tried using UIWebView
instead of WKWebView
. When I use UIWebView
, the problem is that the YouTube video will not even play when the video is recording. It will just open and stay at 0:00 on a black screen.
Here is the button pressed to initially start the recording.
- (void) buttonClickedStart:(UIButton*)sender //button to start/end recording {
if (!WeAreRecording) {
[self setupVideoCapture];
//----- START RECORDING -----
WeAreRecording = YES;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryRecord error:nil];
//Create temporary URL to record the video to for later viewing
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = [paths objectAtIndex:0];
NSString *outputPath = [[NSString alloc] initWithFormat:@"%@", [basePath stringByAppendingPathComponent:@"output.mp4"]];
if ([[NSFileManager defaultManager] isDeletableFileAtPath:outputPath])
[[NSFileManager defaultManager] removeItemAtPath:outputPath error:NULL];
NSURL *outputURL = [[NSURL alloc] initFileURLWithPath:outputPath];
[MovieFileOutput startRecordingToOutputFileURL:outputURL recordingDelegate:self];
self.outputURLs = outputURL;
}
else {
//----- STOP RECORDING -----
WeAreRecording = NO;
[MovieFileOutput stopRecording];
}
}
This is the method called when the button is pressed. It sets up and starts the capture session denoted as CaptureSession
.
- (void)setupVideoCapture {
// Sets up recording capture session
CaptureSession = [[AVCaptureSession alloc] init];
// Add video input to capture session
AVCaptureDevice *VideoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
if (VideoDevice) {
NSError *error;
VideoInputDevice = [[AVCaptureDeviceInput alloc] initWithDevice:[self CameraWithPosition:AVCaptureDevicePositionFront] error:&error];
if (!error) {
if ([CaptureSession canAddInput:VideoInputDevice])
[CaptureSession addInput:VideoInputDevice];
}
}
// Add audio input to capture session
AVCaptureDevice *audioCaptureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
NSError *error = nil;
AVCaptureDeviceInput *audioInput = [AVCaptureDeviceInput deviceInputWithDevice:audioCaptureDevice error:&error];
if (audioInput) {
[CaptureSession addInput:audioInput];
}
// Add movie file output to the capture session
MovieFileOutput = [[AVCaptureMovieFileOutput alloc] init];
[MovieFileOutput setMovieFragmentInterval:kCMTimeInvalid];
if ([CaptureSession canAddOutput:MovieFileOutput])
[CaptureSession addOutput:MovieFileOutput];
// Set the output properties (you don't really need to see this code)
[self CameraSetOutputProperties]; // (We call a method as it also has to be done after changing camera)
[CaptureSession setSessionPreset:AVCaptureSessionPresetMedium];
//----- START THE CAPTURE SESSION RUNNING -----
[CaptureSession startRunning];
}
This is where the WKWebView
is declared and set up.
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// Add recording button
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
CGRect rect = CGRectMake(0, 0, screenSize.width, 337);
UIButton *start = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[start addTarget:self action:@selector(buttonClickedStart:) forControlEvents:UIControlEventTouchUpInside];
[start setFrame:CGRectMake(30, 338, 35, 35)];
[start setTitle:@"" forState:UIControlStateNormal];
[start setExclusiveTouch:YES];
[start setBackgroundImage:[UIImage imageNamed:@"start.png"] forState:UIControlStateNormal];
[self.view addSubview:start];
// Add web view
webView = [[WKWebView alloc] initWithFrame:rect];
[self.view addSubview:webView];
NSString *webSite = @"http://www.youtube.com";
NSURL *url = [NSURL URLWithString:webSite];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
webView.navigationDelegate = self;
webView.UIDelegate = self;
[webView loadRequest:request]; // Load up Youtube
[self.view addSubview:webView];
}
After searching a lot, I found this thread. I did something similar: Just extend WebView and override onWindowVisibilityChanged . This way, the audio continues to play if the screen is locked or another app is opened.
For Android devices, you can play YouTube videos in the background via Google Chrome or picture in picture mode.
Restart the YouTube app or reboot your device If the YouTube app or your mobile device has been running for some time, there may not be enough resources for background play to work smoothly. Try closing the YouTube app or rebooting your phone.
Looks like the only things that are missing is setting the mix with others option and play and record category on the audio session.
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionMixWithOthers error:nil];
Edit: Setup a simple test and it works, hope this helps!
The cause of the
_BSMachError: (os/kern) invalid capability (20) _BSMachError: (os/kern) invalid name (15)
may be due to the fact that Apple introduced App Transport Security which enforces the use of 'HTTPS' URLs. Although you can modify your info.plist to make an exception, for legacy URLS, they highly recommend using HTTPS for any new URLs.
In your case that is an easy fix if you just update your youtube URL to 'https:'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With