Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: improvements for playback on iOS #235

Merged
merged 4 commits into from
Jun 8, 2024
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
13 changes: 0 additions & 13 deletions .github/workflows/smoketest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -131,19 +131,6 @@ jobs:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
command: d1 migrations apply rail-announcements

- name: Setup Rclone
uses: AnimMouse/setup-rclone@v1
with:
rclone_config: ${{ secrets.RCLONE_CONFIG }}

- name: Upload audio files to Cloudflare R2
# If it's a PR, only run if the PR head is not a fork
if: ${{ github.event_name != 'pull_request' || !github.event.pull_request.head.repo.fork }}
run: |
rclone --fast-list -v --transfers=128 --checkers=256 --progress copy "./audio" "Cloudflare R2:/rail-announcements-audio"
env:
RCLONE_CONFIG_PASS: ${{ secrets.RCLONE_CONFIG_PASSWORD }}

- name: Publish to Cloudflare Pages
uses: cloudflare/pages-action@1
if: ${{ github.event_name != 'pull_request_target' || contains(github.event.label.name, '🚀 request deploy') }}
Expand Down
56 changes: 56 additions & 0 deletions .github/workflows/upload_audio_to_r2.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: Smoketest

on:
push:
branches:
- main
- deploy
paths:
- 'audio/**'
# Triggers the workflow on pull request event, but only for pull request from not forked repo
pull_request:
types:
- opened
- synchronize
paths:
- 'audio/**'

permissions:
# default contents: read & write (in forked repos, only read)
contents: write
# default deployments: read & write (in forked repos, only read)
deployments: write
# default pull-requests: read & write (in forked repos, only read)
pull-requests: write

env:
NODE_VERSION: 20.x
CF_PAGES_PROJECT_NAME: rail-announcements

jobs:
smoketest:
runs-on: ubuntu-latest
name: Upload Audio to Cloudflare R2

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.head.ref || github.ref }}
cancel-in-progress: true

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha || github.ref }}

- name: Setup Rclone
uses: AnimMouse/setup-rclone@v1
with:
rclone_config: ${{ secrets.RCLONE_CONFIG }}

