Fix for recording

This commit is contained in:
Selim Mustafaev 2020-09-04 22:16:20 +03:00
parent ac552c3749
commit d95bbe51e2
7 changed files with 90 additions and 23 deletions

View File

@ -34,6 +34,7 @@
7A11474923FF2B2D00B424AF /* Response.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11474823FF2B2D00B424AF /* Response.swift */; }; 7A11474923FF2B2D00B424AF /* Response.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11474823FF2B2D00B424AF /* Response.swift */; };
7A11474B23FF368B00B424AF /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11474A23FF368B00B424AF /* Settings.swift */; }; 7A11474B23FF368B00B424AF /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11474A23FF368B00B424AF /* Settings.swift */; };
7A15051224DB3E3000F39631 /* AnyEncodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A15051124DB3E3000F39631 /* AnyEncodable.swift */; }; 7A15051224DB3E3000F39631 /* AnyEncodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A15051124DB3E3000F39631 /* AnyEncodable.swift */; };
7A21112A24FC3D7E003BBF6F /* AudioEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A21112924FC3D7E003BBF6F /* AudioEngine.swift */; };
7A27ADC7249D43210035F39E /* RegionsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A27ADC6249D43210035F39E /* RegionsController.swift */; }; 7A27ADC7249D43210035F39E /* RegionsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A27ADC6249D43210035F39E /* RegionsController.swift */; };
7A27ADF3249F8B650035F39E /* RecordsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A27ADF2249F8B650035F39E /* RecordsController.swift */; }; 7A27ADF3249F8B650035F39E /* RecordsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A27ADF2249F8B650035F39E /* RecordsController.swift */; };
7A27ADF5249FD2F90035F39E /* FileManagerExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A27ADF4249FD2F90035F39E /* FileManagerExt.swift */; }; 7A27ADF5249FD2F90035F39E /* FileManagerExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A27ADF4249FD2F90035F39E /* FileManagerExt.swift */; };
@ -116,6 +117,7 @@
7A11474A23FF368B00B424AF /* Settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = "<group>"; }; 7A11474A23FF368B00B424AF /* Settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = "<group>"; };
7A11474D23FFEE8800B424AF /* SVProgressHUD.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SVProgressHUD.framework; path = Carthage/Build/iOS/SVProgressHUD.framework; sourceTree = "<group>"; }; 7A11474D23FFEE8800B424AF /* SVProgressHUD.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SVProgressHUD.framework; path = Carthage/Build/iOS/SVProgressHUD.framework; sourceTree = "<group>"; };
7A15051124DB3E3000F39631 /* AnyEncodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyEncodable.swift; sourceTree = "<group>"; }; 7A15051124DB3E3000F39631 /* AnyEncodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyEncodable.swift; sourceTree = "<group>"; };
7A21112924FC3D7E003BBF6F /* AudioEngine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioEngine.swift; sourceTree = "<group>"; };
7A27ADC6249D43210035F39E /* RegionsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegionsController.swift; sourceTree = "<group>"; }; 7A27ADC6249D43210035F39E /* RegionsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegionsController.swift; sourceTree = "<group>"; };
7A27ADF2249F8B650035F39E /* RecordsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordsController.swift; sourceTree = "<group>"; }; 7A27ADF2249F8B650035F39E /* RecordsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordsController.swift; sourceTree = "<group>"; };
7A27ADF4249FD2F90035F39E /* FileManagerExt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileManagerExt.swift; sourceTree = "<group>"; }; 7A27ADF4249FD2F90035F39E /* FileManagerExt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileManagerExt.swift; sourceTree = "<group>"; };
@ -320,6 +322,7 @@
7A27ADF824A09CAD0035F39E /* CocoaError.swift */, 7A27ADF824A09CAD0035F39E /* CocoaError.swift */,
7A659B5A24A3768A0043A0F2 /* Substrings.swift */, 7A659B5A24A3768A0043A0F2 /* Substrings.swift */,
7AE26A3224EEF9EC00625033 /* UIViewControllerExt.swift */, 7AE26A3224EEF9EC00625033 /* UIViewControllerExt.swift */,
7A21112924FC3D7E003BBF6F /* AudioEngine.swift */,
); );
path = Extensions; path = Extensions;
sourceTree = "<group>"; sourceTree = "<group>";
@ -547,6 +550,7 @@
7A11474423FF06CA00B424AF /* Api.swift in Sources */, 7A11474423FF06CA00B424AF /* Api.swift in Sources */,
7A488C3D24A74B990054D0B2 /* RxCollectionViewRealmDataSource.swift in Sources */, 7A488C3D24A74B990054D0B2 /* RxCollectionViewRealmDataSource.swift in Sources */,
7AB67E8E2435D1A000258F61 /* CustomButton.swift in Sources */, 7AB67E8E2435D1A000258F61 /* CustomButton.swift in Sources */,
7A21112A24FC3D7E003BBF6F /* AudioEngine.swift in Sources */,
7A8A220B248D67B60073DFD9 /* VehicleReportImage.swift in Sources */, 7A8A220B248D67B60073DFD9 /* VehicleReportImage.swift in Sources */,
7A488C3E24A74B990054D0B2 /* Reactive+RxRealmDataSources.swift in Sources */, 7A488C3E24A74B990054D0B2 /* Reactive+RxRealmDataSources.swift in Sources */,
7A27ADC7249D43210035F39E /* RegionsController.swift in Sources */, 7A27ADC7249D43210035F39E /* RegionsController.swift in Sources */,

