Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/renderer/src/components/HiddenPlayer.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useState, useRef } from 'react';

import { IRegion } from '../crud/useWavesurferRegions';
import WSAudioPlayer from './WSAudioPlayer';
import WSAudioPlayer, { WSAudioPlayerControls } from './WSAudioPlayer';
import { MediaFile } from '../model';
import { NamedRegions } from '../utils/namedSegments';
import { RequestPlay, usePlayerLogic } from '../business/player/usePlayerLogic';
Expand All @@ -20,6 +20,7 @@ export interface HiddenPlayerProps {
currentSegment?: IRegion;
setCurrentSegment?: (segment: IRegion | undefined, index: number) => void;
playerMediafile?: MediaFile;
controlsRef?: React.RefObject<WSAudioPlayerControls | null>;
}

export function HiddenPlayer(props: HiddenPlayerProps) {
Expand All @@ -36,6 +37,7 @@ export function HiddenPlayer(props: HiddenPlayerProps) {
currentSegmentIndex,
setCurrentSegment,
playerMediafile,
controlsRef,
} = props;

const [requestPlay, setRequestPlay] = useState<RequestPlay>({
Expand Down Expand Up @@ -88,6 +90,7 @@ export function HiddenPlayer(props: HiddenPlayerProps) {
onCurrentSegment={onCurrentSegment}
onProgress={onProgress}
onDuration={onDuration}
controlsRef={controlsRef}
/>
</div>
);
Expand Down
13 changes: 12 additions & 1 deletion src/renderer/src/components/MediaPlayer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import SkipPrevious from '@mui/icons-material/SkipPrevious';
import Pause from '@mui/icons-material/Pause';
import PlayArrow from '@mui/icons-material/PlayArrow';
import HiddenPlayer from './HiddenPlayer';
import { WSAudioPlayerControls } from './WSAudioPlayer';
import { RecordKeyMap } from '@orbit/records';

const StyledTip = styled(LightTooltip)<TooltipProps>(() => ({
Expand Down Expand Up @@ -74,6 +75,7 @@ export function MediaPlayer(props: IProps) {
const { fetchMediaUrl, mediaState } = useFetchMediaUrl(reporter);
const [blobState, fetchBlob] = useFetchMediaBlob();
const audioRef = useRef<HTMLAudioElement | null>(null);
const wsControlsRef = useRef<WSAudioPlayerControls | null>(null);
const playSuccess = useRef(false);
const [playing, setPlayingx] = useState(false);
const playingRef = useRef(false);
Expand Down Expand Up @@ -318,7 +320,15 @@ export function MediaPlayer(props: IProps) {

const handlePlayPause = () => {
if (onTogglePlay) onTogglePlay();
if (playingRef.current) stopPlay();
// iOS Safari requires AudioContext resume to happen synchronously inside
// the user gesture. Driving playback through React state introduces async
// hops (incl. a 100ms setTimeout in usePlayerLogic) that lose that context,
// so audio toggles silently. Calling wavesurfer directly here keeps us in
// the gesture; handlePlayStatus is idempotent so the state chain catching
// up later is a no-op.
const wasPlaying = playingRef.current;
wsControlsRef.current?.togglePlay();
if (wasPlaying) stopPlay();
else startPlayWaveSurfer();
};

Expand Down Expand Up @@ -428,6 +438,7 @@ export function MediaPlayer(props: IProps) {
audioBlob={blobState.blob}
playing={playing}
setPlaying={setPlaying}
controlsRef={wsControlsRef}
/>
</StyledHidden>
)}
Expand Down
33 changes: 19 additions & 14 deletions src/renderer/src/components/MediaRecord.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,14 @@ import { useGlobal } from '../context/useGlobal';
import { IPassageRecordStrings, ISharedStrings } from '../model';
import { Stack, Paper, Typography } from '@mui/material';
import WSAudioPlayer, { WSAudioPlayerControls } from './WSAudioPlayer';
import { loadBlobAsync, useMobile, waitForIt } from '../utils';
import {
infoMsg,
loadBlobAsync,
logError,
Severity,
useMobile,
waitForIt,
} from '../utils';
import {
IMediaState,
MediaSt,
Expand Down Expand Up @@ -535,20 +542,18 @@ function MediaRecord(props: IProps) {
setLoading(true);
reset();

const url = await getGoodUrl();

if (url) {
try {
const blob = await loadBlobAsync(url);
if (blob) gotTheBlob(blob);
else blobError('Failed to load blob');
} catch (error) {
blobError(
error instanceof Error ? error.message : 'Failed to load blob'
);
try {
const url = await getGoodUrl();
if (!url) {
blobError(mediaStateRef.current.error || ts.mediaError);
return;
}
} else {
blobError(mediaStateRef.current.error || 'Failed to fetch media URL');
const blob = await loadBlobAsync(url);
if (blob) gotTheBlob(blob);
else blobError(ts.mediaError);
} catch (error) {
logError(Severity.error, reporter, infoMsg(error as Error, 'media load failed'));
Comment thread
gtryus marked this conversation as resolved.
blobError(ts.mediaError);
}
};

Expand Down
5 changes: 5 additions & 0 deletions src/renderer/src/components/WSAudioPlayer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -968,6 +968,11 @@ function WSAudioPlayer(props: IProps) {
const handlePlayStatus = useCallback(
(play: boolean) => {
if (durationRef.current === 0 || recordingRef.current) return false;
const wouldReplayRegion =
play && (regionOnly || forceRegionOnly) && !!currentSegmentRef.current;
if (play === playingRef.current && !wouldReplayRegion) {
return playingRef.current;
}
let nowplaying = play;

if (
Expand Down
Loading