-
-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add support for native screen recording (#330)
- Loading branch information
1 parent
e00a5a6
commit d2f5b25
Showing
28 changed files
with
1,363 additions
and
62 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
save-exact=true | ||
package-lock=false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
57 changes: 57 additions & 0 deletions
57
WebDriverAgentMac/IntegrationTests/AMVideoRecordingTests.m
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
/* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* See the NOTICE file distributed with this work for additional | ||
* information regarding copyright ownership. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
#import <XCTest/XCTest.h> | ||
|
||
#import "AMIntegrationTestCase.h" | ||
#import "AMVideoRecorder.h" | ||
#import "FBScreenRecordingRequest.h" | ||
#import "FBTestMacros.h" | ||
#import "FBScreenRecordingContainer.h" | ||
#import "FBScreenRecordingPromise.h" | ||
|
||
|
||
@interface AMVideoRecordingTests : AMIntegrationTestCase | ||
@end | ||
|
||
@implementation AMVideoRecordingTests | ||
|
||
- (void)setUp | ||
{ | ||
[super setUp]; | ||
static dispatch_once_t onceToken; | ||
dispatch_once(&onceToken, ^{ | ||
[self launchApplication]; | ||
}); | ||
} | ||
|
||
- (void)testVideoRecording | ||
{ | ||
AMVideoRecorder *recorder = AMVideoRecorder.sharedInstance; | ||
FBScreenRecordingRequest *request = [[FBScreenRecordingRequest alloc] initWithFps:24 | ||
codec:0 | ||
displayID:nil]; | ||
NSError *error; | ||
FBScreenRecordingPromise *promise = [recorder startScreenRecordingWithRequest:request | ||
error:&error]; | ||
XCTAssertNotNil(promise); | ||
XCTAssertNil(error); | ||
FBWaitExact(5); | ||
XCTAssertTrue([recorder stopScreenRecordingWithUUID:promise.identifier error:&error]); | ||
XCTAssertNil(error); | ||
} | ||
|
||
@end |
27 changes: 27 additions & 0 deletions
27
WebDriverAgentMac/WebDriverAgentLib/Commands/AMVideoCommands.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
/* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* See the NOTICE file distributed with this work for additional | ||
* information regarding copyright ownership. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
#import <Foundation/Foundation.h> | ||
|
||
#import <WebDriverAgentLib/FBCommandHandler.h> | ||
|
||
NS_ASSUME_NONNULL_BEGIN | ||
|
||
@interface AMVideoCommands : NSObject <FBCommandHandler> | ||
|
||
@end | ||
|
||
NS_ASSUME_NONNULL_END |
120 changes: 120 additions & 0 deletions
120
WebDriverAgentMac/WebDriverAgentLib/Commands/AMVideoCommands.m
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
/* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* See the NOTICE file distributed with this work for additional | ||
* information regarding copyright ownership. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
#import "AMVideoCommands.h" | ||
|
||
#import "FBRouteRequest.h" | ||
#import "FBScreenRecordingContainer.h" | ||
#import "FBScreenRecordingPromise.h" | ||
#import "FBScreenRecordingRequest.h" | ||
#import "AMScreenUtils.h" | ||
#import "FBSession.h" | ||
#import "AMVideoRecorder.h" | ||
#import "FBErrorBuilder.h" | ||
|
||
const NSUInteger DEFAULT_FPS = 24; | ||
const NSUInteger DEFAULT_CODEC = 0; | ||
|
||
@implementation AMVideoCommands | ||
|
||
+ (NSArray *)routes | ||
{ | ||
return | ||
@[ | ||
[[FBRoute POST:@"/wda/video/start"] respondWithTarget:self action:@selector(handleStartVideoRecording:)], | ||
[[FBRoute POST:@"/wda/video/stop"] respondWithTarget:self action:@selector(handleStopVideoRecording:)], | ||
[[FBRoute GET:@"/wda/video"] respondWithTarget:self action:@selector(handleGetVideoRecording:)], | ||
|
||
[[FBRoute POST:@"/wda/video/start"].withoutSession respondWithTarget:self action:@selector(handleStartVideoRecording:)], | ||
[[FBRoute POST:@"/wda/video/stop"].withoutSession respondWithTarget:self action:@selector(handleStopVideoRecording:)], | ||
[[FBRoute GET:@"/wda/video"].withoutSession respondWithTarget:self action:@selector(handleGetVideoRecording:)], | ||
]; | ||
} | ||
|
||
+ (id<FBResponsePayload>)handleStartVideoRecording:(FBRouteRequest *)request | ||
{ | ||
FBScreenRecordingPromise *activeScreenRecording = FBScreenRecordingContainer.sharedInstance.screenRecordingPromise; | ||
if (nil != activeScreenRecording) { | ||
return FBResponseWithObject([FBScreenRecordingContainer.sharedInstance toDictionary] ?: [NSNull null]); | ||
} | ||
|
||
NSNumber *fps = (NSNumber *)request.arguments[@"fps"] ?: @(DEFAULT_FPS); | ||
NSNumber *codec = (NSNumber *)request.arguments[@"codec"] ?: @(DEFAULT_CODEC); | ||
NSNumber *displayID = (NSNumber *)request.arguments[@"displayId"]; | ||
if (nil != displayID) { | ||
NSError *error; | ||
if (![self verifyDisplayWithID:displayID.longLongValue error:&error]) { | ||
return FBResponseWithStatus([FBCommandStatus invalidArgumentErrorWithMessage:error.description | ||
traceback:nil]); | ||
} | ||
} | ||
FBScreenRecordingRequest *recordingRequest = [[FBScreenRecordingRequest alloc] initWithFps:fps.integerValue | ||
codec:codec.longLongValue | ||
displayID:displayID]; | ||
NSError *error; | ||
FBScreenRecordingPromise* promise = [AMVideoRecorder.sharedInstance startScreenRecordingWithRequest:recordingRequest | ||
error:&error]; | ||
if (nil == promise) { | ||
[FBScreenRecordingContainer.sharedInstance reset]; | ||
return FBResponseWithUnknownError(error); | ||
} | ||
[FBScreenRecordingContainer.sharedInstance storeScreenRecordingPromise:promise | ||
fps:fps.integerValue | ||
codec:codec.longLongValue | ||
displayID:displayID]; | ||
return FBResponseWithObject([FBScreenRecordingContainer.sharedInstance toDictionary]); | ||
} | ||
|
||
+ (id<FBResponsePayload>)handleStopVideoRecording:(FBRouteRequest *)request | ||
{ | ||
FBScreenRecordingPromise *activeScreenRecording = FBScreenRecordingContainer.sharedInstance.screenRecordingPromise; | ||
if (nil == activeScreenRecording) { | ||
return FBResponseWithOK(); | ||
} | ||
|
||
NSUUID *recordingId = activeScreenRecording.identifier; | ||
NSDictionary *response = [FBScreenRecordingContainer.sharedInstance toDictionary]; | ||
NSError *error; | ||
if (![AMVideoRecorder.sharedInstance stopScreenRecordingWithUUID:recordingId error:&error]) { | ||
[FBScreenRecordingContainer.sharedInstance reset]; | ||
return FBResponseWithUnknownError(error); | ||
} | ||
[FBScreenRecordingContainer.sharedInstance reset]; | ||
return FBResponseWithObject(response); | ||
} | ||
|
||
+ (id<FBResponsePayload>)handleGetVideoRecording:(FBRouteRequest *)request | ||
{ | ||
return FBResponseWithObject([FBScreenRecordingContainer.sharedInstance toDictionary] ?: [NSNull null]); | ||
} | ||
|
||
+ (BOOL)verifyDisplayWithID:(long long)displayID error:(NSError **)error | ||
{ | ||
NSMutableArray* availableIds = [NSMutableArray array]; | ||
for (XCUIScreen *screen in XCUIScreen.screens) { | ||
long long currentDisplayId = AMFetchScreenId(screen); | ||
if (displayID == currentDisplayId) { | ||
return YES; | ||
} | ||
[availableIds addObject:@(currentDisplayId)]; | ||
} | ||
return [[[FBErrorBuilder builder] | ||
withDescriptionFormat:@"The provided display identifier %lld is not known. Only the following values are allowed: %@", | ||
displayID, [availableIds componentsJoinedByString:@","]] | ||
buildError:error]; | ||
} | ||
|
||
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.