Re-enable audio playback

This commit is contained in:
Rob Watson 2021-11-29 18:44:31 +01:00
parent b3bc63621a
commit 642ce6e349
2 changed files with 50 additions and 31 deletions

View File

@ -3,16 +3,19 @@ import {
GrpcWebImpl, GrpcWebImpl,
MediaSetServiceClientImpl, MediaSetServiceClientImpl,
GetVideoProgress, GetVideoProgress,
GetAudioProgress,
} from './generated/media_set'; } from './generated/media_set';
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { VideoPreview } from './VideoPreview'; import { VideoPreview } from './VideoPreview';
import { Overview } from './Overview'; import { Overview, CanvasLogicalWidth } from './Overview';
import { Waveform } from './Waveform'; import { Waveform } from './Waveform';
import { ControlBar } from './ControlBar'; import { ControlBar } from './ControlBar';
import { SeekBar } from './SeekBar'; import { SeekBar } from './SeekBar';
import './App.css'; import './App.css';
import { Duration } from './generated/google/protobuf/duration'; import { Duration } from './generated/google/protobuf/duration';
import { from, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
// ported from backend, where should they live? // ported from backend, where should they live?
const thumbnailWidth = 177; const thumbnailWidth = 177;
@ -36,8 +39,12 @@ export interface VideoPosition {
function App(): JSX.Element { function App(): JSX.Element {
const [mediaSet, setMediaSet] = useState<MediaSet | null>(null); const [mediaSet, setMediaSet] = useState<MediaSet | null>(null);
const [video, _setVideo] = useState(document.createElement('video')); const [video, _setVideo] = useState(document.createElement('video'));
const [audio, _setAudio] = useState(document.createElement('audio'));
const [position, setPosition] = useState({ currentTime: 0, percent: 0 }); const [position, setPosition] = useState({ currentTime: 0, percent: 0 });
const [viewport, setViewport] = useState({ start: 0, end: 0 }); const [viewport, setViewport] = useState({ start: 0, end: 0 });
const [overviewPeaks, setOverviewPeaks] = useState<Observable<number[]>>(
from([])
);
// effects // effects
@ -77,6 +84,37 @@ function App(): JSX.Element {
}, 100); }, 100);
}, [mediaSet]); }, [mediaSet]);
// load audio when MediaSet is loaded:
useEffect(() => {
(async function () {
if (mediaSet == null) {
return;
}
console.log('fetching audio...');
// TODO move this call to app.tsx, pass the stream in as a prop.
const service = new MediaSetServiceClientImpl(newRPC());
const audioProgressStream = service.GetAudio({
id: mediaSet.id,
numBins: CanvasLogicalWidth,
});
const peaks = audioProgressStream.pipe(map((progress) => progress.peaks));
setOverviewPeaks(peaks);
let url = '';
// TODO: probably a nicer way to do this.
await audioProgressStream.forEach((progress: GetAudioProgress) => {
if (progress.url != '') {
url = progress.url;
}
});
audio.src = url;
audio.muted = false;
audio.volume = 1;
console.log('got audio URL', url);
})();
}, [mediaSet]);
// load video when MediaSet is loaded: // load video when MediaSet is loaded:
useEffect(() => { useEffect(() => {
(async function () { (async function () {
@ -98,8 +136,6 @@ function App(): JSX.Element {
}); });
video.src = url; video.src = url;
video.muted = false;
video.volume = 1;
console.log('set video src', video.src); console.log('set video src', video.src);
})(); })();
}, [mediaSet]); }, [mediaSet]);
@ -161,14 +197,17 @@ function App(): JSX.Element {
<div style={containerStyles}> <div style={containerStyles}>
<ControlBar <ControlBar
onPlay={() => { onPlay={() => {
audio.play();
video.play(); video.play();
}} }}
onPause={() => { onPause={() => {
video.pause(); video.pause();
audio.pause();
}} }}
/> />
<Overview <Overview
peaks={overviewPeaks}
mediaSet={mediaSet} mediaSet={mediaSet}
offsetPixels={offsetPixels} offsetPixels={offsetPixels}
height={80} height={80}
@ -189,6 +228,7 @@ function App(): JSX.Element {
offsetPixels={offsetPixels} offsetPixels={offsetPixels}
onPositionChanged={(position: number) => { onPositionChanged={(position: number) => {
video.currentTime = position; video.currentTime = position;
audio.currentTime = position;
}} }}
/> />

View File

@ -1,13 +1,8 @@
import { useState, useEffect, useRef, MouseEvent } from 'react'; import { useState, useEffect, useRef, MouseEvent } from 'react';
import { import { MediaSet } from './generated/media_set';
MediaSetServiceClientImpl, import { Frames, VideoPosition } from './App';
MediaSet,
GetAudioProgress,
} from './generated/media_set';
import { Frames, newRPC, VideoPosition } from './App';
import { WaveformCanvas } from './WaveformCanvas'; import { WaveformCanvas } from './WaveformCanvas';
import { from, Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
export interface Selection { export interface Selection {
start: number; start: number;
@ -15,6 +10,7 @@ export interface Selection {
} }
interface Props { interface Props {
peaks: Observable<number[]>;
mediaSet: MediaSet; mediaSet: MediaSet;
height: number; height: number;
offsetPixels: number; offsetPixels: number;
@ -37,12 +33,13 @@ enum HoverState {
OverSelection, OverSelection,
} }
const CanvasLogicalWidth = 2_000; export const CanvasLogicalWidth = 2_000;
const CanvasLogicalHeight = 500; export const CanvasLogicalHeight = 500;
const emptySelection = { start: 0, end: 0 }; const emptySelection = { start: 0, end: 0 };
export const Overview: React.FC<Props> = ({ export const Overview: React.FC<Props> = ({
peaks,
mediaSet, mediaSet,
height, height,
offsetPixels, offsetPixels,
@ -50,7 +47,6 @@ export const Overview: React.FC<Props> = ({
onSelectionChange, onSelectionChange,
}: Props) => { }: Props) => {
const hudCanvasRef = useRef<HTMLCanvasElement>(null); const hudCanvasRef = useRef<HTMLCanvasElement>(null);
const [peaks, setPeaks] = useState<Observable<number[]>>(from([]));
const [mode, setMode] = useState(Mode.Normal); const [mode, setMode] = useState(Mode.Normal);
const [hoverState, setHoverState] = useState(HoverState.Normal); const [hoverState, setHoverState] = useState(HoverState.Normal);
const [newSelection, setNewSelection] = useState({ const [newSelection, setNewSelection] = useState({
@ -112,23 +108,6 @@ export const Overview: React.FC<Props> = ({
console.error('no hud 2d context available'); console.error('no hud 2d context available');
return; return;
} }
console.log('fetching audio...');
const service = new MediaSetServiceClientImpl(newRPC());
const audioProgressStream = service.GetAudio({
id: mediaSet.id,
numBins: CanvasLogicalWidth,
});
const peaks = audioProgressStream.pipe(map((progress) => progress.peaks));
setPeaks(peaks);
let url = '';
// TODO: probably a nicer way to do this.
await audioProgressStream.forEach((progress: GetAudioProgress) => {
if (progress.url != '') {
url = progress.url;
}
});
console.log('got audio URL', url);
})(); })();
}, [mediaSet]); }, [mediaSet]);