Voice Recorder Component

Thank you, I think I understand you. Direct audio recording is not possible.

The component currently doesn’t work because of a CSP issue.

Adding https://cdn.jsdelivr.net/ to the content security policy script src site setting doesn’t fix the issue: the recording button will work, but the file creation will trigger another JS error:

Refused to create a worker from 'blob:https://discourse.canapin.dev/a2d7c36c-2919-48a4-9ca6-8da59a2b020e' because it violates the following Content Security Policy directive: "worker-src 'self' https://discourse.canapin.dev/assets/ https://discourse.canapin.dev/brotli_asset/ https://discourse.canapin.dev/javascripts/ https://discourse.canapin.dev/plugins/".

Voice Recorder is (mostly) working on my site. See the below screenshots of my process…

Just after recording, nothing is clickable (but I can see there underlined in red that the file has indeed been recorded and inserted into the post)…

Then clicking the Back browser button (because the Upload button is non-responsive) I arrive back to the composer where I can see the file has been inserted, and does work to play in the preview pane …

Then, after clicking + Create Topic, the post appears properly…

However, I did get this error in the console immediately after I had clicked the Stop Recording button…

Also, after clicking Upload button I get a second error…

And finally, after clicking the Cancel button I get a third error…

Despite these errors, the audio clip is appearing and playing correctly in the post.

Trying to understand the errors I’m getting in trying to use this Theme Component.

Other than the modal not closing, things otherwise seem to work.

(And if I refresh the page in order to escape the modal, I do arrive back in the composer where the file has recorded and properly uploaded, and is playable, but not in the preview, only after saving the post.)

Here is my best clue thus far…

Is this a possible solution…

1) When the modal opens (after I click the microphone button in the composer)…

2) When I click the playback button (in the modal) to review the recording prior to upload…

3) When I click the upload button (in the modal)…

Here is the entire log copied from the Chrome Inspector…

