New voice message recording mode (#2051)

* Lock voice message recording

* Use the VoiceMessageCache to store the recording file

* Rework on some composer toolbar buttons

* Update accessibility labels for voice message recording button

* PreviewTests
This commit is contained in:
Nicolas Mauri
2023-11-10 16:32:22 +01:00
committed by GitHub
parent 5a0dab1ce8
commit da831f6725
34 changed files with 283 additions and 296 deletions
+2 -1
View File
@@ -49,7 +49,8 @@ class AudioRecorderTests: XCTestCase {
return false
}
}
await audioRecorder.record(with: .uuid(UUID()))
let url = URL.temporaryDirectory.appendingPathComponent("test-voice-message").appendingPathExtension("m4a")
await audioRecorder.record(audioFileURL: url)
try await deferred.fulfill()
XCTAssertFalse(audioRecorder.isRecording)
}
@@ -57,6 +57,7 @@ class VoiceMessageRecorderTests: XCTestCase {
}
audioConverter = AudioConverterMock()
voiceMessageCache = VoiceMessageCacheMock()
voiceMessageCache.urlForRecording = FileManager.default.temporaryDirectory.appendingPathComponent("test-voice-message").appendingPathExtension("m4a")
voiceMessageRecorder = VoiceMessageRecorder(audioRecorder: audioRecorder,
mediaPlayerProvider: mediaPlayerProvider,
@@ -65,7 +66,7 @@ class VoiceMessageRecorderTests: XCTestCase {
}
private func setRecordingComplete() async throws {
audioRecorder.audioFileUrl = recordingURL
audioRecorder.audioFileURL = recordingURL
audioRecorder.currentTime = 5
let deferred = deferFulfillment(voiceMessageRecorder.actions) { action in
@@ -81,7 +82,7 @@ class VoiceMessageRecorderTests: XCTestCase {
}
func testRecordingURL() async throws {
audioRecorder.audioFileUrl = recordingURL
audioRecorder.audioFileURL = recordingURL
XCTAssertEqual(voiceMessageRecorder.recordingURL, recordingURL)
}
@@ -92,7 +93,7 @@ class VoiceMessageRecorderTests: XCTestCase {
func testStartRecording() async throws {
_ = await voiceMessageRecorder.startRecording()
XCTAssert(audioRecorder.recordWithCalled)
XCTAssert(audioRecorder.recordAudioFileURLCalled)
}
func testStopRecording() async throws {
@@ -185,17 +186,17 @@ class VoiceMessageRecorderTests: XCTestCase {
func testBuildRecordedWaveform() async throws {
// If there is no recording file, an error is expected
audioRecorder.audioFileUrl = nil
audioRecorder.audioFileURL = nil
guard case .failure(.missingRecordingFile) = await voiceMessageRecorder.buildRecordingWaveform() else {
XCTFail("An error is expected")
return
}
guard let audioFileUrl = Bundle(for: Self.self).url(forResource: "test_audio", withExtension: "mp3") else {
guard let audioFileURL = Bundle(for: Self.self).url(forResource: "test_audio", withExtension: "mp3") else {
XCTFail("Test audio file is missing")
return
}
audioRecorder.audioFileUrl = audioFileUrl
audioRecorder.audioFileURL = audioFileURL
guard case .success(let data) = await voiceMessageRecorder.buildRecordingWaveform() else {
XCTFail("A waveform is expected")
return
@@ -207,7 +208,7 @@ class VoiceMessageRecorderTests: XCTestCase {
let roomProxy = RoomProxyMock()
// If there is no recording file, an error is expected
audioRecorder.audioFileUrl = nil
audioRecorder.audioFileURL = nil
guard case .failure(.missingRecordingFile) = await voiceMessageRecorder.sendVoiceMessage(inRoom: roomProxy, audioConverter: audioConverter) else {
XCTFail("An error is expected")
return
@@ -215,7 +216,7 @@ class VoiceMessageRecorderTests: XCTestCase {
}
func testSendVoiceMessage_ConversionError() async throws {
audioRecorder.audioFileUrl = recordingURL
audioRecorder.audioFileURL = recordingURL
// If the converter returns an error
audioConverter.convertToOpusOggSourceURLDestinationURLThrowableError = AudioConverterError.conversionFailed(nil)
@@ -227,11 +228,11 @@ class VoiceMessageRecorderTests: XCTestCase {
}
func testSendVoiceMessage_InvalidFile() async throws {
guard let audioFileUrl = Bundle(for: Self.self).url(forResource: "test_voice_message", withExtension: "m4a") else {
guard let audioFileURL = Bundle(for: Self.self).url(forResource: "test_voice_message", withExtension: "m4a") else {
XCTFail("Test audio file is missing")
return
}
audioRecorder.audioFileUrl = audioFileUrl
audioRecorder.audioFileURL = audioFileURL
audioConverter.convertToOpusOggSourceURLDestinationURLClosure = { _, destination in
try? FileManager.default.removeItem(at: destination)
}
@@ -245,14 +246,14 @@ class VoiceMessageRecorderTests: XCTestCase {
}
func testSendVoiceMessage_WaveformAnlyseFailed() async throws {
guard let imageFileUrl = Bundle(for: Self.self).url(forResource: "test_image", withExtension: "png") else {
guard let imageFileURL = Bundle(for: Self.self).url(forResource: "test_image", withExtension: "png") else {
XCTFail("Test audio file is missing")
return
}
audioRecorder.audioFileUrl = imageFileUrl
audioRecorder.audioFileURL = imageFileURL
audioConverter.convertToOpusOggSourceURLDestinationURLClosure = { _, destination in
try? FileManager.default.removeItem(at: destination)
try? FileManager.default.copyItem(at: imageFileUrl, to: destination)
try? FileManager.default.copyItem(at: imageFileURL, to: destination)
}
let roomProxy = RoomProxyMock()
@@ -264,11 +265,11 @@ class VoiceMessageRecorderTests: XCTestCase {
}
func testSendVoiceMessage_SendError() async throws {
guard let audioFileUrl = Bundle(for: Self.self).url(forResource: "test_voice_message", withExtension: "m4a") else {
guard let audioFileURL = Bundle(for: Self.self).url(forResource: "test_voice_message", withExtension: "m4a") else {
XCTFail("Test audio file is missing")
return
}
audioRecorder.audioFileUrl = audioFileUrl
audioRecorder.audioFileURL = audioFileURL
audioConverter.convertToOpusOggSourceURLDestinationURLClosure = { source, destination in
try? FileManager.default.removeItem(at: destination)
let internalConverter = AudioConverter()
@@ -285,34 +286,34 @@ class VoiceMessageRecorderTests: XCTestCase {
}
func testSendVoiceMessage() async throws {
guard let audioFileUrl = Bundle(for: Self.self).url(forResource: "test_voice_message", withExtension: "m4a") else {
guard let imageFileURL = Bundle(for: Self.self).url(forResource: "test_voice_message", withExtension: "m4a") else {
XCTFail("Test audio file is missing")
return
}
let roomProxy = RoomProxyMock()
audioRecorder.currentTime = 42
audioRecorder.audioFileUrl = audioFileUrl
audioRecorder.audioFileURL = imageFileURL
_ = await voiceMessageRecorder.startRecording()
_ = await voiceMessageRecorder.stopRecording()
var convertedFileUrl: URL?
var convertedFileURL: URL?
var convertedFileSize: UInt64?
audioConverter.convertToOpusOggSourceURLDestinationURLClosure = { source, destination in
convertedFileUrl = destination
convertedFileURL = destination
try? FileManager.default.removeItem(at: destination)
let internalConverter = AudioConverter()
try internalConverter.convertToOpusOgg(sourceURL: source, destinationURL: destination)
convertedFileSize = try? UInt64(FileManager.default.sizeForItem(at: destination))
// the source URL must be the recorded file
XCTAssertEqual(source, audioFileUrl)
XCTAssertEqual(source, imageFileURL)
// check the converted file extension
XCTAssertEqual(destination.pathExtension, "ogg")
}
roomProxy.sendVoiceMessageUrlAudioInfoWaveformProgressSubjectRequestHandleClosure = { url, audioInfo, waveform, _, _ in
XCTAssertEqual(url, convertedFileUrl)
XCTAssertEqual(url, convertedFileURL)
XCTAssertEqual(audioInfo.duration, self.audioRecorder.currentTime)
XCTAssertEqual(audioInfo.size, convertedFileSize)
XCTAssertEqual(audioInfo.mimetype, "audio/ogg")
@@ -330,8 +331,8 @@ class VoiceMessageRecorderTests: XCTestCase {
XCTAssert(roomProxy.sendVoiceMessageUrlAudioInfoWaveformProgressSubjectRequestHandleCalled)
// the converted file must have been deleted
if let convertedFileUrl {
XCTAssertFalse(FileManager.default.fileExists(atPath: convertedFileUrl.path()))
if let convertedFileURL {
XCTAssertFalse(FileManager.default.fileExists(atPath: convertedFileURL.path()))
} else {
XCTFail("converted file URL is missing")
}
@@ -351,7 +352,7 @@ class VoiceMessageRecorderTests: XCTestCase {
}
func testAudioRecorderActionHandling_didStopRecording() async throws {
audioRecorder.audioFileUrl = recordingURL
audioRecorder.audioFileURL = recordingURL
audioRecorder.currentTime = 5
let deferred = deferFulfillment(voiceMessageRecorder.actions) { action in
@@ -367,7 +368,7 @@ class VoiceMessageRecorderTests: XCTestCase {
}
func testAudioRecorderActionHandling_didFailed() async throws {
audioRecorder.audioFileUrl = recordingURL
audioRecorder.audioFileURL = recordingURL
let deferred = deferFulfillment(voiceMessageRecorder.actions) { action in
switch action {
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c1e6e18b515a424aa91b552323bb5cba4d01914b51dc47e8ec3b5e9f81a57225
size 66446
oid sha256:5dbc6341b15314bd83e81fc786e9a113d5c08080362bef5b2cfd44f947e447ee
size 67930
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:866e24b28ef3ad776461af85ee96abaf83275d17c4e7c2047691479028fe0f06
size 94382
oid sha256:d2ac55d0cb116fdc1ea0c01dea819dd14162c4084d2e9bf66c42470fb1f41181
size 95317
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:225ba3d11602f2bd92ba2bb50c01c855d134945f1bbb6abedf5ff0cd549220bd
size 95840
oid sha256:77a370c81ffba8cdb1eb899deac3e81accb444872d659379e3ce16648880ea0a
size 97326
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:12c2540041f1a2739e015b962f1490cb7d78201ab5c488d7b0edab06e304e127
size 318511
oid sha256:8128aece82c38468ca5d44dbe1602282ecdd8aa6db46ea8968aec359cf2ef0e9
size 318628
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:720eccf0e4e600da78abe5772d78e871866c3fc3b48da404079dd7285f34ecc6
size 314996
oid sha256:bb67c46c12b1593eea1f3bcf3c561daf1f4d208676a884f76b973735a81bc313
size 315113
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:720eccf0e4e600da78abe5772d78e871866c3fc3b48da404079dd7285f34ecc6
size 314996
oid sha256:bb67c46c12b1593eea1f3bcf3c561daf1f4d208676a884f76b973735a81bc313
size 315113
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:22f419d23e9c8df9325e84bc44e0d706a88b08335a6a5e9bbc8be3deef08d961
size 61935
oid sha256:e47226f5fbdd1032534b2f6a1a715d9eee94b25e5ec7e02592b7c51c10a33f70
size 61828
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:454f1594e4f0eee33f53dcc3d45653087fbf1254324396b65723918af8a44536
size 56462
oid sha256:0d29e54f5d54222a0532f073b3111294335b90e84b56b277e404ceb96c602b3d
size 58855
@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ffcce0a3fe8e27798377372f73090b72a27c986d36f4936701317d60571f5b92
size 60040
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:49ba019171a846ae54d2849ff4ae4f02194fceda407fd26077cbf16a5f8682f3
size 58567
oid sha256:ada032ec7d48cc981306ffaaa0be302a3edd5356d4d9c87257596ab0a9cce8d8
size 58335