@@ -21,6 +21,7 @@ const useSpeechToTextExternal = (
21
21
const [ isListening , setIsListening ] = useState ( false ) ;
22
22
const [ audioChunks , setAudioChunks ] = useState < Blob [ ] > ( [ ] ) ;
23
23
const [ isRequestBeingMade , setIsRequestBeingMade ] = useState ( false ) ;
24
+ const [ audioMimeType , setAudioMimeType ] = useState < string > ( 'audio/webm' ) ;
24
25
25
26
const [ minDecibels ] = useRecoilState ( store . decibelValue ) ;
26
27
const [ autoSendText ] = useRecoilState ( store . autoSendText ) ;
@@ -48,6 +49,44 @@ const useSpeechToTextExternal = (
48
49
} ,
49
50
} ) ;
50
51
52
+ const getBestSupportedMimeType = ( ) => {
53
+ const types = [
54
+ 'audio/webm' ,
55
+ 'audio/webm;codecs=opus' ,
56
+ 'audio/mp4' ,
57
+ 'audio/ogg;codecs=opus' ,
58
+ 'audio/ogg' ,
59
+ 'audio/wav' ,
60
+ ] ;
61
+
62
+ for ( const type of types ) {
63
+ if ( MediaRecorder . isTypeSupported ( type ) ) {
64
+ return type ;
65
+ }
66
+ }
67
+
68
+ const ua = navigator . userAgent . toLowerCase ( ) ;
69
+ if ( ua . indexOf ( 'safari' ) !== - 1 && ua . indexOf ( 'chrome' ) === - 1 ) {
70
+ return 'audio/mp4' ;
71
+ } else if ( ua . indexOf ( 'firefox' ) !== - 1 ) {
72
+ return 'audio/ogg' ;
73
+ } else {
74
+ return 'audio/webm' ;
75
+ }
76
+ } ;
77
+
78
+ const getFileExtension = ( mimeType : string ) => {
79
+ if ( mimeType . includes ( 'mp4' ) ) {
80
+ return 'm4a' ;
81
+ } else if ( mimeType . includes ( 'ogg' ) ) {
82
+ return 'ogg' ;
83
+ } else if ( mimeType . includes ( 'wav' ) ) {
84
+ return 'wav' ;
85
+ } else {
86
+ return 'webm' ;
87
+ }
88
+ } ;
89
+
51
90
const cleanup = ( ) => {
52
91
if ( mediaRecorderRef . current ) {
53
92
mediaRecorderRef . current . removeEventListener ( 'dataavailable' , ( event : BlobEvent ) => {
@@ -73,12 +112,13 @@ const useSpeechToTextExternal = (
73
112
74
113
const handleStop = ( ) => {
75
114
if ( audioChunks . length > 0 ) {
76
- const audioBlob = new Blob ( audioChunks , { type : 'audio/wav' } ) ;
115
+ const audioBlob = new Blob ( audioChunks , { type : audioMimeType } ) ;
116
+ const fileExtension = getFileExtension ( audioMimeType ) ;
77
117
78
118
setAudioChunks ( [ ] ) ;
79
119
80
120
const formData = new FormData ( ) ;
81
- formData . append ( 'audio' , audioBlob , ' audio.wav' ) ;
121
+ formData . append ( 'audio' , audioBlob , ` audio.${ fileExtension } ` ) ;
82
122
setIsRequestBeingMade ( true ) ;
83
123
cleanup ( ) ;
84
124
processAudio ( formData ) ;
@@ -133,7 +173,12 @@ const useSpeechToTextExternal = (
133
173
if ( audioStream . current ) {
134
174
try {
135
175
setAudioChunks ( [ ] ) ;
136
- mediaRecorderRef . current = new MediaRecorder ( audioStream . current ) ;
176
+ const bestMimeType = getBestSupportedMimeType ( ) ;
177
+ setAudioMimeType ( bestMimeType ) ;
178
+
179
+ mediaRecorderRef . current = new MediaRecorder ( audioStream . current , {
180
+ mimeType : bestMimeType ,
181
+ } ) ;
137
182
mediaRecorderRef . current . addEventListener ( 'dataavailable' , ( event : BlobEvent ) => {
138
183
audioChunks . push ( event . data ) ;
139
184
} ) ;
@@ -221,7 +266,7 @@ const useSpeechToTextExternal = (
221
266
return ( ) => {
222
267
window . removeEventListener ( 'keydown' , handleKeyDown ) ;
223
268
} ;
224
- // eslint-disable-next-line react-hooks/exhaustive-deps
269
+
225
270
} , [ isListening ] ) ;
226
271
227
272
return {
0 commit comments