From 42ca60474dad0229156f3bd292bad2415f4303f6 Mon Sep 17 00:00:00 2001 From: liamcottle Date: Sat, 10 Aug 2024 22:39:34 +1200 Subject: [PATCH] allow selecting audio mode when recording voice message --- package-lock.json | 9 ++ package.json | 5 +- .../components/messages/AddAudioButton.vue | 76 ++++++++++++++++ .../messages/ConversationViewer.vue | 90 ++++++++++++------- src/frontend/main.js | 2 + 5 files changed, 149 insertions(+), 33 deletions(-) create mode 100644 src/frontend/components/messages/AddAudioButton.vue diff --git a/package-lock.json b/package-lock.json index 0342882..ac506f4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "1.9.0", "license": "MIT", "dependencies": { + "click-outside-vue3": "^4.0.1", "electron-prompt": "^1.7.0", "mitt": "^3.0.1", "vue-router": "^4.4.2" @@ -1939,6 +1940,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/click-outside-vue3": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/click-outside-vue3/-/click-outside-vue3-4.0.1.tgz", + "integrity": "sha512-sbplNecrup5oGqA3o4bo8XmvHRT6q9fvw21Z67aDbTqB9M6LF7CuYLTlLvNtOgKU6W3zst5H5zJuEh4auqA34g==", + "engines": { + "node": ">=6" + } + }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", diff --git a/package.json b/package.json index 0208b22..b75cb20 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,8 @@ "dist": "npm run build && python setup.py build && electron-builder --publish=never" }, "license": "MIT", - "engines" : { - "node" : ">=18" + "engines": { + "node": ">=18" }, "devDependencies": { "@vitejs/plugin-vue": "^5.1.2", @@ -94,6 +94,7 @@ } }, "dependencies": { + "click-outside-vue3": "^4.0.1", "electron-prompt": "^1.7.0", "mitt": "^3.0.1", "vue-router": "^4.4.2" diff --git a/src/frontend/components/messages/AddAudioButton.vue b/src/frontend/components/messages/AddAudioButton.vue new file mode 100644 index 0000000..940345e --- /dev/null +++ b/src/frontend/components/messages/AddAudioButton.vue @@ -0,0 +1,76 @@ + + + diff --git a/src/frontend/components/messages/ConversationViewer.vue b/src/frontend/components/messages/ConversationViewer.vue index babf28c..2c93efe 100644 --- a/src/frontend/components/messages/ConversationViewer.vue +++ b/src/frontend/components/messages/ConversationViewer.vue @@ -310,20 +310,12 @@
- - + + Recording: {{ audioAttachmentRecordingDuration }} +
@@ -363,9 +355,13 @@ import Utils from "../../js/Utils"; import DialogUtils from "../../js/DialogUtils"; import NotificationUtils from "../../js/NotificationUtils"; import WebSocketConnection from "../../js/WebSocketConnection"; +import AddAudioButton from "./AddAudioButton.vue"; export default { name: 'ConversationViewer', + components: { + AddAudioButton, + }, props: { myLxmfAddressHash: String, selectedPeer: Object, @@ -1018,7 +1014,7 @@ export default { clearImageInput: function() { this.$refs["image-input"].value = null; }, - async startRecordingAudioAttachment() { + async startRecordingAudioAttachment(args) { // do nothing if already recording if(this.isRecordingAudioAttachment){ @@ -1030,22 +1026,36 @@ export default { return; } - // start recording microphone - this.audioAttachmentMicrophoneRecorder = new Codec2MicrophoneRecorder(); - this.audioAttachmentRecordingStartedAt = Date.now(); - this.isRecordingAudioAttachment = await this.audioAttachmentMicrophoneRecorder.start(); + // handle selected codec + switch(args.codec){ + case "codec2": { - // update recording time in ui every second - this.audioAttachmentRecordingDuration = Utils.formatMinutesSeconds(0); - this.audioAttachmentRecordingTimer = setInterval(() => { - const recordingDurationMillis = Date.now() - this.audioAttachmentRecordingStartedAt; - const recordingDurationSeconds = recordingDurationMillis / 1000; - this.audioAttachmentRecordingDuration = Utils.formatMinutesSeconds(recordingDurationSeconds); - }, 1000); + // start recording microphone + this.audioAttachmentMicrophoneRecorder = new Codec2MicrophoneRecorder(); + this.audioAttachmentMicrophoneRecorder.codec2Mode = args.mode; + this.audioAttachmentRecordingStartedAt = Date.now(); + this.isRecordingAudioAttachment = await this.audioAttachmentMicrophoneRecorder.start(); - // alert if failed to start recording - if(!this.isRecordingAudioAttachment){ - DialogUtils.alert("failed to start recording"); + // update recording time in ui every second + this.audioAttachmentRecordingDuration = Utils.formatMinutesSeconds(0); + this.audioAttachmentRecordingTimer = setInterval(() => { + const recordingDurationMillis = Date.now() - this.audioAttachmentRecordingStartedAt; + const recordingDurationSeconds = recordingDurationMillis / 1000; + this.audioAttachmentRecordingDuration = Utils.formatMinutesSeconds(recordingDurationSeconds); + }, 1000); + + // alert if failed to start recording + if(!this.isRecordingAudioAttachment){ + DialogUtils.alert("failed to start recording"); + } + + break; + + } + default: { + DialogUtils.alert(`Unhandled microphone recorder codec: ${args.codec}`); + break; + } } }, @@ -1069,7 +1079,8 @@ export default { } // decode codec2 audio back to wav so we can show a preview audio player before user sends it - const decoded = await Codec2Lib.runDecode("1200", new Uint8Array(audio)); + const codec2Mode = this.audioAttachmentMicrophoneRecorder.codec2Mode; + const decoded = await Codec2Lib.runDecode(codec2Mode, new Uint8Array(audio)); // convert decoded codec2 to wav audio and create a blob const wavAudio = await Codec2Lib.rawToWav(decoded); @@ -1077,9 +1088,26 @@ export default { type: "audio/wav", }); + // determine audio mode + var audioMode = null; + switch(codec2Mode){ + case "1200": { + audioMode = 0x04; // LXMF.AM_CODEC2_1200 + break; + } + case "3200": { + audioMode = 0x09; // LXMF.AM_CODEC2_3200 + break; + } + default: { + DialogUtils.alert(`Unhandled microphone recorder codec2Mode: ${codec2Mode}`); + return; + } + } + // update message audio attachment this.newMessageAudio = { - audio_mode: 0x04, // hardcoded to LXMF.AM_CODEC2_1200 for now + audio_mode: audioMode, audio_blob: new Blob([audio]), audio_wav_url: URL.createObjectURL(wavBlob), }; diff --git a/src/frontend/main.js b/src/frontend/main.js index 5979d09..6c2e067 100644 --- a/src/frontend/main.js +++ b/src/frontend/main.js @@ -1,5 +1,6 @@ import { createApp } from 'vue'; import { createRouter, createWebHashHistory } from 'vue-router'; +import vClickOutside from "click-outside-vue3"; import App from './components/App.vue'; import AboutPage from "./components/about/AboutPage.vue"; @@ -27,4 +28,5 @@ const router = createRouter({ createApp(App) .use(router) + .use(vClickOutside) .mount('#app');