You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Audio.tsx 3.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. import React from 'react';
  2. import AbstractAudio, { IProps } from '../AbstractAudio';
  3. /**
  4. * The React/Web {@link Component} which is similar to and wraps around
  5. * {@code HTMLAudioElement} in order to facilitate cross-platform source code.
  6. */
  7. export default class Audio extends AbstractAudio {
  8. /**
  9. * Set to <code>true</code> when the whole file is loaded.
  10. */
  11. _audioFileLoaded: boolean;
  12. /**
  13. * Reference to the HTML audio element, stored until the file is ready.
  14. */
  15. _ref?: HTMLAudioElement | null;
  16. /**
  17. * Creates new <code>Audio</code> element instance with given props.
  18. *
  19. * @param {Object} props - The read-only properties with which the new
  20. * instance is to be initialized.
  21. */
  22. constructor(props: IProps) {
  23. super(props);
  24. // Bind event handlers so they are only bound once for every instance.
  25. this._onCanPlayThrough = this._onCanPlayThrough.bind(this);
  26. this._setRef = this._setRef?.bind(this);
  27. }
  28. /**
  29. * Implements React's {@link Component#render()}.
  30. *
  31. * @inheritdoc
  32. * @returns {ReactElement}
  33. */
  34. render() {
  35. return (
  36. <audio
  37. loop = { Boolean(this.props.loop) }
  38. onCanPlayThrough = { this._onCanPlayThrough }
  39. preload = 'auto'
  40. ref = { this._setRef }
  41. src = { this.props.src } />
  42. );
  43. }
  44. /**
  45. * Stops the audio HTML element.
  46. *
  47. * @returns {void}
  48. */
  49. stop() {
  50. if (this._ref) {
  51. this._ref.pause();
  52. this._ref.currentTime = 0;
  53. }
  54. }
  55. /**
  56. * If audio element reference has been set and the file has been
  57. * loaded then {@link setAudioElementImpl} will be called to eventually add
  58. * the audio to the Redux store.
  59. *
  60. * @private
  61. * @returns {void}
  62. */
  63. _maybeSetAudioElementImpl() {
  64. if (this._ref && this._audioFileLoaded) {
  65. this.setAudioElementImpl(this._ref);
  66. }
  67. }
  68. /**
  69. * Called when 'canplaythrough' event is triggered on the audio element,
  70. * which means that the whole file has been loaded.
  71. *
  72. * @private
  73. * @returns {void}
  74. */
  75. _onCanPlayThrough() {
  76. this._audioFileLoaded = true;
  77. this._maybeSetAudioElementImpl();
  78. }
  79. /**
  80. * Sets the reference to the HTML audio element.
  81. *
  82. * @param {HTMLAudioElement} audioElement - The HTML audio element instance.
  83. * @private
  84. * @returns {void}
  85. */
  86. _setRef(audioElement?: HTMLAudioElement | null) {
  87. this._ref = audioElement;
  88. if (audioElement) {
  89. this._maybeSetAudioElementImpl();
  90. } else {
  91. // AbstractAudioElement is supposed to trigger "removeAudio" only if
  92. // it was previously added, so it's safe to just call it.
  93. this.setAudioElementImpl(null);
  94. // Reset the loaded flag, as the audio element is being removed from
  95. // the DOM tree.
  96. this._audioFileLoaded = false;
  97. }
  98. }
  99. }