Skip to content

Commit

Permalink
[feature/sample-fps-rate] change video fps to 20 (#48)
Browse files Browse the repository at this point in the history
* [feature/sample-fps-rate] change video fps to 20

* [feature/sample-fps-rate] add SignedURL model for getting GCP v4 signed url

* [feature/sample-fps-rate] adapt APIClient and APIProtocol to upload gcp signed url v4 scheme

* [feature/sample-fps-rate] add upload v4 gcp api

* [feature/sample-fps-rate] add upload video functions to recording view
  • Loading branch information
eliakorkmaz committed Apr 22, 2024
1 parent 5357959 commit eb5dfce
Show file tree
Hide file tree
Showing 8 changed files with 97 additions and 18 deletions.
6 changes: 6 additions & 0 deletions TikTok Reporter/TikTok Reporter.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@
A91324492B62A01100EA54D9 /* SubmissionSuccessView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 684A23EF2B178F12001B83AA /* SubmissionSuccessView.swift */; };
A95A90422B7F7E88004A15F3 /* BroadcastUploadHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = A95A90412B7F7E88004A15F3 /* BroadcastUploadHelpers.m */; };
A98946322B56D0CA002F3AE6 /* AttributedString+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98946312B56D0CA002F3AE6 /* AttributedString+Extension.swift */; };
A989DAAE2BCE842000AC8062 /* SignedURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = A989DAAD2BCE842000AC8062 /* SignedURL.swift */; };
A989DAAF2BCE842900AC8062 /* SignedURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = A989DAAD2BCE842000AC8062 /* SignedURL.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -314,6 +316,7 @@
A95A90402B7F7E88004A15F3 /* TikTok ReporterScreenCapture-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "TikTok ReporterScreenCapture-Bridging-Header.h"; sourceTree = "<group>"; };
A95A90412B7F7E88004A15F3 /* BroadcastUploadHelpers.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BroadcastUploadHelpers.m; sourceTree = "<group>"; };
A98946312B56D0CA002F3AE6 /* AttributedString+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AttributedString+Extension.swift"; sourceTree = "<group>"; };
A989DAAD2BCE842000AC8062 /* SignedURL.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignedURL.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -594,6 +597,7 @@
684A23EC2B178D93001B83AA /* FormTab.swift */,
684A23F12B17922D001B83AA /* ScreenRecording.swift */,
684E2F452B23332F006A05C8 /* RecordingStorage.swift */,
A989DAAD2BCE842000AC8062 /* SignedURL.swift */,
);
path = Models;
sourceTree = "<group>";
Expand Down Expand Up @@ -1283,6 +1287,7 @@
6892A4FD2B14AE5F0023BCA8 /* Date+Formatted.swift in Sources */,
689FF05C2AF3E7E600C9FE51 /* Onboarding.swift in Sources */,
689FF03D2AF2983100C9FE51 /* InjectedValues.swift in Sources */,
A989DAAE2BCE842000AC8062 /* SignedURL.swift in Sources */,
689FF0652AF6787900C9FE51 /* OnboardingView.swift in Sources */,
68FB5B6B2B28865A003FF139 /* DataHandlingViewModel.swift in Sources */,
684E2F342B20B3B5006A05C8 /* GleanManager.swift in Sources */,
Expand Down Expand Up @@ -1374,6 +1379,7 @@
684E2F562B24C656006A05C8 /* PresentationState.swift in Sources */,
684E2F622B24C90F006A05C8 /* LoadingView.swift in Sources */,
684E2F5F2B24C8F6006A05C8 /* CGFloat+Spacing.swift in Sources */,
A989DAAF2BCE842900AC8062 /* SignedURL.swift in Sources */,
684E2F512B24C5F9006A05C8 /* Study.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
12 changes: 12 additions & 0 deletions TikTok Reporter/TikTok Reporter/Models/SignedURL.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//
// SignedURL.swift
// TikTok Reporter
//
// Created by Emrah Korkmaz on 16.04.2024.
//

import Foundation

struct SignedURL: Codable {
var url: String
}
14 changes: 14 additions & 0 deletions TikTok Reporter/TikTok Reporter/Networking/APIClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import Foundation

protocol HTTPClient {
func perform<T: Decodable>(request: APIRequest) async throws -> T
func performUpload(request: APIRequest) async throws -> Bool
}

struct APIClient: HTTPClient {
Expand All @@ -30,4 +31,17 @@ struct APIClient: HTTPClient {
throw APIError.badRequest
}
}

func performUpload(request: APIRequest) async throws -> Bool {
let (data, response) = try await URLSession.shared.data(for: request.asURLRequest())

let statusCode = (response as? HTTPURLResponse)?.statusCode ?? 400

switch statusCode {
case 200, 201:
return true
default:
return false
}
}
}
11 changes: 10 additions & 1 deletion TikTok Reporter/TikTok Reporter/Networking/APIProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,16 @@ protocol APIRequest {
extension APIRequest {

func asURLRequest() throws -> URLRequest {
guard let url = URL(string: Constants.URL.baseURL.appending(path)) else {

var urlToRequest: URL?

if let headers = headers, let contentType = headers["content-type"], contentType == "video/mp4" {
urlToRequest = URL(string: path)
} else {
urlToRequest = URL(string: Constants.URL.baseURL.appending(path))
}

guard let url = urlToRequest else {
throw APIError.invalidURL
}

Expand Down
24 changes: 24 additions & 0 deletions TikTok Reporter/TikTok Reporter/Networking/APIs/RecordingAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,39 @@ import Foundation

enum RecordingAPI: APIRequest {
case uploadRecording(contentType: String, body: Data)
case getSignedUrlPath
case uploadRecordingV4(v4SignedURL: String, body: Data)

var method: APIMethod {
switch self {
case .uploadRecording:
return .POST
case .getSignedUrlPath:
return .GET
case .uploadRecordingV4(_, _):
return .PUT
}
}

var path: String {
switch self {
case .uploadRecording:
return "storage"
case .getSignedUrlPath:
return "signedUrl"
case .uploadRecordingV4(let v4SignedURL, _):
return v4SignedURL
}
}

var body: Data? {
switch self {
case let .uploadRecording(_, data):
return data
case .getSignedUrlPath:
return nil
case let .uploadRecordingV4(_, data):
return data
}
}

Expand All @@ -38,6 +52,16 @@ enum RecordingAPI: APIRequest {
"Content-Type": contentType,
"X-API-Key": "c11442cb-790c-40f9-a357-a8205841e1f4"
]

case .getSignedUrlPath:
return [
"content-type": "application/json"
]

case .uploadRecordingV4(_, _):
return [
"content-type": "video/mp4"
]
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ enum FileManagerError: Error {

protocol ScreenRecordingServicing {
var localURL: URL? { get }


func getSignedURL() async throws -> String

func loadRecording() throws -> AVAsset
func removeRecording() throws
func updateLocalRecording(with path: String) throws -> AVAsset

func uploadRecording() async throws -> RecordingStorage?
func uploadRecording() async throws -> (SignedURL?, Bool)
}

final class ScreenRecordingService: ScreenRecordingServicing {
Expand Down Expand Up @@ -78,16 +80,17 @@ final class ScreenRecordingService: ScreenRecordingServicing {
return try loadRecording()
}

func uploadRecording() async throws -> RecordingStorage? {

func uploadRecording() async throws -> (SignedURL?,Bool) {
guard let localData = self.loadLocalData() else {
return nil
return (nil, false)
}

let signedURL = try await getSignedURL()
let status = try await apiClient.performUpload(request: RecordingAPI.uploadRecordingV4(v4SignedURL: signedURL,body: localData))


var multipartRequest = MultipartRequest()
multipartRequest.add(key: "file", fileName: Strings.fileName, fileMimeType: "video/mp4", fileData: localData)

return try await apiClient.perform(request: RecordingAPI.uploadRecording(contentType: multipartRequest.httpHeader, body: multipartRequest.httpBody))
return (SignedURL(url: signedURL), status)
}

// MARK: - Private Methods
Expand Down Expand Up @@ -136,6 +139,11 @@ final class ScreenRecordingService: ScreenRecordingServicing {

return data
}

func getSignedURL() async throws -> String {
let signedURL: SignedURL = try await apiClient.perform(request: RecordingAPI.getSignedUrlPath)
return Strings.signedURLBase + signedURL.url
}
}

// MARK: - Strings
Expand All @@ -144,4 +152,5 @@ private enum Strings {
static let fileName = "screenRecording.mp4"
static let appGroupID = "group.org.mozilla.ios.TikTok-Reporter"
static let appGroupFilePath = "Library/Documents/screenRecording.mp4"
static let signedURLBase = "https://storage.googleapis.com/regrets_reporter_recording_docs/"
}
Original file line number Diff line number Diff line change
Expand Up @@ -117,16 +117,21 @@ extension RecordView {
videoComments = ""

Task {

do {
let (signedURL, uploadStatus) = try await screenRecordingService.uploadRecording()

let storage = try await screenRecordingService.uploadRecording()
let jsonString = try JSONMapper.map(storage)

let jsonStringToScreenRecording = prepareScreenRecording(jsonString: jsonString)
if !uploadStatus {
state = .failed(nil)
return
}

gleanManager.setScreenRecording(jsonStringToScreenRecording, identifier: uuid)
gleanManager.submitScreenRecording()
if let signedURL = signedURL {
let jsonString = try JSONMapper.map(signedURL)
let jsonStringToScreenRecording = prepareScreenRecording(jsonString: jsonString)

gleanManager.setScreenRecording(jsonStringToScreenRecording, identifier: uuid)
gleanManager.submitScreenRecording()
}

state = .success

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class SampleHandler: RPBroadcastSampleHandler {
private lazy var videoInput: AVAssetWriterInput = {

let compressionProperties: [String: Any] = [
AVVideoExpectedSourceFrameRateKey: NSNumber(value: 60),
AVVideoExpectedSourceFrameRateKey: NSNumber(value: 20),
AVVideoProfileLevelKey: "HEVC_Main_AutoLevel"
]

Expand Down

0 comments on commit eb5dfce

Please sign in to comment.