Play recording init

pull/1102/head
Vincent 5 years ago
parent 2dc5885c88
commit bf749b4e0b

@ -60,13 +60,15 @@ window.isBeforeVersion = (toCheck, baseVersion) => {
}
};
const DEFAULT_PUBLIC_CHAT_URL = appConfig.get('defaultPublicChatServer');
window.CONSTANTS = {
SECS_IN_DAY: 60 * 60 * 24,
MAX_LOGIN_TRIES: 3,
MAX_PASSWORD_LENGTH: 32,
MAX_USERNAME_LENGTH: 20,
MAX_GROUP_NAME_LENGTH: 64,
DEFAULT_PUBLIC_CHAT_URL: appConfig.get('defaultPublicChatServer'),
DEFAULT_PUBLIC_CHAT_URL,
MAX_CONNECTION_DURATION: 5000,
MAX_MESSAGE_BODY_LENGTH: 64 * 1024,
// Limited due to the proof-of-work requirement
@ -79,7 +81,8 @@ window.CONSTANTS = {
// at which more messages should be loaded
MESSAGE_CONTAINER_BUFFER_OFFSET_PX: 30,
MESSAGE_FETCH_INTERVAL: 1,
MAX_VOICE_MESSAGE_DURATION: 600,
// Maximum voice message duraiton of 5 minutes
MAX_VOICE_MESSAGE_DURATION: 300,
};
window.versionInfo = {

@ -52,6 +52,7 @@ $session-color-green-alt-2: #00fd73;
$session-color-green-alt-3: #00f782;
$session-shade-1: #0c0c0c;
$session-shade-1-alt: #0F1011;
$session-shade-2: #161616;
$session-shade-3: #191818;
$session-shade-4: #1b1b1b;

@ -29,6 +29,18 @@ $composition-container-height: 60px;
}
}
@keyframes pulseLight {
0% {
box-shadow: 0px 0px 0px 0px $session-color-danger-alt;
}
50% {
box-shadow: 0px 0px 12px 0px rgba($session-color-danger-alt, 1);
}
100% {
box-shadow: 0px 0px 0px 0px rgba($session-color-danger-alt, 1);
}
}
.conversation-item {
display: flex;
@ -267,6 +279,7 @@ $composition-container-height: 60px;
width: 100%;
padding: 0px $session-margin-lg;
}
}
&--status {
@ -290,7 +303,10 @@ $composition-container-height: 60px;
user-select: none;
&:hover{
filter: brightness(100%);
border: 2px solid #161819;
}
background-color: $session-shade-1-alt;
border: 2px solid #161819;
}
}
}
@ -308,6 +324,8 @@ $composition-container-height: 60px;
border-radius: 50%;
background-color: $session-color-danger-alt;
margin-left: $session-margin-sm;
animation: pulseLight 4s infinite;
}
}
}

