Play audio from video elements, fixes #242
parent
5c4eeb121a
commit
7a3bd327f2
|
|
@ -340,6 +340,7 @@ const Peer = (props) =>
|
|||
videoMultiLayer={webcamConsumer && webcamConsumer.type !== 'simple'}
|
||||
videoTrack={webcamConsumer && webcamConsumer.track}
|
||||
videoVisible={videoVisible}
|
||||
audioTrack={micConsumer && micConsumer.track}
|
||||
audioCodec={micConsumer && micConsumer.codec}
|
||||
videoCodec={webcamConsumer && webcamConsumer.codec}
|
||||
audioScore={micConsumer ? micConsumer.score : null}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { micConsumerSelector } from '../Selectors';
|
||||
import { passiveMicConsumerSelector } from '../Selectors';
|
||||
import PropTypes from 'prop-types';
|
||||
import PeerAudio from './PeerAudio';
|
||||
|
||||
|
|
@ -37,7 +37,7 @@ AudioPeers.propTypes =
|
|||
|
||||
const mapStateToProps = (state) =>
|
||||
({
|
||||
micConsumers : micConsumerSelector(state),
|
||||
micConsumers : passiveMicConsumerSelector(state),
|
||||
audioOutputDevice : state.settings.selectedAudioOutputDevice
|
||||
});
|
||||
|
||||
|
|
@ -50,7 +50,9 @@ const AudioPeersContainer = connect(
|
|||
{
|
||||
return (
|
||||
prev.consumers === next.consumers &&
|
||||
prev.settings.selectedAudioOutputDevice === next.settings.selectedAudioOutputDevice
|
||||
prev.room.spotlights === next.room.spotlights &&
|
||||
prev.settings.selectedAudioOutputDevice ===
|
||||
next.settings.selectedAudioOutputDevice
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,6 +67,15 @@ export const screenConsumerSelector = createSelector(
|
|||
(consumers) => Object.values(consumers).filter((consumer) => consumer.source === 'screen')
|
||||
);
|
||||
|
||||
export const passiveMicConsumerSelector = createSelector(
|
||||
spotlightsSelector,
|
||||
consumersSelect,
|
||||
(spotlights, consumers) =>
|
||||
Object.values(consumers).filter(
|
||||
(consumer) => consumer.source === 'mic' && !spotlights.includes(consumer.peerId)
|
||||
)
|
||||
);
|
||||
|
||||
export const spotlightsLengthSelector = createSelector(
|
||||
spotlightsSelector,
|
||||
(spotlights) => spotlights.length
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
|
|||
import classnames from 'classnames';
|
||||
import { withStyles } from '@material-ui/core/styles';
|
||||
import EditableInput from '../Controls/EditableInput';
|
||||
import Logger from '../../Logger';
|
||||
import { green, yellow, orange, red } from '@material-ui/core/colors';
|
||||
import SignalCellularOffIcon from '@material-ui/icons/SignalCellularOff';
|
||||
import SignalCellular0BarIcon from '@material-ui/icons/SignalCellular0Bar';
|
||||
|
|
@ -11,6 +12,8 @@ import SignalCellular2BarIcon from '@material-ui/icons/SignalCellular2Bar';
|
|||
import SignalCellular3BarIcon from '@material-ui/icons/SignalCellular3Bar';
|
||||
import SignalCellularAltIcon from '@material-ui/icons/SignalCellularAlt';
|
||||
|
||||
const logger = new Logger('VideoView');
|
||||
|
||||
const styles = (theme) =>
|
||||
({
|
||||
root :
|
||||
|
|
@ -134,6 +137,10 @@ class VideoView extends React.PureComponent
|
|||
videoHeight : null
|
||||
};
|
||||
|
||||
// Latest received audio track
|
||||
// @type {MediaStreamTrack}
|
||||
this._audioTrack = null;
|
||||
|
||||
// Latest received video track.
|
||||
// @type {MediaStreamTrack}
|
||||
this._videoTrack = null;
|
||||
|
|
@ -292,7 +299,7 @@ class VideoView extends React.PureComponent
|
|||
</div>
|
||||
|
||||
<video
|
||||
ref='video'
|
||||
ref='videoElement'
|
||||
className={classnames(classes.video, {
|
||||
hidden : !videoVisible,
|
||||
'isMe' : isMe && !isScreen,
|
||||
|
|
@ -300,6 +307,16 @@ class VideoView extends React.PureComponent
|
|||
})}
|
||||
autoPlay
|
||||
playsInline
|
||||
muted
|
||||
controls={false}
|
||||
/>
|
||||
|
||||
<audio
|
||||
ref='audioElement'
|
||||
autoPlay
|
||||
playsInline
|
||||
muted={isMe}
|
||||
controls={false}
|
||||
/>
|
||||
|
||||
{children}
|
||||
|
|
@ -309,52 +326,84 @@ class VideoView extends React.PureComponent
|
|||
|
||||
componentDidMount()
|
||||
{
|
||||
const { videoTrack } = this.props;
|
||||
const { videoTrack, audioTrack } = this.props;
|
||||
|
||||
this._setTracks(videoTrack);
|
||||
this._setTracks(videoTrack, audioTrack);
|
||||
}
|
||||
|
||||
componentWillUnmount()
|
||||
{
|
||||
clearInterval(this._videoResolutionTimer);
|
||||
|
||||
const { videoElement } = this.refs;
|
||||
|
||||
if (videoElement)
|
||||
{
|
||||
videoElement.oncanplay = null;
|
||||
videoElement.onplay = null;
|
||||
videoElement.onpause = null;
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
UNSAFE_componentWillReceiveProps(nextProps)
|
||||
componentWillUpdate()
|
||||
{
|
||||
const { videoTrack } = nextProps;
|
||||
|
||||
this._setTracks(videoTrack);
|
||||
const { videoTrack, audioTrack } = this.props;
|
||||
|
||||
this._setTracks(videoTrack, audioTrack);
|
||||
}
|
||||
|
||||
_setTracks(videoTrack)
|
||||
_setTracks(videoTrack, audioTrack)
|
||||
{
|
||||
if (this._videoTrack === videoTrack)
|
||||
if (this._videoTrack === videoTrack && this._audioTrack === audioTrack)
|
||||
return;
|
||||
|
||||
this._videoTrack = videoTrack;
|
||||
this._audioTrack = audioTrack;
|
||||
|
||||
clearInterval(this._videoResolutionTimer);
|
||||
this._hideVideoResolution();
|
||||
|
||||
const { video } = this.refs;
|
||||
const { videoElement, audioElement } = this.refs;
|
||||
|
||||
if (videoTrack)
|
||||
{
|
||||
const stream = new MediaStream();
|
||||
|
||||
if (videoTrack)
|
||||
stream.addTrack(videoTrack);
|
||||
|
||||
video.srcObject = stream;
|
||||
videoElement.srcObject = stream;
|
||||
|
||||
videoElement.oncanplay = () => this.setState({ videoCanPlay: true });
|
||||
|
||||
videoElement.onplay = () =>
|
||||
{
|
||||
audioElement.play()
|
||||
.catch((error) => logger.warn('audioElement.play() [error:"%o]', error));
|
||||
};
|
||||
|
||||
videoElement.play()
|
||||
.catch((error) => logger.warn('videoElement.play() [error:"%o]', error));
|
||||
|
||||
if (videoTrack)
|
||||
this._showVideoResolution();
|
||||
}
|
||||
else
|
||||
{
|
||||
video.srcObject = null;
|
||||
videoElement.srcObject = null;
|
||||
}
|
||||
|
||||
if (audioTrack)
|
||||
{
|
||||
const stream = new MediaStream();
|
||||
|
||||
stream.addTrack(audioTrack);
|
||||
audioElement.srcObject = stream;
|
||||
|
||||
audioElement.play()
|
||||
.catch((error) => logger.warn('audioElement.play() [error:"%o]', error));
|
||||
}
|
||||
else
|
||||
{
|
||||
audioElement.srcObject = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -363,16 +412,19 @@ class VideoView extends React.PureComponent
|
|||
this._videoResolutionTimer = setInterval(() =>
|
||||
{
|
||||
const { videoWidth, videoHeight } = this.state;
|
||||
const { video } = this.refs;
|
||||
const { videoElement } = this.refs;
|
||||
|
||||
// Don't re-render if nothing changed.
|
||||
if (video.videoWidth === videoWidth && video.videoHeight === videoHeight)
|
||||
if (
|
||||
videoElement.videoWidth === videoWidth &&
|
||||
videoElement.videoHeight === videoHeight
|
||||
)
|
||||
return;
|
||||
|
||||
this.setState(
|
||||
{
|
||||
videoWidth : video.videoWidth,
|
||||
videoHeight : video.videoHeight
|
||||
videoWidth : videoElement.videoWidth,
|
||||
videoHeight : videoElement.videoHeight
|
||||
});
|
||||
}, 1000);
|
||||
}
|
||||
|
|
@ -392,6 +444,7 @@ VideoView.propTypes =
|
|||
videoContain : PropTypes.bool,
|
||||
advancedMode : PropTypes.bool,
|
||||
videoTrack : PropTypes.any,
|
||||
audioTrack : PropTypes.any,
|
||||
videoVisible : PropTypes.bool.isRequired,
|
||||
consumerSpatialLayers : PropTypes.number,
|
||||
consumerTemporalLayers : PropTypes.number,
|
||||
|
|
|
|||
Loading…
Reference in New Issue