@@ -28,6 +28,9 @@ import {VoiceRecordingStore} from "../../../stores/VoiceRecordingStore";
28
28
import { UPDATE_EVENT } from "../../../stores/AsyncStore" ;
29
29
import RecordingPlayback from "../voice_messages/RecordingPlayback" ;
30
30
import { MsgType } from "matrix-js-sdk/src/@types/event" ;
31
+ import Modal from "../../../Modal" ;
32
+ import ErrorDialog from "../dialogs/ErrorDialog" ;
33
+ import CallMediaHandler from "../../../CallMediaHandler" ;
31
34
32
35
interface IProps {
33
36
room : Room ;
@@ -113,16 +116,59 @@ export default class VoiceRecordComposerTile extends React.PureComponent<IProps,
113
116
await this . state . recorder . stop ( ) ;
114
117
return ;
115
118
}
116
- const recorder = VoiceRecordingStore . instance . startRecording ( ) ;
117
- await recorder . start ( ) ;
118
119
119
- // We don't need to remove the listener: the recorder will clean that up for us.
120
- recorder . on ( UPDATE_EVENT , ( ev : RecordingState ) => {
121
- if ( ev === RecordingState . EndingSoon ) return ; // ignore this state: it has no UI purpose here
122
- this . setState ( { recordingPhase : ev } ) ;
123
- } ) ;
120
+ // The "microphone access error" dialogs are used a lot, so let's functionify them
121
+ const accessError = ( ) => {
122
+ Modal . createTrackedDialog ( 'Microphone Access Error' , '' , ErrorDialog , {
123
+ title : _t ( "Unable to access your microphone" ) ,
124
+ description : < >
125
+ < p > { _t (
126
+ "We were unable to access your microphone. Please check your browser settings and try again." ,
127
+ ) } </ p >
128
+ </ > ,
129
+ } ) ;
130
+ } ;
131
+
132
+ // Do a sanity test to ensure we're about to grab a valid microphone reference. Things might
133
+ // change between this and recording, but at least we will have tried.
134
+ try {
135
+ const devices = await CallMediaHandler . getDevices ( ) ;
136
+ if ( ! devices ?. [ 'audioinput' ] ?. length ) {
137
+ Modal . createTrackedDialog ( 'No Microphone Error' , '' , ErrorDialog , {
138
+ title : _t ( "No microphone found" ) ,
139
+ description : < >
140
+ < p > { _t (
141
+ "We didn't find a microphone on your device. Please check your settings and try again." ,
142
+ ) } </ p >
143
+ </ > ,
144
+ } ) ;
145
+ return ;
146
+ }
147
+ // else we probably have a device that is good enough
148
+ } catch ( e ) {
149
+ console . error ( "Error getting devices: " , e ) ;
150
+ accessError ( ) ;
151
+ return ;
152
+ }
153
+
154
+ try {
155
+ const recorder = VoiceRecordingStore . instance . startRecording ( ) ;
156
+ await recorder . start ( ) ;
157
+
158
+ // We don't need to remove the listener: the recorder will clean that up for us.
159
+ recorder . on ( UPDATE_EVENT , ( ev : RecordingState ) => {
160
+ if ( ev === RecordingState . EndingSoon ) return ; // ignore this state: it has no UI purpose here
161
+ this . setState ( { recordingPhase : ev } ) ;
162
+ } ) ;
163
+
164
+ this . setState ( { recorder, recordingPhase : RecordingState . Started } ) ;
165
+ } catch ( e ) {
166
+ console . error ( "Error starting recording: " , e ) ;
167
+ accessError ( ) ;
124
168
125
- this . setState ( { recorder, recordingPhase : RecordingState . Started } ) ;
169
+ // noinspection ES6MissingAwait - if this goes wrong we don't want it to affect the call stack
170
+ VoiceRecordingStore . instance . disposeRecording ( ) ;
171
+ }
126
172
} ;
127
173
128
174
private renderWaveformArea ( ) : ReactNode {
0 commit comments