The Audio.js setRef callback does not behave like react ref callback in that the former will not have fired before componentDidMount but the later will have. So for audio output preview, trying to set sink id on mount will no-op because it does not have a ref yet to Audio.js, possibly leading to audio output previews playing on the default speaker device. This generally has not been a user visible problem due to coincidence; other re-renders necessary by the parent of audio output preview will have triggered componentDidUpdates on the audio out preview, which would then set the sink id on the Audio.js ref it should have received by then.
121 lines
2.7 KiB
JavaScript
121 lines
2.7 KiB
JavaScript
/* @flow */
|
|
|
|
import React, { Component } from 'react';
|
|
|
|
import { translate } from '../../base/i18n';
|
|
import { Audio } from '../../base/media';
|
|
|
|
const TEST_SOUND_PATH = 'sounds/ring.wav';
|
|
|
|
/**
|
|
* The type of the React {@code Component} props of {@link AudioOutputPreview}.
|
|
*/
|
|
type Props = {
|
|
|
|
/**
|
|
* The device id of the audio output device to use.
|
|
*/
|
|
deviceId: string,
|
|
|
|
/**
|
|
* Invoked to obtain translated strings.
|
|
*/
|
|
t: Function
|
|
};
|
|
|
|
/**
|
|
* React component for playing a test sound through a specified audio device.
|
|
*
|
|
* @extends Component
|
|
*/
|
|
class AudioOutputPreview extends Component<Props> {
|
|
_audioElement: ?Object;
|
|
|
|
/**
|
|
* Initializes a new AudioOutputPreview instance.
|
|
*
|
|
* @param {Object} props - The read-only React Component props with which
|
|
* the new instance is to be initialized.
|
|
*/
|
|
constructor(props: Props) {
|
|
super(props);
|
|
|
|
this._audioElement = null;
|
|
|
|
this._audioElementReady = this._audioElementReady.bind(this);
|
|
this._onClick = this._onClick.bind(this);
|
|
}
|
|
|
|
/**
|
|
* Updates the audio element when the target output device changes and the
|
|
* audio element has re-rendered.
|
|
*
|
|
* @inheritdoc
|
|
* @returns {void}
|
|
*/
|
|
componentDidUpdate() {
|
|
this._setAudioSink();
|
|
}
|
|
|
|
/**
|
|
* Implements React's {@link Component#render()}.
|
|
*
|
|
* @inheritdoc
|
|
* @returns {ReactElement}
|
|
*/
|
|
render() {
|
|
return (
|
|
<div className = 'audio-output-preview'>
|
|
<a onClick = { this._onClick }>
|
|
{ this.props.t('deviceSelection.testAudio') }
|
|
</a>
|
|
<Audio
|
|
setRef = { this._audioElementReady }
|
|
src = { TEST_SOUND_PATH } />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
_audioElementReady: (Object) => void;
|
|
|
|
/**
|
|
* Sets the instance variable for the component's audio element so it can be
|
|
* accessed directly.
|
|
*
|
|
* @param {Object} element - The DOM element for the component's audio.
|
|
* @private
|
|
* @returns {void}
|
|
*/
|
|
_audioElementReady(element: Object) {
|
|
this._audioElement = element;
|
|
|
|
this._setAudioSink();
|
|
}
|
|
|
|
_onClick: () => void;
|
|
|
|
/**
|
|
* Plays a test sound.
|
|
*
|
|
* @private
|
|
* @returns {void}
|
|
*/
|
|
_onClick() {
|
|
this._audioElement
|
|
&& this._audioElement.play();
|
|
}
|
|
|
|
/**
|
|
* Updates the target output device for playing the test sound.
|
|
*
|
|
* @private
|
|
* @returns {void}
|
|
*/
|
|
_setAudioSink() {
|
|
this._audioElement
|
|
&& this._audioElement.setSinkId(this.props.deviceId);
|
|
}
|
|
}
|
|
|
|
export default translate(AudioOutputPreview);
|