hark running now on producers and consumers directly instead on PeerView component, now we can send audiolevel events into more places ...

master
Stefan Otto 2018-07-17 12:56:58 +02:00
parent 977ffd9d24
commit 3ab603bbe7
7 changed files with 123 additions and 59 deletions

View File

@ -1,6 +1,7 @@
import protooClient from 'protoo-client'; import protooClient from 'protoo-client';
import * as mediasoupClient from 'mediasoup-client'; import * as mediasoupClient from 'mediasoup-client';
import Logger from './Logger'; import Logger from './Logger';
import hark from 'hark';
import ScreenShare from './ScreenShare'; import ScreenShare from './ScreenShare';
import { getProtooUrl } from './urlFactory'; import { getProtooUrl } from './urlFactory';
import * as cookiesManager from './cookiesManager'; import * as cookiesManager from './cookiesManager';
@ -1380,7 +1381,33 @@ export default class RoomClient
}) })
.then(() => .then(() =>
{ {
const stream = new MediaStream;
logger.debug('_setMicProducer() succeeded'); logger.debug('_setMicProducer() succeeded');
stream.addTrack(producer.track);
if (!stream.getAudioTracks()[0])
throw new Error('_setMicProducer(): given stream has no audio track');
producer.hark = hark(stream, { play: false });
// eslint-disable-next-line no-unused-vars
producer.hark.on('volume_change', (dBs, threshold) =>
{
// The exact formula to convert from dBs (-100..0) to linear (0..1) is:
// Math.pow(10, dBs / 20)
// However it does not produce a visually useful output, so let exagerate
// it a bit. Also, let convert it from 0..1 to 0..10 and avoid value 1 to
// minimize component renderings.
let volume = Math.round(Math.pow(10, dBs / 85) * 10);
if (volume === 1)
volume = 0;
if (volume !== producer.volume)
{
producer.volume = volume;
this._dispatch(stateActions.setProducerVolume(producer.id, volume));
}
});
}) })
.catch((error) => .catch((error) =>
{ {
@ -1823,7 +1850,8 @@ export default class RoomClient
track : null, track : null,
codec : codec ? codec.name : null codec : codec ? codec.name : null
}, },
consumer.peer.name)); consumer.peer.name)
);
consumer.on('close', (originator) => consumer.on('close', (originator) =>
{ {
@ -1835,6 +1863,43 @@ export default class RoomClient
consumer.id, consumer.peer.name)); consumer.id, consumer.peer.name));
}); });
consumer.on('handled', (originator) =>
{
logger.debug(
'consumer "handled" event [id:%s, originator:%s, consumer:%o]',
consumer.id, originator, consumer);
if (consumer.kind === 'audio')
{
const stream = new MediaStream;
stream.addTrack(consumer.track);
if (!stream.getAudioTracks()[0])
throw new Error('consumer.on("handled" | given stream has no audio track');
consumer.hark = hark(stream, { play: false });
// eslint-disable-next-line no-unused-vars
consumer.hark.on('volume_change', (dBs, threshold) =>
{
// The exact formula to convert from dBs (-100..0) to linear (0..1) is:
// Math.pow(10, dBs / 20)
// However it does not produce a visually useful output, so let exagerate
// it a bit. Also, let convert it from 0..1 to 0..10 and avoid value 1 to
// minimize component renderings.
let volume = Math.round(Math.pow(10, dBs / 85) * 10);
if (volume === 1)
volume = 0;
if (volume !== consumer.volume)
{
consumer.volume = volume;
this._dispatch(stateActions.setConsumerVolume(consumer.id, volume));
}
});
}
});
consumer.on('pause', (originator) => consumer.on('pause', (originator) =>
{ {
logger.debug( logger.debug(

View File

@ -140,6 +140,7 @@ class Me extends React.Component
advancedMode={advancedMode} advancedMode={advancedMode}
peer={me} peer={me}
audioTrack={micProducer ? micProducer.track : null} audioTrack={micProducer ? micProducer.track : null}
volume={micProducer ? micProducer.volume : null}
videoTrack={webcamProducer ? webcamProducer.track : null} videoTrack={webcamProducer ? webcamProducer.track : null}
videoVisible={videoVisible} videoVisible={videoVisible}
audioCodec={micProducer ? micProducer.codec : null} audioCodec={micProducer ? micProducer.codec : null}

View File

@ -136,6 +136,7 @@ class Peer extends Component
advancedMode={advancedMode} advancedMode={advancedMode}
peer={peer} peer={peer}
audioTrack={micConsumer ? micConsumer.track : null} audioTrack={micConsumer ? micConsumer.track : null}
volume={micConsumer ? micConsumer.volume : null}
videoTrack={webcamConsumer ? webcamConsumer.track : null} videoTrack={webcamConsumer ? webcamConsumer.track : null}
videoVisible={videoVisible} videoVisible={videoVisible}
videoProfile={videoProfile} videoProfile={videoProfile}

View File

@ -2,7 +2,6 @@ import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import classnames from 'classnames'; import classnames from 'classnames';
import Spinner from 'react-spinner'; import Spinner from 'react-spinner';
import hark from 'hark';
import * as appPropTypes from './appPropTypes'; import * as appPropTypes from './appPropTypes';
import EditableInput from './EditableInput'; import EditableInput from './EditableInput';
@ -27,10 +26,6 @@ export default class PeerView extends React.Component
// @type {MediaStreamTrack} // @type {MediaStreamTrack}
this._videoTrack = null; this._videoTrack = null;
// Hark instance.
// @type {Object}
this._hark = null;
// Periodic timer for showing video resolution. // Periodic timer for showing video resolution.
this._videoResolutionTimer = null; this._videoResolutionTimer = null;
} }
@ -40,6 +35,7 @@ export default class PeerView extends React.Component
const { const {
isMe, isMe,
peer, peer,
volume,
advancedMode, advancedMode,
videoVisible, videoVisible,
videoProfile, videoProfile,
@ -49,7 +45,6 @@ export default class PeerView extends React.Component
} = this.props; } = this.props;
const { const {
volume,
videoWidth, videoWidth,
videoHeight videoHeight
} = this.state; } = this.state;
@ -149,9 +144,6 @@ export default class PeerView extends React.Component
componentWillUnmount() componentWillUnmount()
{ {
if (this._hark)
this._hark.stop();
clearInterval(this._videoResolutionTimer); clearInterval(this._videoResolutionTimer);
} }
@ -160,6 +152,7 @@ export default class PeerView extends React.Component
const { audioTrack, videoTrack } = nextProps; const { audioTrack, videoTrack } = nextProps;
this._setTracks(audioTrack, videoTrack); this._setTracks(audioTrack, videoTrack);
} }
_setTracks(audioTrack, videoTrack) _setTracks(audioTrack, videoTrack)
@ -170,9 +163,6 @@ export default class PeerView extends React.Component
this._audioTrack = audioTrack; this._audioTrack = audioTrack;
this._videoTrack = videoTrack; this._videoTrack = videoTrack;
if (this._hark)
this._hark.stop();
clearInterval(this._videoResolutionTimer); clearInterval(this._videoResolutionTimer);
this._hideVideoResolution(); this._hideVideoResolution();
@ -190,9 +180,6 @@ export default class PeerView extends React.Component
video.srcObject = stream; video.srcObject = stream;
if (audioTrack)
this._runHark(stream);
if (videoTrack) if (videoTrack)
this._showVideoResolution(); this._showVideoResolution();
} }
@ -202,31 +189,6 @@ export default class PeerView extends React.Component
} }
} }
_runHark(stream)
{
if (!stream.getAudioTracks()[0])
throw new Error('_runHark() | given stream has no audio track');
this._hark = hark(stream, { play: false });
// eslint-disable-next-line no-unused-vars
this._hark.on('volume_change', (dBs, threshold) =>
{
// The exact formula to convert from dBs (-100..0) to linear (0..1) is:
// Math.pow(10, dBs / 20)
// However it does not produce a visually useful output, so let exagerate
// it a bit. Also, let convert it from 0..1 to 0..10 and avoid value 1 to
// minimize component renderings.
let volume = Math.round(Math.pow(10, dBs / 85) * 10);
if (volume === 1)
volume = 0;
if (volume !== this.state.volume)
this.setState({ volume: volume });
});
}
_showVideoResolution() _showVideoResolution()
{ {
this._videoResolutionTimer = setInterval(() => this._videoResolutionTimer = setInterval(() =>
@ -259,6 +221,7 @@ PeerView.propTypes =
[ appPropTypes.Me, appPropTypes.Peer ]).isRequired, [ appPropTypes.Me, appPropTypes.Peer ]).isRequired,
advancedMode : PropTypes.bool, advancedMode : PropTypes.bool,
audioTrack : PropTypes.any, audioTrack : PropTypes.any,
volume : PropTypes.number,
videoTrack : PropTypes.any, videoTrack : PropTypes.any,
videoVisible : PropTypes.bool.isRequired, videoVisible : PropTypes.bool.isRequired,
videoProfile : PropTypes.string, videoProfile : PropTypes.string,

View File

@ -35,6 +35,15 @@ const consumers = (state = initialState, action) =>
return { ...state, [consumerId]: newConsumer }; return { ...state, [consumerId]: newConsumer };
} }
case 'SET_CONSUMER_VOLUME':
{
const { consumerId, volume } = action.payload;
const consumer = state[consumerId];
const newConsumer = { ...consumer, volume };
return { ...state, [consumerId]: newConsumer };
}
case 'SET_CONSUMER_RESUMED': case 'SET_CONSUMER_RESUMED':
{ {
const { consumerId, originator } = action.payload; const { consumerId, originator } = action.payload;

View File

@ -35,6 +35,15 @@ const producers = (state = initialState, action) =>
return { ...state, [producerId]: newProducer }; return { ...state, [producerId]: newProducer };
} }
case 'SET_PRODUCER_VOLUME':
{
const { producerId, volume } = action.payload;
const producer = state[producerId];
const newProducer = { ...producer, volume };
return { ...state, [producerId]: newProducer };
}
case 'SET_PRODUCER_RESUMED': case 'SET_PRODUCER_RESUMED':
{ {
const { producerId, originator } = action.payload; const { producerId, originator } = action.payload;

View File

@ -331,6 +331,22 @@ export const setConsumerTrack = (consumerId, track) =>
}; };
}; };
export const setConsumerVolume = (consumerId, volume) =>
{
return {
type : 'SET_CONSUMER_VOLUME',
payload : { consumerId, volume }
};
};
export const setProducerVolume = (producerId, volume) =>
{
return {
type : 'SET_PRODUCER_VOLUME',
payload : { producerId, volume }
};
};
export const addNotification = (notification) => export const addNotification = (notification) =>
{ {
return { return {