@ -13,12 +13,27 @@ interface Props {
interface State {
recordDuration: number;
isRecording: boolean;
isPlaying: boolean;
isPaused: boolean;
actionHover: boolean;
mediaSetting?: boolean;
// Steam information and data
mediaBlob?: any;
audioElement?: HTMLAudioElement;
streamParams?: {
stream: any;
media: any;
input: any;
processor: any;
}
volumeArray?: Array<number>;
startTimestamp: number;
nowTimestamp: number;
updateTimerInterval: NodeJS.Timeout;
}
@ -40,6 +55,7 @@ export class SessionRecording extends React.Component<Props, State> {
this.timerUpdate = this.timerUpdate.bind(this);
this.onStream = this.onStream.bind(this);
this.stopStream = this.stopStream.bind(this);
this.visualisationRef = React.createRef();
this.visualisationCanvas = React.createRef();
@ -50,10 +66,15 @@ export class SessionRecording extends React.Component<Props, State> {
this.state = {
recordDuration: 0,
isRecording: true,
isPlaying: false,
isPaused: false,
actionHover: false,
mediaSetting: undefined,
mediaBlob: undefined,
audioElement: undefined,
streamParams: undefined,
volumeArray: undefined,
startTimestamp: now,
nowTimestamp: now,
updateTimerInterval: updateTimerInterval,
@ -78,12 +99,8 @@ export class SessionRecording extends React.Component<Props, State> {
const actionDefault = !actionPause && !actionPlay;
const { isRecording, startTimestamp, nowTimestamp } = this.state;
const elapsedTime = nowTimestamp - startTimestamp;
const displayTimeString = moment(elapsedTime).format('mm:ss');
console.log(`[vince][time] Elapsed time: `, this.state.nowTimestamp - this.state.startTimestamp);
console.log(`[vince][time] Elapsed time calculated: `, elapsedTime);
const elapsedTimeMs = 1000 * (nowTimestamp - startTimestamp);
const displayTimeString = moment.utc(elapsedTimeMs).format('m:ss');
return (
<div className="session-recording">
@ -98,7 +115,7 @@ export class SessionRecording extends React.Component<Props, State> {
iconSize={SessionIconSize.Medium}
// FIXME VINCE: Globalise constants for JS Session Colors
iconColor={'#FF4538'}
onClick={this.stopRecording}
onClick={this.stopStream}
/>
)}
{actionPlay && (
@ -166,12 +183,6 @@ export class SessionRecording extends React.Component<Props, State> {
</div>
);
}
public blobToFile (data: any, fileName:string) {
const file = new File([data.blob], fileName);
console.log(`[vince][mic] File: `, file);
return file;
}
private handleHoverActions() {
if ((this.state.isRecording) && !this.state.actionHover) {
@ -182,6 +193,15 @@ export class SessionRecording extends React.Component<Props, State> {
}
private timerUpdate(){
const { nowTimestamp, startTimestamp } = this.state;
const elapsedTime = nowTimestamp - startTimestamp;
if (elapsedTime >= window.CONSTANTS.MAX_VOICE_MESSAGE_DURATION){
clearInterval(this.state.updateTimerInterval);
this.stopStream();
return;
}
this.setState({
nowTimestamp: moment().unix()
});
@ -195,9 +215,7 @@ export class SessionRecording extends React.Component<Props, State> {
}
}
private stopRecording() {
console.log(`[vince][mic] Stopped recording`);
private async stopRecording() {
this.setState({
isRecording: false,
isPaused: true,
@ -205,23 +223,47 @@ export class SessionRecording extends React.Component<Props, State> {
}
private playRecording() {
console.log(`[vince][mic] Playing recording`);
const { mediaBlob, streamParams } = this.state;
this.setState({
isRecording: false,
isPaused: false,
if (!mediaBlob){
window.pushToast({
title: 'There was an error playing your voice recording.',
});
return;
}
this.setState({
isRecording: false,
isPaused: false,
isPlaying: true,
});
// Start playing recording
const audioURL = window.URL.createObjectURL(mediaBlob.data);
const audioElement = new Audio(audioURL);
this.setState({audioElement});
audioElement.play();
console.log(`[vince][stream] Audio: `, audioURL);
console.log(`[vince][stream] AudioURL: `, audioURL);
}
private initSendVoiceRecording(){
// Is the audio file < 10mb? That's the attachment filesize limit
return;
}
private onDeleteVoiceMessage() {
//this.stopRecording();
this.stopStream();
this.setState({
isRecording: false,
isPaused: true,
isPlaying: false,
}, () => this.props.onStoppedRecording());
}
@ -231,15 +273,48 @@ export class SessionRecording extends React.Component<Props, State> {
private async initiateStream() {
navigator.getUserMedia({audio:true}, this.onStream, this.onStreamError);
}
private stopStream() {
const {streamParams} = this.state;
//const mediaStreamSource = audioContext.createMediaStreamSource(stream);
//const meter = getMeter(audioContext);
//mediaStreamSource.connect(meter);
// Exit if parameters aren't yet set
if (!streamParams){
return;
}
// Stop the stream
streamParams.media.stop();
streamParams.input.disconnect();
streamParams.processor.disconnect();
streamParams.stream.getTracks().forEach((track: any) => track.stop);
console.log(`[vince][stream] Stream: `, streamParams.stream);
console.log(`[vince][stream] Media: `, streamParams.media);
console.log(`[vince][stream] Input: `, streamParams.input);
console.log(`[vince][stream] Processor: `, streamParams.processor);
// Stop recording
this.stopRecording();
}
private onStream(stream: any) {
// If not recording, stop stream
if (!this.state.isRecording) {
this.stopStream();
return;
}
// Start recording the stream
const media = new window.MediaRecorder(stream);
media.ondataavailable = (mediaBlob: any) => {
this.setState({mediaBlob});
};
media.start();
// AUDIO CONTEXT
// Audio Context
const audioContext = new window.AudioContext();
const input = audioContext.createMediaStreamSource(stream);
@ -251,6 +326,9 @@ export class SessionRecording extends React.Component<Props, State> {
const processor = audioContext.createScriptProcessor(bufferSize, 1, 1);
processor.onaudioprocess = () => {
const streamParams = {stream, media, input, processor};
this.setState({streamParams});
// Array of volumes by frequency (not in Hz, arbitrary unit)
const freqTypedArray = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(freqTypedArray);
@ -263,7 +341,7 @@ export class SessionRecording extends React.Component<Props, State> {
// CANVAS CONTEXT
const drawCanvas = () => {
const drawRecordingCanvas = () => {
const canvas = this.visualisationCanvas.current;
const CANVAS_HEIGHT = 35;
const CANVAS_WIDTH = VISUALISATION_WIDTH || 600;
@ -289,9 +367,8 @@ export class SessionRecording extends React.Component<Props, State> {
const frontLoad = volumeArray.slice(0, frontLoadLen - 1).reverse().map(n => n * 0.80);
volumeArray = [...frontLoad, ...volumeArray];
// Chop off values which exceed the bouinds of the container
// Chop off values which exceed the bounds of the container
volumeArray = volumeArray.slice(0, numBars);
console.log(`[vince][mic] Width: `, VISUALISATION_WIDTH);
canvas && (canvas.height = CANVAS_HEIGHT);
canvas && (canvas.width = CANVAS_WIDTH);
@ -316,24 +393,20 @@ export class SessionRecording extends React.Component<Props, State> {
}
}
requestAnimationFrame(drawCanvas);
const drawPlayingCanvas = () => {
return;
}
this.state.isRecording && requestAnimationFrame(drawRecordingCanvas);
this.state.isPlaying && requestAnimationFrame(drawPlayingCanvas);
}
// Get volume for visualisation
// Init listeners for visualisation visualisation
input.connect(analyser);
processor.connect(audioContext.destination);
console.log(`[vince][mic] Freq:`, analyser.frequencyBinCount);
//Start recording the stream
const media = new window.MediaRecorder(stream);
}
private onStreamError(error: any) {
return error;
}

Loading…
Cancel
Save