Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 98472b4

Browse files
authored
Merge pull request #6433 from matrix-org/travis/voice-messages/errors
Render error state for audio components
2 parents b9b37f5 + 3d72b9e commit 98472b4

File tree

4 files changed

+65
-46
lines changed

4 files changed

+65
-46
lines changed

src/components/views/audio_messages/AudioPlayer.tsx

Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ interface IProps {
3636

3737
interface IState {
3838
playbackPhase: PlaybackState;
39+
error?: boolean;
3940
}
4041

4142
@replaceableComponent("views.audio_messages.AudioPlayer")
@@ -55,8 +56,10 @@ export default class AudioPlayer extends React.PureComponent<IProps, IState> {
5556

5657
// Don't wait for the promise to complete - it will emit a progress update when it
5758
// is done, and it's not meant to take long anyhow.
58-
// noinspection JSIgnoredPromiseFromCall
59-
this.props.playback.prepare();
59+
this.props.playback.prepare().catch(e => {
60+
console.error("Error processing audio file:", e);
61+
this.setState({ error: true });
62+
});
6063
}
6164

6265
private onPlaybackUpdate = (ev: PlaybackState) => {
@@ -91,34 +94,37 @@ export default class AudioPlayer extends React.PureComponent<IProps, IState> {
9194
public render(): ReactNode {
9295
// tabIndex=0 to ensure that the whole component becomes a tab stop, where we handle keyboard
9396
// events for accessibility
94-
return <div className='mx_MediaBody mx_AudioPlayer_container' tabIndex={0} onKeyDown={this.onKeyDown}>
95-
<div className='mx_AudioPlayer_primaryContainer'>
96-
<PlayPauseButton
97-
playback={this.props.playback}
98-
playbackPhase={this.state.playbackPhase}
99-
tabIndex={-1} // prevent tabbing into the button
100-
ref={this.playPauseRef}
101-
/>
102-
<div className='mx_AudioPlayer_mediaInfo'>
103-
<span className='mx_AudioPlayer_mediaName'>
104-
{ this.props.mediaName || _t("Unnamed audio") }
105-
</span>
106-
<div className='mx_AudioPlayer_byline'>
107-
<DurationClock playback={this.props.playback} />
108-
&nbsp; { /* easiest way to introduce a gap between the components */ }
109-
{ this.renderFileSize() }
97+
return <>
98+
<div className='mx_MediaBody mx_AudioPlayer_container' tabIndex={0} onKeyDown={this.onKeyDown}>
99+
<div className='mx_AudioPlayer_primaryContainer'>
100+
<PlayPauseButton
101+
playback={this.props.playback}
102+
playbackPhase={this.state.playbackPhase}
103+
tabIndex={-1} // prevent tabbing into the button
104+
ref={this.playPauseRef}
105+
/>
106+
<div className='mx_AudioPlayer_mediaInfo'>
107+
<span className='mx_AudioPlayer_mediaName'>
108+
{ this.props.mediaName || _t("Unnamed audio") }
109+
</span>
110+
<div className='mx_AudioPlayer_byline'>
111+
<DurationClock playback={this.props.playback} />
112+
&nbsp; { /* easiest way to introduce a gap between the components */ }
113+
{ this.renderFileSize() }
114+
</div>
110115
</div>
111116
</div>
117+
<div className='mx_AudioPlayer_seek'>
118+
<SeekBar
119+
playback={this.props.playback}
120+
tabIndex={-1} // prevent tabbing into the bar
121+
playbackPhase={this.state.playbackPhase}
122+
ref={this.seekRef}
123+
/>
124+
<PlaybackClock playback={this.props.playback} defaultDisplaySeconds={0} />
125+
</div>
112126
</div>
113-
<div className='mx_AudioPlayer_seek'>
114-
<SeekBar
115-
playback={this.props.playback}
116-
tabIndex={-1} // prevent tabbing into the bar
117-
playbackPhase={this.state.playbackPhase}
118-
ref={this.seekRef}
119-
/>
120-
<PlaybackClock playback={this.props.playback} defaultDisplaySeconds={0} />
121-
</div>
122-
</div>;
127+
{ this.state.error && <div className="text-warning">{ _t("Error downloading audio") }</div> }
128+
</>;
123129
}
124130
}

src/components/views/audio_messages/RecordingPlayback.tsx

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import PlaybackClock from "./PlaybackClock";
2222
import { replaceableComponent } from "../../../utils/replaceableComponent";
2323
import { TileShape } from "../rooms/EventTile";
2424
import PlaybackWaveform from "./PlaybackWaveform";
25+
import { _t } from "../../../languageHandler";
2526

2627
interface IProps {
2728
// Playback instance to render. Cannot change during component lifecycle: create
@@ -33,6 +34,7 @@ interface IProps {
3334

3435
interface IState {
3536
playbackPhase: PlaybackState;
37+
error?: boolean;
3638
}
3739

3840
@replaceableComponent("views.audio_messages.RecordingPlayback")
@@ -49,8 +51,10 @@ export default class RecordingPlayback extends React.PureComponent<IProps, IStat
4951

5052
// Don't wait for the promise to complete - it will emit a progress update when it
5153
// is done, and it's not meant to take long anyhow.
52-
// noinspection JSIgnoredPromiseFromCall
53-
this.props.playback.prepare();
54+
this.props.playback.prepare().catch(e => {
55+
console.error("Error processing audio file:", e);
56+
this.setState({ error: true });
57+
});
5458
}
5559

5660
private get isWaveformable(): boolean {
@@ -65,10 +69,13 @@ export default class RecordingPlayback extends React.PureComponent<IProps, IStat
6569

6670
public render(): ReactNode {
6771
const shapeClass = !this.isWaveformable ? 'mx_VoiceMessagePrimaryContainer_noWaveform' : '';
68-
return <div className={'mx_MediaBody mx_VoiceMessagePrimaryContainer ' + shapeClass}>
69-
<PlayPauseButton playback={this.props.playback} playbackPhase={this.state.playbackPhase} />
70-
<PlaybackClock playback={this.props.playback} />
71-
{ this.isWaveformable && <PlaybackWaveform playback={this.props.playback} /> }
72-
</div>;
72+
return <>
73+
<div className={'mx_MediaBody mx_VoiceMessagePrimaryContainer ' + shapeClass}>
74+
<PlayPauseButton playback={this.props.playback} playbackPhase={this.state.playbackPhase} />
75+
<PlaybackClock playback={this.props.playback} />
76+
{ this.isWaveformable && <PlaybackWaveform playback={this.props.playback} /> }
77+
</div>
78+
{ this.state.error && <div className="text-warning">{ _t("Error downloading audio") }</div> }
79+
</>;
7380
}
7481
}

src/i18n/strings/en_EN.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2601,6 +2601,7 @@
26012601
"Use email to optionally be discoverable by existing contacts.": "Use email to optionally be discoverable by existing contacts.",
26022602
"Sign in with SSO": "Sign in with SSO",
26032603
"Unnamed audio": "Unnamed audio",
2604+
"Error downloading audio": "Error downloading audio",
26042605
"Pause": "Pause",
26052606
"Play": "Play",
26062607
"Couldn't load page": "Couldn't load page",

src/voice/Playback.ts

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -135,18 +135,23 @@ export class Playback extends EventEmitter implements IDestroyable {
135135
// Safari compat: promise API not supported on this function
136136
this.audioBuf = await new Promise((resolve, reject) => {
137137
this.context.decodeAudioData(this.buf, b => resolve(b), async e => {
138-
// This error handler is largely for Safari as well, which doesn't support Opus/Ogg
139-
// very well.
140-
console.error("Error decoding recording: ", e);
141-
console.warn("Trying to re-encode to WAV instead...");
142-
143-
const wav = await decodeOgg(this.buf);
144-
145-
// noinspection ES6MissingAwait - not needed when using callbacks
146-
this.context.decodeAudioData(wav, b => resolve(b), e => {
147-
console.error("Still failed to decode recording: ", e);
138+
try {
139+
// This error handler is largely for Safari as well, which doesn't support Opus/Ogg
140+
// very well.
141+
console.error("Error decoding recording: ", e);
142+
console.warn("Trying to re-encode to WAV instead...");
143+
144+
const wav = await decodeOgg(this.buf);
145+
146+
// noinspection ES6MissingAwait - not needed when using callbacks
147+
this.context.decodeAudioData(wav, b => resolve(b), e => {
148+
console.error("Still failed to decode recording: ", e);
149+
reject(e);
150+
});
151+
} catch (e) {
152+
console.error("Caught decoding error:", e);
148153
reject(e);
149-
});
154+
}
150155
});
151156
});
152157

0 commit comments

Comments
 (0)