Audio playback speedup

This commit is contained in:
1hitsong 2022-05-29 14:41:06 -04:00
parent 86edf371d3
commit 071b814568
12 changed files with 177 additions and 149 deletions

View File

@ -152,6 +152,12 @@ sub loadItems()
getPersonVideos("Episode", results, { MaxWidth: 502, MaxHeight: 300 })
else if m.top.itemsToLoad = "personSeries"
getPersonVideos("Series", results, {})
else if m.top.itemsToLoad = "metaData"
results.push(ItemMetaData(m.top.itemId))
else if m.top.itemsToLoad = "audioStream"
results.push(AudioStream(m.top.itemId))
else if m.top.itemsToLoad = "backdropImage"
results.push(BackdropImage(m.top.itemId))
end if
m.top.content = results

View File

@ -1,29 +1,41 @@
sub init()
m.top.optionsAvailable = false
setupMainNode()
setupAudioNode()
setupButtons()
setupInfoNodes()
end sub
sub setupMainNode()
main = m.top.findNode("toplevel")
main.translation = [96, 175]
m.LoadMetaDataTask = CreateObject("roSGNode", "LoadItemsTask")
m.LoadMetaDataTask.itemsToLoad = "metaData"
m.LoadBackdropImageTask = CreateObject("roSGNode", "LoadItemsTask")
m.LoadBackdropImageTask.itemsToLoad = "backdropImage"
m.LoadAudioStreamTask = CreateObject("roSGNode", "LoadItemsTask")
m.LoadAudioStreamTask.itemsToLoad = "audioStream"
m.currentSongIndex = 0
m.buttonsNeedToBeLoaded = true
end sub
sub setupAudioNode()
m.top.audio = createObject("RoSGNode", "Audio")
m.top.audio.observeField("contentIndex", "audioIndexChanged")
m.top.audio.observeField("state", "audioStateChanged")
end sub
sub setupButtons()
m.buttons = m.top.findNode("buttons")
m.buttons.buttons = [tr("Previous"), tr("Play/Pause"), tr("Next")]
m.top.observeField("selectedButtonIndex", "selectedButtonChanged")
m.previouslySelectedButtonIndex = 1
m.top.selectedButtonIndex = 1
end sub
m.buttons.selectedIndex = 1
m.buttons.focusedIndex = 1
m.buttons.setFocus(true)
sub selectedButtonChanged()
selectedButton = m.buttons.getChild(m.previouslySelectedButtonIndex)
selectedButton.uri = selectedButton.uri.Replace("-selected", "-default")
selectedButton = m.buttons.getChild(m.top.selectedButtonIndex)
selectedButton.uri = selectedButton.uri.Replace("-default", "-selected")
end sub
sub setupInfoNodes()
@ -31,8 +43,16 @@ sub setupInfoNodes()
m.backDrop = m.top.findNode("backdrop")
end sub
sub audioIndexChanged()
pageContentChanged()
sub audioStateChanged()
' Song Finished, attempt to move to next song
if m.top.audio.state = "finished"
if m.currentSongIndex < m.top.pageContent.count() - 1
LoadNextSong()
else
' Return to previous screen
m.top.state = "finished"
end if
end if
end sub
function playAction() as boolean
@ -46,33 +66,80 @@ function playAction() as boolean
end function
function previousClicked() as boolean
if m.top.audio.contentIndex > 0
m.top.audio.nextContentIndex = m.top.audio.contentIndex - 1
m.top.audio.control = "skipcontent"
if m.currentSongIndex > 0
m.currentSongIndex--
pageContentChanged()
end if
return true
end function
function nextClicked() as boolean
if m.top.audio.contentIsPlaylist
m.top.audio.control = "skipcontent"
if m.currentSongIndex < m.top.pageContent.count() - 1
LoadNextSong()
end if
return true
end function
sub LoadNextSong()
m.currentSongIndex++
pageContentChanged()
end sub
' Update values on screen when page content changes
sub pageContentChanged()
' If audio isn't playing yet, skip because we have nothing to update
if m.top.audio.contentIndex = -1 then return
m.LoadMetaDataTask.itemId = m.top.pageContent[m.currentSongIndex]
m.LoadMetaDataTask.observeField("content", "onMetaDataLoaded")
m.LoadMetaDataTask.control = "RUN"
item = m.top.pageContent[m.top.audio.contentIndex]
m.LoadAudioStreamTask.itemId = m.top.pageContent[m.currentSongIndex]
m.LoadAudioStreamTask.observeField("content", "onAudioStreamLoaded")
m.LoadAudioStreamTask.control = "RUN"
end sub
setPosterImage(item.posterURL)
setScreenTitle(item.json)
setOnScreenTextValues(item.json)
setBackdropImage()
sub onAudioStreamLoaded()
data = m.LoadAudioStreamTask.content[0]
m.LoadAudioStreamTask.unobserveField("content")
if data <> invalid and data.count() > 0
m.top.audio.content = data
m.top.audio.control = "stop"
m.top.audio.control = "none"
m.top.audio.control = "play"
end if
end sub
sub onBackdropImageLoaded()
data = m.LoadBackdropImageTask.content[0]
m.LoadBackdropImageTask.unobserveField("content")
if isValid(data) and data <> ""
setBackdropImage(data)
end if
end sub
sub onMetaDataLoaded()
data = m.LoadMetaDataTask.content[0]
m.LoadMetaDataTask.unobserveField("content")
if data <> invalid and data.count() > 0
' Use metadata to load backdrop image
m.LoadBackdropImageTask.itemId = data.json.ArtistItems[0].id
m.LoadBackdropImageTask.observeField("content", "onBackdropImageLoaded")
m.LoadBackdropImageTask.control = "RUN"
setPosterImage(data.posterURL)
setScreenTitle(data.json)
setOnScreenTextValues(data.json)
' If we have more and 1 song to play, fade in the next and previous controls
if m.buttonsNeedToBeLoaded
if m.top.pageContent.count() > 1
m.floatanimation = m.top.FindNode("displayButtonsAnimation")
m.floatanimation.control = "start"
end if
m.buttonsNeedToBeLoaded = false
end if
end if
end sub
' Set poster image on screen
@ -107,18 +174,17 @@ end sub
' Populate on screen text variables
sub setOnScreenTextValues(json)
if isValid(json)
setFieldTextValue("numberofsongs", "Track " + stri(m.top.audio.contentIndex + 1) + "/" + stri(m.top.pageContent.count()))
setFieldTextValue("numberofsongs", "Track " + stri(m.currentSongIndex + 1) + "/" + stri(m.top.pageContent.count()))
setFieldTextValue("artist", json.Artists[0])
setFieldTextValue("album", json.album)
setFieldTextValue("song", json.name)
end if
end sub
' Add backdrop image to screen
sub setBackdropImage()
if isValid(m.top.backgroundContent[m.top.audio.contentIndex])
if m.backDrop.uri <> m.top.backgroundContent[m.top.audio.contentIndex]
m.backDrop.uri = m.top.backgroundContent[m.top.audio.contentIndex]
sub setBackdropImage(data)
if isValid(data)
if m.backDrop.uri <> data
m.backDrop.uri = data
end if
end if
end sub
@ -136,19 +202,26 @@ function onKeyEvent(key as string, press as boolean) as boolean
return previousClicked()
else if key = "fastforward"
return nextClicked()
end if
else if key = "left"
if m.top.pageContent.count() = 1 then return false
if m.top.selectedButtonIndex > 0
m.previouslySelectedButtonIndex = m.top.selectedButtonIndex
m.top.selectedButtonIndex = m.top.selectedButtonIndex - 1
end if
return true
else if key = "right"
if m.top.pageContent.count() = 1 then return false
return false
end if
' Key bindings for button group
if m.buttons.hasFocus()
if key = "OK"
if m.buttons.buttons[m.buttons.focusedIndex] = tr("Play/Pause")
m.previouslySelectedButtonIndex = m.top.selectedButtonIndex
if m.top.selectedButtonIndex < 2 then m.top.selectedButtonIndex = m.top.selectedButtonIndex + 1
return true
else if key = "OK"
if m.buttons.getChild(m.top.selectedButtonIndex).id = "play"
return playAction()
else if m.buttons.buttons[m.buttons.focusedIndex] = tr("Previous")
else if m.buttons.getChild(m.top.selectedButtonIndex).id = "previous"
return previousClicked()
else if m.buttons.buttons[m.buttons.focusedIndex] = tr("Next")
else if m.buttons.getChild(m.top.selectedButtonIndex).id = "next"
return nextClicked()
end if
end if

