VideoLatency.tsx 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. import React, { useContext, useState, useEffect, FC } from 'react';
  2. import { Typography, Slider } from 'antd';
  3. import { ServerStatusContext } from '../../utils/server-status-context';
  4. import { AlertMessageContext } from '../../utils/alert-message-context';
  5. import {
  6. API_VIDEO_SEGMENTS,
  7. RESET_TIMEOUT,
  8. postConfigUpdateToAPI,
  9. } from '../../utils/config-constants';
  10. import {
  11. createInputStatus,
  12. StatusState,
  13. STATUS_ERROR,
  14. STATUS_PROCESSING,
  15. STATUS_SUCCESS,
  16. } from '../../utils/input-statuses';
  17. import { FormStatusIndicator } from './FormStatusIndicator';
  18. const { Title } = Typography;
  19. const SLIDER_MARKS = {
  20. 0: 'Lowest',
  21. 1: ' ',
  22. 2: ' ',
  23. 3: ' ',
  24. 4: 'Highest',
  25. };
  26. const SLIDER_COMMENTS = {
  27. 0: 'Lowest latency, lowest error tolerance (Not recommended, may not work for all content/configurations.)',
  28. 1: 'Low latency, low error tolerance',
  29. 2: 'Medium latency, medium error tolerance (Default)',
  30. 3: 'High latency, high error tolerance',
  31. 4: 'Highest latency, highest error tolerance',
  32. };
  33. // eslint-disable-next-line import/prefer-default-export
  34. export const VideoLatency: FC = () => {
  35. const [submitStatus, setSubmitStatus] = useState<StatusState>(null);
  36. const [selectedOption, setSelectedOption] = useState(null);
  37. const serverStatusData = useContext(ServerStatusContext);
  38. const { setMessage } = useContext(AlertMessageContext);
  39. const { serverConfig, setFieldInConfigState } = serverStatusData || {};
  40. const { videoSettings } = serverConfig || {};
  41. let resetTimer = null;
  42. if (!videoSettings) {
  43. return null;
  44. }
  45. useEffect(() => {
  46. setSelectedOption(videoSettings.latencyLevel);
  47. }, [videoSettings]);
  48. const resetStates = () => {
  49. setSubmitStatus(null);
  50. resetTimer = null;
  51. clearTimeout(resetTimer);
  52. };
  53. // posts all the variants at once as an array obj
  54. const postUpdateToAPI = async (postValue: any) => {
  55. setSubmitStatus(createInputStatus(STATUS_PROCESSING));
  56. await postConfigUpdateToAPI({
  57. apiPath: API_VIDEO_SEGMENTS,
  58. data: { value: postValue },
  59. onSuccess: () => {
  60. setFieldInConfigState({
  61. fieldName: 'latencyLevel',
  62. value: postValue,
  63. path: 'videoSettings',
  64. });
  65. setSubmitStatus(createInputStatus(STATUS_SUCCESS, 'Latency buffer level updated.'));
  66. resetTimer = setTimeout(resetStates, RESET_TIMEOUT);
  67. if (serverStatusData.online) {
  68. setMessage(
  69. 'Your latency buffer setting will take effect the next time you begin a live stream.',
  70. );
  71. }
  72. },
  73. onError: (message: string) => {
  74. setSubmitStatus(createInputStatus(STATUS_ERROR, message));
  75. resetTimer = setTimeout(resetStates, RESET_TIMEOUT);
  76. },
  77. });
  78. };
  79. const handleChange = value => {
  80. postUpdateToAPI(value);
  81. };
  82. return (
  83. <div className="config-video-latency-container">
  84. <Title level={3} className="section-title">
  85. Latency Buffer
  86. </Title>
  87. <p className="description">
  88. While it&apos;s natural to want to keep your latency as low as possible, you may experience
  89. reduced error tolerance and stability the lower you go. The lowest setting is not
  90. recommended.
  91. </p>
  92. <p className="description">
  93. For interactive live streams you may want to experiment with a lower latency, for
  94. non-interactive broadcasts you may want to increase it.{' '}
  95. <a
  96. href="https://owncast.online/docs/encoding#latency-buffer?source=admin"
  97. target="_blank"
  98. rel="noopener noreferrer"
  99. >
  100. Read to learn more.
  101. </a>
  102. </p>
  103. <div className="segment-slider-container">
  104. <Slider
  105. tipFormatter={value => SLIDER_COMMENTS[value]}
  106. onChange={handleChange}
  107. min={0}
  108. max={4}
  109. marks={SLIDER_MARKS}
  110. defaultValue={selectedOption}
  111. value={selectedOption}
  112. />
  113. <p className="selected-value-note">{SLIDER_COMMENTS[selectedOption]}</p>
  114. <FormStatusIndicator status={submitStatus} />
  115. </div>
  116. </div>
  117. );
  118. };