deprecate-shim.js:33 DEPRECATION: Function prototype extensions have been deprecated, please migrate from function(){}.on('foo') to on('foo', function() {}). [deprecation id: function-prototype-extensions.on] See https://deprecations.emberjs.com/v3.x#toc_function-prototype-extensions-on for more details.
(anonymous) @ deprecate-shim.js:33
e @ deprecate-shim.js:10
(anonymous) @ main.js:43
e @ deprecate-shim.js:10
(anonymous) @ main.js:78
e @ deprecate-shim.js:10
require.deprecate @ deprecate-shim.js:17
value @ function.js:139
(anonymous) @ autoplay-media.js:50
e.withPluginApi @ plugin-api.js:2247
initialize @ autoplay-media.js:47
i.initialize @ app.js:173
(anonymous) @ index.js:126
e.each @ dag-map.js:192
e.walk @ dag-map.js:121
e.each @ dag-map.js:66
e.topsort @ dag-map.js:72
_runInitializer @ index.js:138
runInstanceInitializers @ index.js:124
_bootSync @ instance.js:101
didBecomeReady @ application.js:656
p.invoke @ queue.ts:201
p.flush @ queue.ts:98
h.flush @ deferred-action-queues.ts:75
$._end @ index.ts:616
_boundAutorunEnd @ index.ts:257
Promise.then (async)
n @ platform.ts:28
flush @ index.js:41
$._scheduleAutorun @ index.ts:803
$._ensureInstance @ index.ts:791
$.schedule @ index.ts:384
_ @ index.js:351
waitForDOMReady @ application.js:409
init @ application.js:323
r @ index.js:388
_ @ core_object.js:122
create @ core_object.js:626
(anonymous) @ start-app.js:4
(anonymous) @ discourse-boot.js:20
(anonymous) @ discourse-boot.js:1
deprecated.js:64 Deprecation notice: DButton no longer supports @action as a string. Please refactor to use an closure action instead. [deprecation id: discourse.d-button-action-string]
e.default @ deprecated.js:64
y @ d-button.js:91
createComponent @ base-component-manager.js:31
createComponent @ ember-component-manager.js:50
create @ manager.js:419
create @ glimmer-component-with-deprecated-parent-view.js:11
(anonymous) @ runtime.js:2679
evaluate @ runtime.js:1052
evaluateSyscall @ runtime.js:4263
evaluateInner @ runtime.js:4234
evaluateOuter @ runtime.js:4227
next @ runtime.js:5058
_execute @ runtime.js:5045
execute @ runtime.js:5038
handleException @ runtime.js:4372
handleException @ runtime.js:4580
throw @ runtime.js:4319
evaluate @ runtime.js:2091
_execute @ runtime.js:4306
execute @ runtime.js:4291
rerender @ runtime.js:4606
render @ index.js:6751
(anonymous) @ index.js:7013
Mt @ runtime.js:4139
_renderRoots @ index.js:6996
_renderRootsTransaction @ index.js:7039
_revalidate @ index.js:7072
p.invoke @ queue.ts:201
p.flush @ queue.ts:98
h.flush @ deferred-action-queues.ts:75
$._end @ index.ts:616
_boundAutorunEnd @ index.ts:257
Promise.then (async)
n @ platform.ts:28
flush @ index.js:41
$._scheduleAutorun @ index.ts:803
$._end @ index.ts:623
_boundAutorunEnd @ index.ts:257
Promise.then (async)
n @ platform.ts:28
flush @ index.js:41
$._scheduleAutorun @ index.ts:803
$._end @ index.ts:623
_boundAutorunEnd @ index.ts:257
Promise.then (async)
n @ platform.ts:28
flush @ index.js:41
$._scheduleAutorun @ index.ts:803
$._end @ index.ts:623
_boundAutorunEnd @ index.ts:257
Promise.then (async)
n @ platform.ts:28
flush @ index.js:41
$._scheduleAutorun @ index.ts:803
$._end @ index.ts:623
_boundAutorunEnd @ index.ts:257
Promise.then (async)
n @ platform.ts:28
flush @ index.js:41
$._scheduleAutorun @ index.ts:803
$._ensureInstance @ index.ts:791
$.ensureInstance @ index.ts:579
scheduleRevalidate @ index.js:5390
dirtyTag @ validator.js:411
R @ validator.js:486
F @ index.js:497
z @ index.js:533
_set @ index.js:1848
set @ index.js:1790
r @ index.js:930
De @ index.js:1390
Te @ index.js:1385
set @ observable.js:175
_setModel @ composer.js:1000
await in _setModel (async)
open @ composer.js:980
await in open (async)
editPost @ topic.js:611
$._join @ index.ts:646
$.join @ index.ts:362
p @ index.js:157
(anonymous) @ index.js:708
a @ index.js:128
(anonymous) @ index.js:707
(anonymous) @ index.js:666
_sendComponentAction @ widget.js:275
(anonymous) @ widget.js:319
rerenderResult @ widget.js:291
sendWidgetAction @ widget.js:314
click @ button.js:122
(anonymous) @ hooks.js:236
(anonymous) @ hooks.js:202
rerenderResult @ widget.js:291
R @ hooks.js:202
(anonymous) @ hooks.js:236
dispatch @ jquery.js:5135
g.handle @ jquery.js:4939
deprecated.js:64 Deprecation notice: DButton no longer supports @action as a string. Please refactor to use an closure action instead. [deprecation id: discourse.d-button-action-string]
e.default @ deprecated.js:64
_triggerAction @ d-button.js:164
click @ d-button.js:144
deprecated.js:64 [THEME 11 'Voice Recorder'] Deprecation notice: Defining modals using a controller is deprecated. Use the component-based API instead. (modal: audio_upload) [deprecated since Discourse 3.1] [removal in Discourse 3.2] [deprecation id: discourse.modal-controllers] [info: https://meta.discourse.org/t/268057]
e.default @ deprecated.js:64
show @ modal.js:126
e.default @ show-modal.js:36
showAudioUploadModal @ audio-upload-initializer.js:15
send @ action_support.js:20
r @ index.js:388
_triggerAction @ d-button.js:166
click @ d-button.js:144
deprecated.js:64 Deprecation notice: DButton no longer supports @action as a string. Please refactor to use an closure action instead. [deprecation id: discourse.d-button-action-string]
e.default @ deprecated.js:64
y @ d-button.js:91
createComponent @ base-component-manager.js:31
createComponent @ ember-component-manager.js:50
create @ manager.js:419
create @ glimmer-component-with-deprecated-parent-view.js:11
(anonymous) @ runtime.js:2679
evaluate @ runtime.js:1052
evaluateSyscall @ runtime.js:4263
evaluateInner @ runtime.js:4234
evaluateOuter @ runtime.js:4227
next @ runtime.js:5058
_execute @ runtime.js:5045
execute @ runtime.js:5038
handleException @ runtime.js:4372
handleException @ runtime.js:4580
throw @ runtime.js:4319
evaluate @ runtime.js:2091
_execute @ runtime.js:4306
execute @ runtime.js:4291
rerender @ runtime.js:4606
render @ index.js:6751
(anonymous) @ index.js:7013
Mt @ runtime.js:4139
_renderRoots @ index.js:6996
_renderRootsTransaction @ index.js:7039
_revalidate @ index.js:7072
p.invoke @ queue.ts:201
p.flush @ queue.ts:98
h.flush @ deferred-action-queues.ts:75
$._end @ index.ts:616
_boundAutorunEnd @ index.ts:257
Promise.then (async)
n @ platform.ts:28
flush @ index.js:41
$._scheduleAutorun @ index.ts:803
$._end @ index.ts:623
_boundAutorunEnd @ index.ts:257
Promise.then (async)
n @ platform.ts:28
flush @ index.js:41
$._scheduleAutorun @ index.ts:803
$._end @ index.ts:623
_boundAutorunEnd @ index.ts:257
Promise.then (async)
n @ platform.ts:28
flush @ index.js:41
$._scheduleAutorun @ index.ts:803
$._ensureInstance @ index.ts:791
$.ensureInstance @ index.ts:579
scheduleRevalidate @ index.js:5390
dirtyTag @ validator.js:411
R @ validator.js:486
setter @ validator.js:702
c @ index.js:3501
close @ modal.js:62
close @ modal.js:177
show @ modal.js:122
e.default @ show-modal.js:36
showAudioUploadModal @ audio-upload-initializer.js:15
send @ action_support.js:20
r @ index.js:388
_triggerAction @ d-button.js:166
click @ d-button.js:144

Any tips appreciated!

2 Likes

I’ve fixed this theme component.

6 Likes

With iPad and iPhone it can’t go forward from here:

Same issue than earlier, if I’m remembering right.

That’s a different issue, and has probably been there for a long time. I’ll take a look at it soon.

4 Likes

Same here, but in the browser. Here’s some errors from the console. Thank you for bringing this back to life Angus.

2 Likes

It looks like a safari issue. I’ll take a look at that shortly.

1 Like

Yeah, it’s a safari issue and it’s been there for a while (in fact this probably never worked on safari).

The component works in Chrome and Firefox, as it did before. I’ve further updated the component to use the native javascript MediaRecorder API (instead of a 5 year old npm library), however someone with some more time on their hands will need to get the native MediaRecorder API and audio element to play nicely with Safari. Happy to help with a PR for that specific task.

@peter.be @denvergeeks Perhaps you want to focus your efforts just on that. I’d be happy to make you maintainers of the repository.

6 Likes

Thank you, Angus, I won’t have the time to dive deeper into this as of now.

For what it’s worth - I’ve tried the MediaRecorder API initially when developing the plugin, but quickly came to find that there’s no way to support all browsers for recording and playback (there’s always a combination that doesn’t work) because of codec/format issues. I spent quite some time with this, but as far as I’m aware, there’s no way to support all browsers when using the MediaRecorder API. That’s why I used a mp3 encoder.

3 Likes

Thanks @peter.be and @angus! I have tested and found that this TC does now work, except:

  1. not in Safari on MacOS (although it does work in Chrome on MacOS)

  2. not in Safari or Chrome or Firefox or Brave on iOS

Here’s one possible solution…

3 Likes

@denvergeeks have you tested playback in the respective other browser(s)?

When I tested, recording worked, but especially when switching from Safari to Chrome and vice versa there were always playback issues. Specifically, if I remember correctly, files recorded through Chrome would not play back in Safari, no matter what codec I used.

But you said you tested this and it worked (with all combinations for recording and playback between different browsers)?

Yes @peter.be – I tested just now and found that…

Recordings made in Chrome on Windows:

  • do play in Chrome on MacOS
  • do play in FireFox on MacOS

  • do not play in Safari on MacOS
  • do not play in Chrome on iOS
  • do not play in Safari on iOS
  • do not play in FireFox on iOS
  • do not play in Brave on iOS
1 Like

Right…

That’s why I chose to use a mp3 encoder. Only using the MediaRecorder API in that way won’t support all browsers.

1 Like

So… are we back in the situation where a plugin works, but a component not :wink:

2 Likes

The component works in the same way it always has. Considering the clear interest in this I’ll try to find some time to address the safari issues later this week.

4 Likes

Ok, this component now

  • supports all browsers (including Safari, Firefox and Chrome iOS)
  • uses no external dependencies
  • works with the latest Discourse
9 Likes

As our british friends say: splendid indeed.

Works nicely. Thanks.

2 Likes

Happy Very Funny GIF by Disney Zootopia

2 Likes