View File

@ -1,28 +1,34 @@
<?xml version="1.0" encoding="utf-8" ?>
<component name="NowPlaying" extends="JFGroup">
<children>
<Poster id="backdrop" opacity=".5" loadDisplayMode="scaleToZoom" width="2000" height="1200" blendColor="#3f3f3f" />
<LayoutGroup id="toplevel" layoutDirection="vert" itemSpacings="[-10]" >
<LayoutGroup id="main_group" layoutDirection="horiz" itemSpacings="[15]" >
<LayoutGroup layoutDirection="vert" itemSpacings="[15]">
<Poster id="albumCover" width="450" height="450" />
<Label id="numberofsongs" width="450" height="25" horizAlign="left" />
</LayoutGroup>
<LayoutGroup layoutDirection="vert" horizAlignment="left" itemSpacings="[15]">
<Label id="artist" width="450" height="25" horizAlign="left" />
<Label id="song" width="450" height="25" horizAlign="left" />
<Label id="album" width="450" height="25" horizAlign="left" />
<LayoutGroup id="controlButtons" layoutDirection="horiz" itemSpacings="[15]">
<JFButtons id="buttons" />
</LayoutGroup>
</LayoutGroup>
<Poster id="backdrop" opacity=".5" loadDisplayMode="scaleToZoom" width="1920" height="1200" blendColor="#3f3f3f" />
<LayoutGroup id="toplevel" layoutDirection="vert" horizAlignment="center" translation="[900,175]" itemSpacings="[40]">
<LayoutGroup id="main_group" layoutDirection="vert" horizAlignment="center" itemSpacings="[15]">
<Poster id="albumCover" width="500" height="500" />
<Label id="artist" width="900" height="25" horizAlign="center" />
<Label id="song" width="900" height="25" horizAlign="center" />
<Label id="numberofsongs" width="500" height="25" horizAlign="center" font="font:SmallestSystemFont" color="#999999" />
</LayoutGroup>
<LayoutGroup id="buttons" layoutDirection="horiz" horizAlignment="center" itemSpacings="[45]">
<Poster id="previous" width="64" height="64" uri="pkg:/images/icons/previous-default.png" opacity="0" />
<Poster id="play" width="64" height="64" uri="pkg:/images/icons/play-default.png" />
<Poster id="next" width="64" height="64" uri="pkg:/images/icons/next-default.png" opacity="0" />
</LayoutGroup>
<Animation id="displayButtonsAnimation" duration="1" repeat="false" easeFunction="linear">
<FloatFieldInterpolator key="[0.0, 1.0]" keyValue="[0.0, 1.0]" fieldToInterp="previous.opacity" />
<FloatFieldInterpolator key="[0.0, 1.0]" keyValue="[0.0, 1.0]" fieldToInterp="next.opacity" />
</Animation>
</LayoutGroup>
<!-- Preload selected icons to prevent flicker -->
<Poster width="0" height="0" uri="pkg:/images/icons/previous-selected.png" visible="false" />
<Poster width="0" height="0" uri="pkg:/images/icons/play-selected.png" visible="false" />
<Poster width="0" height="0" uri="pkg:/images/icons/next-selected.png" visible="false" />
</children>
<interface>
<field id="backgroundContent" type="array" />
<field id="pageContent" type="nodearray" onChange="pageContentChanged" />
<field id="pageContent" type="array" onChange="pageContentChanged" />
<field id="audio" type="node" />
<field id="state" type="string" />
<field id="selectedButtonIndex" type="integer" />
</interface>
<script type="text/brightscript" uri="pkg:/source/utils/misc.brs" />
<script type="text/brightscript" uri="NowPlaying.brs" />

