about summary refs log tree commit diff
path: root/app/javascript/mastodon/features/audio
diff options
context:
space:
mode:
Diffstat (limited to 'app/javascript/mastodon/features/audio')
-rw-r--r--app/javascript/mastodon/features/audio/index.jsx (renamed from app/javascript/mastodon/features/audio/index.js)99
1 files changed, 51 insertions, 48 deletions
diff --git a/app/javascript/mastodon/features/audio/index.js b/app/javascript/mastodon/features/audio/index.jsx
index 00854d0e4..df40b48f0 100644
--- a/app/javascript/mastodon/features/audio/index.js
+++ b/app/javascript/mastodon/features/audio/index.jsx
@@ -1,12 +1,10 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
-import { formatTime } from 'mastodon/features/video';
+import { formatTime, getPointerPosition, fileNameFromURL } from 'mastodon/features/video';
 import Icon from 'mastodon/components/icon';
 import classNames from 'classnames';
-import { throttle } from 'lodash';
-import { getPointerPosition, fileNameFromURL } from 'mastodon/features/video';
-import { debounce } from 'lodash';
+import { throttle, debounce } from 'lodash';
 import Visualizer from './visualizer';
 import { displayMedia, useBlurhash } from '../../initial_state';
 import Blurhash from '../../components/blurhash';
@@ -24,12 +22,12 @@ const messages = defineMessages({
 const TICK_SIZE = 10;
 const PADDING   = 180;
 
-export default @injectIntl
 class Audio extends React.PureComponent {
 
   static propTypes = {
     src: PropTypes.string.isRequired,
     alt: PropTypes.string,
+    lang: PropTypes.string,
     poster: PropTypes.string,
     duration: PropTypes.number,
     width: PropTypes.number,
@@ -59,7 +57,7 @@ class Audio extends React.PureComponent {
     duration: null,
     paused: true,
     muted: false,
-    volume: 0.5,
+    volume: 1,
     dragging: false,
     revealed: this.props.visible !== undefined ? this.props.visible : (displayMedia !== 'hide_all' && !this.props.sensitive || displayMedia === 'show_all'),
   };
@@ -75,13 +73,13 @@ class Audio extends React.PureComponent {
     if (this.player) {
       this._setDimensions();
     }
-  }
+  };
 
   _pack() {
     return {
       src: this.props.src,
-      volume: this.audio.volume,
-      muted: this.audio.muted,
+      volume: this.state.volume,
+      muted: this.state.muted,
       currentTime: this.audio.currentTime,
       poster: this.props.poster,
       backgroundColor: this.props.backgroundColor,
@@ -105,25 +103,26 @@ class Audio extends React.PureComponent {
 
   setSeekRef = c => {
     this.seek = c;
-  }
+  };
 
   setVolumeRef = c => {
     this.volume = c;
-  }
+  };
 
   setAudioRef = c => {
     this.audio = c;
 
     if (this.audio) {
-      this.setState({ volume: this.audio.volume, muted: this.audio.muted });
+      this.audio.volume = 1;
+      this.audio.muted = false;
     }
-  }
+  };
 
   setCanvasRef = c => {
     this.canvas = c;
 
     this.visualizer.setCanvas(c);
-  }
+  };
 
   componentDidMount () {
     window.addEventListener('scroll', this.handleScroll);
@@ -162,7 +161,7 @@ class Audio extends React.PureComponent {
     } else {
       this.setState({ paused: true }, () => this.audio.pause());
     }
-  }
+  };
 
   handleResize = debounce(() => {
     if (this.player) {
@@ -180,7 +179,7 @@ class Audio extends React.PureComponent {
     }
 
     this._renderCanvas();
-  }
+  };
 
   handlePause = () => {
     this.setState({ paused: true });
@@ -188,7 +187,7 @@ class Audio extends React.PureComponent {
     if (this.audioContext) {
       this.audioContext.suspend();
     }
-  }
+  };
 
   handleProgress = () => {
     const lastTimeRange = this.audio.buffered.length - 1;
@@ -196,15 +195,17 @@ class Audio extends React.PureComponent {
     if (lastTimeRange > -1) {
       this.setState({ buffer: Math.ceil(this.audio.buffered.end(lastTimeRange) / this.audio.duration * 100) });
     }
-  }
+  };
 
   toggleMute = () => {
     const muted = !this.state.muted;
 
     this.setState({ muted }, () => {
-      this.audio.muted = muted;
+      if (this.gainNode) {
+        this.gainNode.gain.value = muted ? 0 : this.state.volume;
+      }
     });
-  }
+  };
 
   toggleReveal = () => {
     if (this.props.onToggleVisibility) {
@@ -212,7 +213,7 @@ class Audio extends React.PureComponent {
     } else {
       this.setState({ revealed: !this.state.revealed });
     }
-  }
+  };
 
   handleVolumeMouseDown = e => {
     document.addEventListener('mousemove', this.handleMouseVolSlide, true);
@@ -224,14 +225,14 @@ class Audio extends React.PureComponent {
 
     e.preventDefault();
     e.stopPropagation();
-  }
+  };
 
   handleVolumeMouseUp = () => {
     document.removeEventListener('mousemove', this.handleMouseVolSlide, true);
     document.removeEventListener('mouseup', this.handleVolumeMouseUp, true);
     document.removeEventListener('touchmove', this.handleMouseVolSlide, true);
     document.removeEventListener('touchend', this.handleVolumeMouseUp, true);
-  }
+  };
 
   handleMouseDown = e => {
     document.addEventListener('mousemove', this.handleMouseMove, true);
@@ -245,7 +246,7 @@ class Audio extends React.PureComponent {
 
     e.preventDefault();
     e.stopPropagation();
-  }
+  };
 
   handleMouseUp = () => {
     document.removeEventListener('mousemove', this.handleMouseMove, true);
@@ -255,7 +256,7 @@ class Audio extends React.PureComponent {
 
     this.setState({ dragging: false });
     this.audio.play();
-  }
+  };
 
   handleMouseMove = throttle(e => {
     const { x } = getPointerPosition(this.seek, e);
@@ -273,14 +274,16 @@ class Audio extends React.PureComponent {
       currentTime: this.audio.currentTime,
       duration: this.audio.duration,
     });
-  }
+  };
 
   handleMouseVolSlide = throttle(e => {
     const { x } = getPointerPosition(this.volume, e);
 
     if(!isNaN(x)) {
       this.setState({ volume: x }, () => {
-        this.audio.volume = x;
+        if (this.gainNode) {
+          this.gainNode.gain.value = this.state.muted ? 0 : x;
+        }
       });
     }
   }, 15);
