Wire up the send button for voice messages

This fixes a bug where we couldn't upload voice messages because the audio buffer was being read, therefore changing the position of the cursor. When this happened, the upload function would claim that the buffer was empty and could not be read.
pull/21833/head
Travis Ralston 2021-04-27 18:59:10 -06:00
parent c1bb0bb0b8
commit 5e646f861c
2 changed files with 21 additions and 5 deletions

View File

@ -198,6 +198,7 @@ interface IState {
export default class MessageComposer extends React.Component<IProps, IState> { export default class MessageComposer extends React.Component<IProps, IState> {
private dispatcherRef: string; private dispatcherRef: string;
private messageComposerInput: SendMessageComposer; private messageComposerInput: SendMessageComposer;
private voiceRecordingButton: VoiceRecordComposerTile;
constructor(props) { constructor(props) {
super(props); super(props);
@ -322,7 +323,15 @@ export default class MessageComposer extends React.Component<IProps, IState> {
}); });
} }
sendMessage = () => { sendMessage = async () => {
if (this.state.haveRecording && this.voiceRecordingButton) {
// There shouldn't be any text message to send when a voice recording is active, so
// just send out the voice recording.
await this.voiceRecordingButton.send();
return;
}
// XXX: Private function access
this.messageComposerInput._sendMessage(); this.messageComposerInput._sendMessage();
} }
@ -387,6 +396,7 @@ export default class MessageComposer extends React.Component<IProps, IState> {
if (SettingsStore.getValue("feature_voice_messages")) { if (SettingsStore.getValue("feature_voice_messages")) {
controls.push(<VoiceRecordComposerTile controls.push(<VoiceRecordComposerTile
key="controls_voice_record" key="controls_voice_record"
ref={c => this.voiceRecordingButton = c}
room={this.props.room} />); room={this.props.room} />);
} }

View File

@ -54,7 +54,7 @@ export class VoiceRecording extends EventEmitter implements IDestroyable {
private recorderStream: MediaStream; private recorderStream: MediaStream;
private recorderFFT: AnalyserNode; private recorderFFT: AnalyserNode;
private recorderWorklet: AudioWorkletNode; private recorderWorklet: AudioWorkletNode;
private buffer = new Uint8Array(0); private buffer = new Uint8Array(0); // use this.audioBuffer to access
private mxc: string; private mxc: string;
private recording = false; private recording = false;
private observable: SimpleObservable<IRecordingUpdate>; private observable: SimpleObservable<IRecordingUpdate>;
@ -166,6 +166,12 @@ export class VoiceRecording extends EventEmitter implements IDestroyable {
}; };
} }
private get audioBuffer(): Uint8Array {
// We need a clone of the buffer to avoid accidentally changing the position
// on the real thing.
return this.buffer.slice(0);
}
public get liveData(): SimpleObservable<IRecordingUpdate> { public get liveData(): SimpleObservable<IRecordingUpdate> {
if (!this.recording) throw new Error("No observable when not recording"); if (!this.recording) throw new Error("No observable when not recording");
return this.observable; return this.observable;
@ -267,13 +273,13 @@ export class VoiceRecording extends EventEmitter implements IDestroyable {
await this.recorder.close(); await this.recorder.close();
this.emit(RecordingState.Ended); this.emit(RecordingState.Ended);
return this.buffer; return this.audioBuffer;
}); });
} }
public getPlayback(): Promise<Playback> { public getPlayback(): Promise<Playback> {
return Singleflight.for(this, "playback").do(async () => { return Singleflight.for(this, "playback").do(async () => {
const playback = new Playback(this.buffer.buffer); // cast to ArrayBuffer proper const playback = new Playback(this.audioBuffer.buffer); // cast to ArrayBuffer proper
await playback.prepare(); await playback.prepare();
return playback; return playback;
}); });
@ -294,7 +300,7 @@ export class VoiceRecording extends EventEmitter implements IDestroyable {
if (this.mxc) return this.mxc; if (this.mxc) return this.mxc;
this.emit(RecordingState.Uploading); this.emit(RecordingState.Uploading);
this.mxc = await this.client.uploadContent(new Blob([this.buffer], { this.mxc = await this.client.uploadContent(new Blob([this.audioBuffer], {
type: this.contentType, type: this.contentType,
}), { }), {
onlyContentUri: false, // to stop the warnings in the console onlyContentUri: false, // to stop the warnings in the console