- name: Upload audio files to Cloudflare R2
# If it's a PR, only run if the PR head is not a fork
if: ${{ github.event_name != 'pull_request' || !github.event.pull_request.head.repo.fork }}
run: |
rclone --fast-list -v --transfers=128 --checkers=256 --progress copy "./audio" "Cloudflare R2:/rail-announcements-audio"
env:
RCLONE_CONFIG_PASS: ${{ secrets.RCLONE_CONFIG_PASSWORD }}
2 changes: 1 addition & 1 deletion gatsby-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export const onCreateWebpackConfig: GatsbyNode['onCreateWebpackConfig'] = ({ sta
module: {
rules: [
{
test: /crunker/,
test: /crunker/g,
use: loaders.null(),
},
],
Expand Down
55 changes: 48 additions & 7 deletions src/announcement-data/AnnouncementSystem.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Crunker from 'crunker'
import Crunker from '../helpers/crunker'

import type { ICustomAnnouncementPaneProps } from '@components/PanelPanes/CustomAnnouncementPane'
import type { ICustomButtonPaneProps } from '@components/PanelPanes/CustomButtonPane'
Expand Down Expand Up @@ -170,6 +170,12 @@ export default abstract class AnnouncementSystem {
return
}

window.Crunker = Crunker

if ('audioSession' in window.navigator) {
window.navigator.audioSession.type = 'playback'
}

window.__audio = fileIds
console.info('Playing audio files:', fileIds)

Expand All @@ -186,20 +192,55 @@ export default abstract class AnnouncementSystem {

if (audio.numberOfChannels > 1) {
// This is stereo. We need to mux it to mono.

audio.copyToChannel(audio.getChannelData(0), 1, 0)
}

if (download) {
crunker.download(crunker.export(audio, 'audio/wav').blob, 'announcement')
window.__audio = undefined
} else {
const source = crunker.play(audio)

return new Promise<void>(resolve => {
source.addEventListener('ended', () => {
window.__audio = undefined
resolve()
crunker.play(audio, source => {
console.log('[Crunker] About to play audio...')
crunker._context.onstatechange = () => console.log('state changed to: ', audioContext.state)
console.log('Context state: ', crunker._context.state)

if (crunker._context.state === 'suspended') {
console.log('[Crunker] Resuming audio context')
crunker._context.resume()
console.log('Context state: ', crunker._context.state)

if (crunker._context.state === 'suspended') {
console.error('[Crunker] Failed to resume audio context')

document.getElementById('resume-audio-button')?.remove()

const button = document.createElement('button')
button.textContent = 'Resume audio'
button.id = 'resume-audio-button'
button.style.margin = '16px'
button.onclick = () => {
crunker._context.resume()
button.remove()
}

const container = document.getElementById('resume-audio-container')
if (container) container.appendChild(button)
else document.body.appendChild(button)

alert(
"Your device or web browser is refusing to let the website play audio.\n\nThis is especially common on iPhones and iPads. We'd recommend you try using a desktop computer or an alterantive device.\n\nTry scrolling to and pressing the 'Resume audio' button. If this doesn't help, there's nothing else that we can do. Sorry!",
)

button.scrollIntoView()
}
}

source.addEventListener('ended', () => {
console.log('[Crunker] Finished playing audio')
window.__audio = undefined
resolve()
})
})
})
}
Expand Down
95 changes: 76 additions & 19 deletions src/components/AmeyLiveTrainAnnouncements.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,26 @@ export function LiveTrainAnnouncements<SystemKeys extends string>({
false,
x => x === true || x === false,
)
const [isPlaying, setIsPlaying] = useState(false)
const [isPlaying, _setIsPlaying] = useState(false)
const setIsPlaying = useCallback(
function setIsPlaying(val: boolean) {
console.log(`Setting isPlaying to ${val}`)

_setIsPlaying(val)
},
[_setIsPlaying],
)
const setIsPlayingAfter = useCallback(
function setIsPlayingAfter(val: boolean, timeout: number) {
console.log(`Setting isPlaying to ${val} after ${timeout}ms`)

setTimeout(() => {
setIsPlaying(val)
}, timeout)
},
[setIsPlaying],
)

const [enabledAnnouncements, setEnabledAnnouncements] = useStateWithLocalStorage<AnnouncementType[]>('amey.live-trains.announcement-types', [
AnnouncementType.Next,
AnnouncementType.Approaching,
Expand Down Expand Up @@ -590,15 +609,26 @@ export function LiveTrainAnnouncements<SystemKeys extends string>({
)})`,
)
await standingTrainHandler[systemKey](options)
console.log(`[Live Trains] Announcement for ${train.rid} complete: waiting 5s until next`)
setIsPlayingAfter(false, 5000)
} catch (e) {
console.warn(`[Live Trains] Error playing announcement for ${train.rid}; see below`)
console.error(e)
} finally {
console.log(`[Live Trains] Announcement for ${train.rid} complete: waiting 5s until next`)
setTimeout(() => setIsPlaying(false), 5000)
setIsPlaying(false)
}
},
[markNextTrainAnnounced, systems, setIsPlaying, standingTrainHandler, selectedCrs, getStation, addLog, useLegacyTocNames, announceViaPoints],
[
markNextTrainAnnounced,
systems,
setIsPlaying,
standingTrainHandler,
selectedCrs,
getStation,
addLog,
useLegacyTocNames,
announceViaPoints,
setIsPlayingAfter,
],
)

const announceApproachingTrain = useCallback(
Expand Down Expand Up @@ -655,12 +685,12 @@ export function LiveTrainAnnouncements<SystemKeys extends string>({
)})`,
)
await approachingTrainHandler[systemKey](options)
console.log(`[Live Trains] Announcement for ${train.rid} complete: waiting 5s until next`)
setIsPlayingAfter(false, 5000)
} catch (e) {
console.warn(`[Live Trains] Error playing announcement for ${train.rid}; see below`)
console.error(e)
} finally {
console.log(`[Live Trains] Announcement for ${train.rid} complete: waiting 5s until next`)
setTimeout(() => setIsPlaying(false), 5000)
setIsPlaying(false)
}
},
[
Expand All @@ -673,6 +703,7 @@ export function LiveTrainAnnouncements<SystemKeys extends string>({
useLegacyTocNames,
chimeType,
announceViaPoints,
setIsPlayingAfter,
],
)

Expand Down Expand Up @@ -732,15 +763,26 @@ export function LiveTrainAnnouncements<SystemKeys extends string>({
)})`,
)
await nextTrainHandler[systemKey](options)
console.log(`[Live Trains] Announcement for ${train.rid} complete: waiting 5s until next`)
setIsPlayingAfter(false, 5000)
} catch (e) {
console.warn(`[Live Trains] Error playing announcement for ${train.rid}; see below`)
console.error(e)
} finally {
console.log(`[Live Trains] Announcement for ${train.rid} complete: waiting 5s until next`)
setTimeout(() => setIsPlaying(false), 5000)
setIsPlaying(false)
}
},
[markNextTrainAnnounced, systems, setIsPlaying, nextTrainHandler, getStation, addLog, useLegacyTocNames, chimeType, announceViaPoints],
[
markNextTrainAnnounced,
systems,
setIsPlaying,
nextTrainHandler,
getStation,
addLog,
useLegacyTocNames,
chimeType,
announceViaPoints,
setIsPlayingAfter,
],
)

const announceDisruptedTrain = useCallback(
Expand Down Expand Up @@ -806,6 +848,8 @@ export function LiveTrainAnnouncements<SystemKeys extends string>({
)})`,
)
await disruptedTrainHandler[systemKey](options)
console.log(`[Live Trains] Announcement for ${train.rid} complete: waiting 5s until next`)
setIsPlayingAfter(false, 5000)
} catch (e) {
console.warn(`[Live Trains] Error playing announcement for ${train.rid}; see below`)

Expand All @@ -820,19 +864,30 @@ export function LiveTrainAnnouncements<SystemKeys extends string>({
)})`,
)
await disruptedTrainHandler[systemKey](options2)
console.log(`[Live Trains] Announcement for ${train.rid} complete: waiting 5s until next`)
setIsPlayingAfter(false, 5000)
} catch (e) {
console.warn(`[Live Trains] Error playing announcement for ${train.rid}; see below`)
console.error(e)
setIsPlaying(false)
}
} else {
console.error(e)
setIsPlaying(false)
}

console.error(e)
} finally {
console.log(`[Live Trains] Announcement for ${train.rid} complete: waiting 5s until next`)
setTimeout(() => setIsPlaying(false), 5000)
}
},
[markDisruptedTrainAnnounced, systems, setIsPlaying, disruptedTrainHandler, addLog, useLegacyTocNames, chimeType, announceViaPoints],
[
markDisruptedTrainAnnounced,
systems,
setIsPlaying,
disruptedTrainHandler,
addLog,
useLegacyTocNames,
chimeType,
announceViaPoints,
setIsPlayingAfter,
],
)

useEffect(() => {
Expand Down Expand Up @@ -866,7 +921,7 @@ export function LiveTrainAnnouncements<SystemKeys extends string>({

try {
const resp = await fetch(
process.env.NODE_ENV === 'development' ? `http://localhost:8787/api/get-services?${params}` : `/api/get-services?${params}`,
process.env.NODE_ENV === 'development' ? `http://local.davw.network:8787/api/get-services?${params}` : `/api/get-services?${params}`,
)

if (!resp.ok) {
Expand Down Expand Up @@ -1611,6 +1666,8 @@ export function LiveTrainAnnouncements<SystemKeys extends string>({
/>
</FullScreen>

<div id="resume-audio-container" />

<Logs css={{ marginTop: 16 }} logs={logs} />

<img
Expand Down
Loading
Loading