BIN
images/icons/next-default.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
images/icons/next-selected.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
images/icons/play-default.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
images/icons/play-selected.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
images/icons/previous-default.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -159,7 +159,7 @@ sub Main (args as dynamic) as void
else if selectedItem.type = "MusicAlbum"
group = CreateMusicAlbumDetailsGroup(selectedItem.json)
else if selectedItem.type = "Audio"
group = CreateAudioPlayerGroup(selectedItem.json)
group = CreateAudioPlayerGroup([selectedItem.json])
else
' TODO - switch on more node types
message_dialog("This type is not yet supported: " + selectedItem.type + ".")
@ -190,7 +190,7 @@ sub Main (args as dynamic) as void
' User has selected audio they want us to play
selectedIndex = msg.getData()
screenContent = msg.getRoSGNode()
group = CreateAudioPlayerGroup(screenContent.albumData.items[selectedIndex])
group = CreateAudioPlayerGroup([screenContent.albumData.items[selectedIndex]])
else if isNodeEvent(msg, "playAllSelected")
' User has selected playlist of of audio they want us to play
screenContent = msg.getRoSGNode()

View File

@ -418,82 +418,16 @@ end function
function CreateAudioPlayerGroup(audiodata)
group = CreateObject("roSGNode", "NowPlaying")
songMetaDataArray = CreateObject("roArray", 0, true)
songBackdropArray = CreateObject("roArray", 0, true)
content = createObject("RoSGNode", "ContentNode")
group.observeField("state", m.port)
songIDArray = CreateObject("roArray", 0, true)
if type(audiodata) = "roArray"
' Passed data is an array of audio, setup playback as a playlist
group.audio.contentIsPlaylist = true
audioPlaylistContent = createObject("RoSGNode", "ContentNode")
for each song in audiodata
songContent = audioPlaylistContent.CreateChild("ContentNode")
songData = AudioItem(song.id)
songMetaDataArray.push(ItemMetaData(song.id))
imgParams = { "maxHeight": "720", "maxWidth": "1280" }
if isValid(song.json.ArtistItems[0])
songBackdropArray.push(ImageURL(song.json.ArtistItems[0].id, "Backdrop", imgParams))
end if
params = {}
params.append({
"Static": "true",
"Container": songData.mediaSources[0].container,
})
params.MediaSourceId = songData.mediaSources[0].id
songContent.url = buildURL(Substitute("Audio/{0}/stream", song.id), params)
songContent.title = song.title
songContent.streamformat = songData.mediaSources[0].container
end for
content = audioPlaylistContent
else if type(audiodata) = "roSGNode"
' Passed data is a single node
if audiodata.subtype() = "MusicSongData"
' Passed data is data for a single song, setup playback as a single song
songData = AudioItem(audiodata.id)
songMetaDataArray.push(ItemMetaData(audiodata.id))
imgParams = { "maxHeight": "720", "maxWidth": "1280" }
if isValid(audiodata.json.ArtistItems[0])
songBackdropArray.push(ImageURL(audiodata.json.ArtistItems[0].id, "Backdrop", imgParams))
end if
params = {}
params.append({
"Static": "true",
"Container": songData.mediaSources[0].container,
})
params.MediaSourceId = songData.mediaSources[0].id
content.url = buildURL(Substitute("Audio/{0}/stream", audiodata.id), params)
content.title = audiodata.title
content.streamformat = songData.mediaSources[0].container
end if
end if
group.backgroundContent = songBackdropArray
group.pageContent = songMetaDataArray
' All we need is an array of Song IDs the user selected to play.
for each song in audiodata
songIDArray.push(song.id)
end for
group.pageContent = songIDArray
group.musicArtistAlbumData = audiodata
group.audio.content = content
group.audio.control = "stop"
group.audio.control = "none"
group.audio.control = "play"
m.global.sceneManager.callFunc("pushScene", group)

View File

@ -204,24 +204,33 @@ function AudioItem(id as string)
"sortBy": "SortName"
})
data = getJson(resp)
results = []
if data.Items <> invalid
for each item in data.Items
tmp = CreateObject("roSGNode", "MusicSongData")
tmp.image = PosterImage(item.id)
tmp.json = item
results.push(tmp)
end for
else
tmp = CreateObject("roSGNode", "MusicSongData")
tmp.image = PosterImage(data.id)
tmp.json = data
results.push(tmp)
end if
return getJson(resp)
end function
data.Items = results
return data
function AudioStream(id as string)
songData = AudioItem(id)
content = createObject("RoSGNode", "ContentNode")
params = {}
params.append({
"Static": "true",
"Container": songData.mediaSources[0].container,
})
params.MediaSourceId = songData.mediaSources[0].id
content.url = buildURL(Substitute("Audio/{0}/stream", songData.id), params)
content.title = songData.title
content.streamformat = songData.mediaSources[0].container
return content
end function
function BackdropImage(id as string)
imgParams = { "maxHeight": "720", "maxWidth": "1280" }
return ImageURL(id, "Backdrop", imgParams)
end function
' Seasons for a TV Show