fix(27): seek native client to start when backing track ends

When track reaches end:
- UI was reset to position 0
- Native client was NOT seeked to position 0

Result: First play click failed because native client was still at end,
but UI showed position 0 so atEnd check was false and no seek was done.

Fix: Call SessionTrackSeekMs(0) when track ends, so native client
position matches UI state and next play works immediately.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Nuwan 2026-03-02 13:28:58 +05:30
parent d59fdae944
commit fe589f4ac2
1 changed files with 27 additions and 35 deletions

View File

@ -3,6 +3,8 @@ import { Modal, ModalHeader, ModalBody, ModalFooter, Button } from 'reactstrap';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faPlay, faPause, faStop } from '@fortawesome/free-solid-svg-icons'; import { faPlay, faPause, faStop } from '@fortawesome/free-solid-svg-icons';
import useMediaActions from '../../hooks/useMediaActions'; import useMediaActions from '../../hooks/useMediaActions';
import playIcon from '../../assets/img/client/play.svg';
import stopIcon from '../../assets/img/client/stop.svg';
const JKSessionBackingTrackPlayer = ({ const JKSessionBackingTrackPlayer = ({
isOpen, isOpen,
@ -188,6 +190,8 @@ const JKSessionBackingTrackPlayer = ({
console.log('[POLLING] Not looping, stopping and resetting'); console.log('[POLLING] Not looping, stopping and resetting');
// Stop playback and reset to beginning for clean state // Stop playback and reset to beginning for clean state
await jamClient.SessionStopPlay(); await jamClient.SessionStopPlay();
// Seek native client to beginning so next play works immediately
await jamClient.SessionTrackSeekMs(0);
setIsPlaying(false); setIsPlaying(false);
setCurrentPositionMs(0); setCurrentPositionMs(0);
setCurrentTime('0:00'); setCurrentTime('0:00');
@ -491,34 +495,19 @@ const JKSessionBackingTrackPlayer = ({
height: '100vh', height: '100vh',
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", sans-serif', // fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", sans-serif',
backgroundColor: '#f8f9fa' backgroundColor: '#edf2f9f5'
}}> }}>
{/* Popup Header */}
<div style={{
height: '40px',
backgroundColor: '#f8f9fa',
borderBottom: '1px solid #dee2e6',
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
padding: '0 12px',
fontWeight: 'bold',
color: '#495057',
userSelect: 'none'
}}>
<span>Backing Track Player</span>
</div>
{/* Popup Content */} {/* Popup Content */}
<div style={{ <div style={{
flex: 1, flex: 1,
padding: '30px 20px', padding: '20px',
overflow: 'auto', overflow: 'auto',
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
alignItems: 'center', // alignItems: 'center',
justifyContent: 'center' // justifyContent: 'center'
}}> }}>
<div style={{ maxWidth: '420px', width: '100%' }}> <div style={{ maxWidth: '420px', width: '100%' }}>
<div style={{ display: 'flex', flexDirection: 'column', gap: '20px' }}> <div style={{ display: 'flex', flexDirection: 'column', gap: '20px' }}>
@ -528,7 +517,7 @@ const JKSessionBackingTrackPlayer = ({
fontSize: '14px', fontSize: '14px',
fontWeight: 'normal' fontWeight: 'normal'
}}> }}>
<span style={{ color: '#999' }}>Backing Track: </span> <span>Backing Track: </span>
{getFileName(backingTrack)} {getFileName(backingTrack)}
</div> </div>
@ -568,18 +557,19 @@ const JKSessionBackingTrackPlayer = ({
{/* Controls Section */} {/* Controls Section */}
<div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}> <div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
{/* Circular Buttons and Seek Bar */} {/* Circular Buttons and Seek Bar */}
<div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}> <div style={{ display: 'flex', alignItems: 'center', gap: '3px' }}>
{/* Play Button - Circular */} {/* Play Button - Circular */}
<button <button
onClick={handlePlay} onClick={handlePlay}
disabled={!backingTrack || isLoadingDuration || isOperating || error} disabled={!backingTrack || isLoadingDuration || isOperating || error}
style={{ style={{
width: '36px', width: '44px',
height: '36px', height: '44px',
borderRadius: '50%', borderRadius: '50%',
border: 'none', border: 'none',
backgroundColor: isPlaying ? '#6c757d' : '#5b9bd5', //backgroundColor: isPlaying ? '#6c757d' : '#5b9bd5',
color: 'white', backgroundColor: '#edf2f9f5',
//color: 'white',
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center',
@ -589,7 +579,8 @@ const JKSessionBackingTrackPlayer = ({
flexShrink: 0 flexShrink: 0
}} }}
> >
<FontAwesomeIcon icon={isPlaying ? faPause : faPlay} style={{ fontSize: '14px' }} /> {/* <FontAwesomeIcon icon={isPlaying ? faPause : faPlay} style={{ fontSize: '14px' }} /> */}
<img src={playIcon} alt='play' />
</button> </button>
{/* Stop Button - Circular */} {/* Stop Button - Circular */}
@ -597,11 +588,11 @@ const JKSessionBackingTrackPlayer = ({
onClick={handleStop} onClick={handleStop}
disabled={!backingTrack || isLoadingDuration || isOperating} disabled={!backingTrack || isLoadingDuration || isOperating}
style={{ style={{
width: '36px', width: '44px',
height: '36px', height: '44ßpx',
borderRadius: '50%', borderRadius: '50%',
border: 'none', border: 'none',
backgroundColor: '#b0b0b0', backgroundColor: '#edf2f9f5',
color: 'white', color: 'white',
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
@ -612,12 +603,13 @@ const JKSessionBackingTrackPlayer = ({
flexShrink: 0 flexShrink: 0
}} }}
> >
<FontAwesomeIcon icon={faStop} style={{ fontSize: '12px' }} /> {/* <FontAwesomeIcon icon={faStop} style={{ fontSize: '12px' }} /> */}
<img src={stopIcon} alt="stop" />
</button> </button>
{/* Time and Seek Bar */} {/* Time and Seek Bar */}
<div style={{ display: 'flex', alignItems: 'center', flex: 1, gap: '8px' }}> <div style={{ display: 'flex', alignItems: 'center', flex: 1, gap: '8px' }}>
<span style={{ fontSize: '14px', color: '#666', minWidth: '35px', fontFamily: 'monospace' }}>{currentTime}</span> <span style={{ fontSize: '14px', color: '#666', minWidth: '35px' }}>{currentTime}</span>
<input <input
type="range" type="range"
min="0" min="0"
@ -635,7 +627,7 @@ const JKSessionBackingTrackPlayer = ({
cursor: (!backingTrack || isLoadingDuration) ? 'not-allowed' : 'pointer' cursor: (!backingTrack || isLoadingDuration) ? 'not-allowed' : 'pointer'
}} }}
/> />
<span style={{ fontSize: '14px', color: '#666', minWidth: '35px', fontFamily: 'monospace' }}>{duration}</span> <span style={{ fontSize: '14px', color: '#666', minWidth: '35px' }}>{duration}</span>
</div> </div>
</div> </div>
@ -693,7 +685,7 @@ const JKSessionBackingTrackPlayer = ({
</ModalHeader> </ModalHeader>
<ModalBody> <ModalBody>
<div style={{ display: 'flex', flexDirection: 'column', gap: '20px' }}> <div style={{ display: 'flex', flexDirection: 'column', gap: '10px' }}>
{/* Title */} {/* Title */}
<div style={{ <div style={{
color: '#666', color: '#666',