@@ -10,13 +10,21 @@ import Foundation
1010import ReplayKit
1111import Photos
1212
13+ public enum WylerError : Error {
14+ case photoLibraryAccessNotGranted
15+ }
16+
1317final public class ScreenRecorder {
1418 private var videoOutputURL : URL ?
1519 private var videoWriter : AVAssetWriter ?
1620 private var videoWriterInput : AVAssetWriterInput ?
21+ private var audioWriterInput : AVAssetWriterInput ?
1722 private var saveToCameraRoll = false
23+ let recorder = RPScreenRecorder . shared ( )
1824
19- public init ( ) { }
25+ public init ( ) {
26+ recorder. isMicrophoneEnabled = true
27+ }
2028
2129 /**
2230 Starts recording the content of the application screen. It works together with stopRecording
@@ -30,12 +38,9 @@ final public class ScreenRecorder {
3038 size: CGSize ? = nil ,
3139 saveToCameraRoll: Bool = false ,
3240 errorHandler: @escaping ( Error ) -> Void ) {
33- if saveToCameraRoll {
34- checkPhotoLibraryAuthorizationStatus ( )
35- }
36-
3741 createVideoWriter ( in: outputURL, error: errorHandler)
3842 addVideoWriterInput ( size: size)
43+ addAudioWriterInput ( )
3944 startCapture ( error: errorHandler)
4045 }
4146
@@ -72,25 +77,36 @@ final public class ScreenRecorder {
7277 }
7378
7479 private func addVideoWriterInput( size: CGSize ? ) {
75- let passingSize : CGSize
76-
77- if let passedSize = size {
78- passingSize = passedSize
79- } else {
80- passingSize = UIScreen . main. bounds. size
81- }
80+ let passingSize : CGSize = size ?? UIScreen . main. bounds. size
8281
8382 let videoSettings : [ String : Any ] = [ AVVideoCodecKey: AVVideoCodecType . h264,
8483 AVVideoWidthKey: passingSize. width,
8584 AVVideoHeightKey: passingSize. height]
8685
8786 let newVideoWriterInput = AVAssetWriterInput ( mediaType: AVMediaType . video, outputSettings: videoSettings)
87+
8888 self . videoWriterInput = newVideoWriterInput
89+ newVideoWriterInput. expectsMediaDataInRealTime = true
8990 videoWriter? . add ( newVideoWriterInput)
9091 }
9192
93+ private func addAudioWriterInput( ) {
94+ let settings = [
95+ AVFormatIDKey: Int ( kAudioFormatMPEG4AAC) ,
96+ AVSampleRateKey: 12000 ,
97+ AVNumberOfChannelsKey: 1 ,
98+ AVEncoderAudioQualityKey: AVAudioQuality . high. rawValue
99+ ]
100+
101+ let audioInput = AVAssetWriterInput ( mediaType: . audio, outputSettings: settings)
102+ self . audioWriterInput = audioInput
103+
104+ audioInput. expectsMediaDataInRealTime = true
105+ videoWriter? . add ( audioInput)
106+ }
107+
92108 private func startCapture( error: @escaping ( Error ) -> Void ) {
93- RPScreenRecorder . shared ( ) . startCapture ( handler: { ( sampleBuffer, sampleType, passedError) in
109+ recorder . startCapture ( handler: { ( sampleBuffer, sampleType, passedError) in
94110 if let passedError = passedError {
95111 error ( passedError)
96112 return
@@ -99,6 +115,10 @@ final public class ScreenRecorder {
99115 switch sampleType {
100116 case . video:
101117 self . handleSampleBuffer ( sampleBuffer: sampleBuffer)
118+ case . audioApp, . audioMic:
119+ if self . audioWriterInput? . isReadyForMoreMediaData ?? false {
120+ self . audioWriterInput? . append ( sampleBuffer)
121+ }
102122 default :
103123 break
104124 }
@@ -128,8 +148,23 @@ final public class ScreenRecorder {
128148 } )
129149
130150 self . videoWriterInput? . markAsFinished ( )
151+ self . audioWriterInput? . markAsFinished ( )
131152 self . videoWriter? . finishWriting {
132- self . saveVideoToCameraRoll ( errorHandler: errorHandler)
153+ self . saveVideoToCameraRollAfterAuthorized ( errorHandler: errorHandler)
154+ }
155+ }
156+
157+ private func saveVideoToCameraRollAfterAuthorized( errorHandler: @escaping ( Error ) -> Void ) {
158+ if PHPhotoLibrary . authorizationStatus ( ) == . authorized {
159+ self . saveVideoToCameraRoll ( errorHandler: errorHandler)
160+ } else {
161+ PHPhotoLibrary . requestAuthorization ( { ( status) in
162+ if status == . authorized {
163+ self . saveVideoToCameraRoll ( errorHandler: errorHandler)
164+ } else {
165+ errorHandler ( WylerError . photoLibraryAccessNotGranted)
166+ }
167+ } )
133168 }
134169 }
135170
0 commit comments