Fix for recording
This commit is contained in:
parent
ac552c3749
commit
d95bbe51e2
@ -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 */,
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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? {
|
||||||
|
|||||||
@ -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() {
|
||||||
|
|||||||
25
AutoCat/Extensions/AudioEngine.swift
Normal file
25
AutoCat/Extensions/AudioEngine.swift
Normal 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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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"])))
|
||||||
|
|||||||
@ -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))
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user