@@ -306,41 +309,38 @@ class Audio extends React.PureComponent {
 
   handleMouseEnter = () => {
     this.setState({ hovered: true });
-  }
+  };
 
   handleMouseLeave = () => {
     this.setState({ hovered: false });
-  }
+  };
 
   handleLoadedData = () => {
-    const { autoPlay, currentTime, volume, muted } = this.props;
+    const { autoPlay, currentTime } = this.props;
 
     if (currentTime) {
       this.audio.currentTime = currentTime;
     }
 
-    if (volume !== undefined) {
-      this.audio.volume = volume;
-    }
-
-    if (muted !== undefined) {
-      this.audio.muted = muted;
-    }
-
     if (autoPlay) {
       this.togglePlay();
     }
-  }
+  };
 
   _initAudioContext () {
     const AudioContext = window.AudioContext || window.webkitAudioContext;
     const context      = new AudioContext();
     const source       = context.createMediaElementSource(this.audio);
+    const gainNode     = context.createGain();
+
+    gainNode.gain.value = this.state.muted ? 0 : this.state.volume;
 
     this.visualizer.setAudioContext(context, source);
-    source.connect(context.destination);
+    source.connect(gainNode);
+    gainNode.connect(context.destination);
 
     this.audioContext = context;
+    this.gainNode = gainNode;
   }
 
   handleDownload = () => {
@@ -359,7 +359,7 @@ class Audio extends React.PureComponent {
     }).catch(err => {
       console.error(err);
     });
-  }
+  };
 
   _renderCanvas () {
     requestAnimationFrame(() => {
@@ -430,7 +430,7 @@ class Audio extends React.PureComponent {
       e.stopPropagation();
       this.togglePlay();
     }
-  }
+  };
 
   handleKeyDown = e => {
     switch(e.key) {
@@ -455,10 +455,10 @@ class Audio extends React.PureComponent {
       this.seekBy(10);
       break;
     }
-  }
+  };
 
   render () {
-    const { src, intl, alt, editable, autoPlay, sensitive, blurhash } = this.props;
+    const { src, intl, alt, lang, editable, autoPlay, sensitive, blurhash } = this.props;
     const { paused, muted, volume, currentTime, duration, buffer, dragging, revealed } = this.state;
     const progress = Math.min((currentTime / duration) * 100, 100);
 
@@ -470,7 +470,7 @@ class Audio extends React.PureComponent {
     }
 
     return (
-      <div className={classNames('audio-player', { editable, inactive: !revealed })} ref={this.setPlayerRef} style={{ backgroundColor: this._getBackgroundColor(), color: this._getForegroundColor(), width: '100%', height: this.props.fullscreen ? '100%' : (this.state.height || this.props.height) }} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave} tabIndex='0' onKeyDown={this.handleKeyDown}>
+      <div className={classNames('audio-player', { editable, inactive: !revealed })} ref={this.setPlayerRef} style={{ backgroundColor: this._getBackgroundColor(), color: this._getForegroundColor(), width: '100%', height: this.props.fullscreen ? '100%' : (this.state.height || this.props.height) }} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave} tabIndex={0} onKeyDown={this.handleKeyDown}>
 
         <Blurhash
           hash={blurhash}
@@ -493,7 +493,7 @@ class Audio extends React.PureComponent {
 
         <canvas
           role='button'
-          tabIndex='0'
+          tabIndex={0}
           className='audio-player__canvas'
           width={this.state.width}
           height={this.state.height}
@@ -503,6 +503,7 @@ class Audio extends React.PureComponent {
           onKeyDown={this.handleAudioKeyDown}
           title={alt}
           aria-label={alt}
+          lang={lang}
         />
 
         <div className={classNames('spoiler-button', { 'spoiler-button--hidden': revealed || editable })}>
@@ -525,7 +526,7 @@ class Audio extends React.PureComponent {
 
           <span
             className={classNames('video-player__seek__handle', { active: dragging })}
-            tabIndex='0'
+            tabIndex={0}
             style={{ left: `${progress}%`, backgroundColor: this._getAccentColor() }}
             onKeyDown={this.handleAudioKeyDown}
           />
@@ -542,7 +543,7 @@ class Audio extends React.PureComponent {
 
                 <span
                   className='video-player__volume__handle'
-                  tabIndex='0'
+                  tabIndex={0}
                   style={{ left: `${volume * 100}%`, backgroundColor: this._getAccentColor() }}
                 />
               </div>
@@ -567,3 +568,5 @@ class Audio extends React.PureComponent {
   }
 
 }
+
+export default injectIntl(Audio);