View File

@ -79,5 +79,21 @@
landmarkType = "7"> landmarkType = "7">
</BreakpointContent> </BreakpointContent>
</BreakpointProxy> </BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "CFC2DD73-A257-45F3-A7A8-7D9462944F86"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "AutoCat/Extensions/AudioEngine.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "12"
endingLineNumber = "12"
landmarkName = "setCategoryAsync(_:)"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
</Breakpoints> </Breakpoints>
</Bucket> </Bucket>

View File

@ -16,6 +16,7 @@ class RecordsController: UIViewController, UITableViewDelegate {
var addButton: UIBarButtonItem! var addButton: UIBarButtonItem!
let bag = DisposeBag() let bag = DisposeBag()
var recordDisposable: Disposable? var recordDisposable: Disposable?
var audioSessionObserver: NSObjectProtocol?
let validLetters = ["А", "В", "Е", "К", "М", "Н", "О", "Р", "С", "Т", "У", "Х"] let validLetters = ["А", "В", "Е", "К", "М", "Н", "О", "Р", "С", "Т", "У", "Х"]
@ -123,13 +124,26 @@ class RecordsController: UIViewController, UITableViewDelegate {
.observeOn(MainScheduler.instance) .observeOn(MainScheduler.instance)
.flatMap(self.makeStartSoundIfNeeded) .flatMap(self.makeStartSoundIfNeeded)
.flatMap { .flatMap {
DispatchQueue.main.async { #if targetEnvironment(macCatalyst) || targetEnvironment(simulator)
alert = UIAlertController(title: "Recording...", message: nil, preferredStyle: .alert) DispatchQueue.main.async {
alert!.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { _ in self.recordDisposable?.dispose() })) alert = self.showRecordingAlert()
alert!.addAction(UIAlertAction(title: "Done", style: .default, handler: { _ in self.recorder?.stopRecording() })) }
self.present(alert!, animated: true) #else
} if let observer = self.audioSessionObserver {
NotificationCenter.default.removeObserver(observer, name: AVAudioSession.routeChangeNotification, object: nil)
}
self.audioSessionObserver = NotificationCenter.default.addObserver(forName: AVAudioSession.routeChangeNotification, object: nil, queue: .main) { notification in
guard let dict = notification.userInfo as? [String: Any],
let prev = dict["AVAudioSessionRouteChangePreviousRouteKey"] as? AVAudioSessionRouteDescription,
let reasonInt = dict["AVAudioSessionRouteChangeReasonKey"] as? NSNumber,
let reason = AVAudioSession.RouteChangeReason(rawValue: reasonInt.uintValue),
let session = notification.object as? AVAudioSession else { return }
if reason == .categoryChange && session.category == .playAndRecord && prev.inputs.isEmpty && !session.currentRoute.inputs.isEmpty {
alert = self.showRecordingAlert()
}
}
#endif
let date = Date() let date = Date()
let fileName = "recording-\(date.timeIntervalSince1970).m4a" let fileName = "recording-\(date.timeIntervalSince1970).m4a"
url = try FileManager.default.url(for: fileName, in: "recordings") url = try FileManager.default.url(for: fileName, in: "recordings")
@ -160,6 +174,14 @@ class RecordsController: UIViewController, UITableViewDelegate {
} }
} }
func showRecordingAlert() -> UIAlertController {
let alert = UIAlertController(title: "Recording...", message: nil, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { _ in self.recordDisposable?.dispose() }))
alert.addAction(UIAlertAction(title: "Done", style: .default, handler: { _ in self.recorder?.stopRecording() }))
self.present(alert, animated: true)
return alert
}
// MARK: - Processing // MARK: - Processing
func getPlateNumber(from recognizedText: String) -> String? { func getPlateNumber(from recognizedText: String) -> String? {

View File

@ -61,7 +61,7 @@ class SettingsController: FormViewController {
} }
} }
+++ Section(footer: "When enabled, you will hear short sound before starting audio recording. This will only work when audio record is started via Siri") +++ Section(footer: "When enabled, you will hear short sound before starting audio recording. This will only work when audio record is started via Siri") { $0.tag = "BeepRecordSection" }
<<< SwitchRow("BeepRecord") { row in <<< SwitchRow("BeepRecord") { row in
row.title = "Beep before record" row.title = "Beep before record"
row.value = Settings.shared.recordBeep row.value = Settings.shared.recordBeep
@ -75,6 +75,13 @@ class SettingsController: FormViewController {
<<< ButtonRow("SignOut") { $0.title = "Sign Out" }.onCellSelection { cell, row in <<< ButtonRow("SignOut") { $0.title = "Sign Out" }.onCellSelection { cell, row in
self.logout() self.logout()
} }
#if targetEnvironment(macCatalyst)
if let beepSection = self.form.sectionBy(tag: "BeepRecordSection") {
beepSection.hidden = true
beepSection.evaluateHidden()
}
#endif
} }
func logout() { func logout() {

View File

@ -0,0 +1,25 @@
import Foundation
import AVFoundation
import RxSwift
extension AVAudioSession {
func setCategoryAsync(_ category: AVAudioSession.Category) -> Single<Void> {
if self.category == category {
return .just(())
} else {
return Single.create { observer in
NotificationCenter.default.addObserver(forName: AVAudioSession.routeChangeNotification, object: self, queue: .main) { notification in
print("")
}
do {
try self.setCategory(category, mode: .default, options: [])
} catch {
observer(.error(error))
}
return Disposables.create()
}
}
}
}

View File

@ -72,14 +72,14 @@ class LocationManager {
private static func checkPermissions() -> Single<Void> { private static func checkPermissions() -> Single<Void> {
return Single<Void>.create { observer in return Single<Void>.create { observer in
switch CLLocationManager.authorizationStatus() { switch CLLocationManager.authorizationStatus() {
case .authorizedWhenInUse: case .authorizedWhenInUse, .authorizedAlways:
observer(.success(())) observer(.success(()))
break break
case .notDetermined: case .notDetermined:
self.manager.requestWhenInUseAuthorization() self.manager.requestWhenInUseAuthorization()
let proxy = RxLocationManagerDelegateProxy.proxy(for: self.manager) let proxy = RxLocationManagerDelegateProxy.proxy(for: self.manager)
_ = proxy.authSubject.skip(1).first().subscribe(onSuccess: { result in _ = proxy.authSubject.filter{ $0 != .notDetermined }.first().subscribe(onSuccess: { result in
if let status = result, status == .authorizedWhenInUse { if let status = result, [.authorizedWhenInUse, .authorizedAlways].contains(status) {
observer(.success(())) observer(.success(()))
} else { } else {
observer(.error(NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "Location permission error"]))) observer(.error(NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "Location permission error"])))

View File

@ -3,6 +3,7 @@ import Speech
import AVFoundation import AVFoundation
import AudioToolbox import AudioToolbox
import RxSwift import RxSwift
import os.log
class Recorder { class Recorder {
@ -28,15 +29,7 @@ class Recorder {
func microphoneAvailable() -> Bool { func microphoneAvailable() -> Bool {
// FIXME: // FIXME:
// This is primarily for mac catalyst app. return true
// On iOS this will always return true (as there is always at least one microphone on any iOS device)
let session = AVAudioSession.sharedInstance()
// #if targetEnvironment(macCatalyst)
// for input in session.availableInputs! {
// print(input.portType == .headsetMic)
// }
// #endif
return session.availableInputs?.contains(where: { $0.portType == .builtInMic }) ?? false
} }
func requestPermissions() -> Single<Void> { func requestPermissions() -> Single<Void> {
@ -94,9 +87,6 @@ class Recorder {
} }
do { do {
try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .default, options: [])
try AVAudioSession.sharedInstance().setActive(true)
let inFormat = self.engine.inputNode.outputFormat(forBus: 0) let inFormat = self.engine.inputNode.outputFormat(forBus: 0)
ExtAudioFileSetProperty(fileRef, kExtAudioFileProperty_ClientDataFormat, UInt32(MemoryLayout<AudioStreamBasicDescription>.size), inFormat.streamDescription) ExtAudioFileSetProperty(fileRef, kExtAudioFileProperty_ClientDataFormat, UInt32(MemoryLayout<AudioStreamBasicDescription>.size), inFormat.streamDescription)
@ -123,6 +113,9 @@ class Recorder {
self.engine.prepare() self.engine.prepare()
try self.engine.start() try self.engine.start()
try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .default, options: [])
try AVAudioSession.sharedInstance().setActive(true)
} catch { } catch {
observer(.error(error)) observer(.error(error))
} }