Obrigado, acho que entendi. A gravação de áudio direta não é possível.
O componente atualmente não funciona devido a um problema de CSP.
Adicionar https://cdn.jsdelivr.net/ à configuração do site content security policy script src não resolve o problema: o botão de gravação funcionará, mas a criação do arquivo acionará outro erro de JS:
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/".
O Gravador de Voz está (na maioria) funcionando no meu site. Veja as capturas de tela abaixo do meu processo…
Logo após a gravação, nada é clicável (mas posso ver que está sublinhado em vermelho que o arquivo foi de fato gravado e inserido na postagem)…
Então, clicando no botão Voltar do navegador (porque o botão Upload não responde), volto para o composer onde posso ver que o arquivo foi inserido e funciona para tocar na janela de visualização…
Em seguida, após clicar em + Criar Tópico, a postagem aparece corretamente…
No entanto, recebi este erro no console imediatamente após clicar no botão Parar Gravação…
Além disso, após clicar no botão Upload, recebo um segundo erro…
E finalmente, após clicar no botão Cancelar, recebo um terceiro erro…
Apesar desses erros, o clipe de áudio está aparecendo e tocando corretamente na postagem.
Tentando entender os erros que estou recebendo ao tentar usar este Componente de Tema.
Além do modal não fechar, as coisas parecem funcionar.
(E se eu atualizar a página para escapar do modal, volto para o composer onde o arquivo foi gravado e carregado corretamente, e está reproduzível, mas não na pré-visualização, apenas depois de salvar a postagem.)
Aqui está minha melhor pista até agora…

Esta é uma possível solução…
1) Quando o modal abre (depois que clico no botão do microfone no composer)…
2) Quando clico no botão de reprodução (no modal) para revisar a gravação antes do upload…
3) Quando clico no botão de upload (no modal)…
Aqui está o log completo copiado do 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
$._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
Qualquer dica é bem-vinda!
Essa é uma questão diferente e provavelmente está lá há muito tempo. Vou dar uma olhada nisso em breve.
O mesmo aqui, mas no navegador. Aqui estão alguns erros do console. Obrigado por trazer isso de volta à vida, Angus.
Parece um problema do Safari. Vou dar uma olhada nisso em breve.
Sim, é um problema do Safari e já existe há algum tempo (na verdade, isso provavelmente nunca funcionou no Safari).
O componente funciona no Chrome e Firefox, como funcionava antes. Atualizei ainda mais o componente para usar a API nativa MediaRecorder do JavaScript (em vez de uma biblioteca npm de 5 anos), no entanto, alguém com mais tempo precisará fazer com que a API nativa MediaRecorder e o elemento audio funcionem bem com o Safari. Terei prazer em ajudar com um PR para essa tarefa específica.
@peter.be @denvergeeks Talvez vocês queiram focar seus esforços apenas nisso. Terei prazer em torná-los mantenedores do repositório.
Obrigado, Angus, não terei tempo de me aprofundar nisso por enquanto.
Para que valha a pena - tentei a API MediaRecorder inicialmente ao desenvolver o plugin, mas rapidamente descobri que não há como suportar todos os navegadores para gravação e reprodução (sempre há uma combinação que não funciona) devido a problemas de codec/formato. Passei bastante tempo com isso, mas, até onde sei, não há como suportar todos os navegadores ao usar a API MediaRecorder. É por isso que usei um codificador mp3.
Obrigado @peter.be e @angus! Testei e descobri que este TC agora funciona, exceto:\n\n1) não no Safari no MacOS (embora funcione no Chrome no MacOS)\n\n2) não no Safari ou Chrome ou Firefox ou Brave no iOS\n\nAqui está uma possível solução…\n\nhttps://stackoverflow.com/questions/76532656/media-recorder-api-browser-compatibility
@denvergeeks você testou a reprodução nos respectivos outros navegadores?
Quando testei, a gravação funcionou, mas especialmente ao alternar de Safari para Chrome e vice-versa, sempre houve problemas de reprodução. Especificamente, se bem me lembro, arquivos gravados pelo Chrome não reproduziam no Safari, não importava o codec que eu usasse.
Mas você disse que testou isso e funcionou (com todas as combinações de gravação e reprodução entre diferentes navegadores)?
Sim @peter.be – Testei agora e descobri que…
Gravações feitas no Chrome no Windows:
- reproduzem no Chrome no MacOS
- reproduzem no FireFox no MacOS
- não reproduzem no Safari no MacOS
- não reproduzem no Chrome no iOS
- não reproduzem no Safari no iOS
- não reproduzem no FireFox no iOS
- não reproduzem no Brave no iOS
Certo…
É por isso que escolhi usar um codificador mp3. Usar apenas a API MediaRecorder dessa forma não suportará todos os navegadores.
Então… estamos de volta à situação em que um plugin funciona, mas um componente não ![]()
O componente funciona da mesma forma que sempre funcionou. Considerando o claro interesse nisso, tentarei encontrar tempo para resolver os problemas do Safari ainda esta semana.
Ok, este componente agora
- suporta todos os navegadores (incluindo Safari, Firefox e Chrome iOS)
- não usa dependências externas
- funciona com o Discourse mais recente
Como dizem nossos amigos britânicos: esplêndido, de fato.
Funciona bem. Obrigado.











