For those of you who have been asking about how to modify the videoplayer example SDK app to play audio, here's a solution:
1. In the XML file for your feed, set <streamFormat> to mp3 or wma, as appropriate. The <streamFormat> tag should be subordinate to the <item> tag for your content, the <item> tag being under the <feed> tag. You can mix audio and video content in the same feed as long as the <streamFormat> tags for each are set appropriately.
2. Replace appDetailScreen.brs with:
'*******************************************************************
'** Video Player Example Application - Detail Screen
'** November 2009
'** Copyright(c) 2009 Roku Inc. All Rights Reserved.
'*******************************************************************
'
' Modified by belltown to support mp3 and wma audio streams.
'
' All you need to do to handle an audio stream is to replace
' appDetailScreen.brs in the videoplayer SDK example with this file,
' then in the XML file set <StreamFormat> for your audio item
' to mp3 or wma.
'*******************************************************************
Function VIDEO_BUTTON_PLAY() As Integer : Return 1 : End Function
Function VIDEO_BUTTON_RESUME() As Integer : Return 2 : End Function
Function AUDIO_BUTTON_PLAY() As Integer : Return 3 : End Function
Function AUDIO_BUTTON_STOP() As Integer : Return 4 : End Function
Function AUDIO_BUTTON_PAUSE() As Integer : Return 5 : End Function
Function AUDIO_BUTTON_RESUME() As Integer : Return 6 : End Function
Function preShowDetailScreen(breadA=invalid, breadB=invalid) As Object
port=CreateObject("roMessagePort")
screen = CreateObject("roSpringboardScreen")
' The description style is now set in refreshShowDetail once it is known whether the content is audio or video
'screen.SetDescriptionStyle("video")
screen.SetMessagePort(port)
if breadA<>invalid and breadB<>invalid then
screen.SetBreadcrumbText(breadA, breadB)
end if
return screen
End Function
'***************************************************************
'** The show detail screen(springboard) is where the user sees
'** the details for a show and is allowed to select a show to
'** begin playback. This is the main event loop for that screen
'** and where we spend our time waiting until the user presses a
'** button and then we decide how best to handle the event.
'***************************************************************
Function showDetailScreen(screen As Object, showList As Object, showIndex as Integer) As Integer
if validateParam(screen, "roSpringboardScreen", "showDetailScreen") = false return -1
if validateParam(showList, "roArray", "showDetailScreen") = false return -1
' Set up the audio player
audio = CreateObject("roAudioPlayer")
audio.SetMessagePort(screen.GetMessagePort())
audio.SetLoop(0)
audio.SetNext(0)
' Display the Springboard screen
show = showList[showIndex]
refreshShowDetail(screen, audio, showList, showIndex)
'remote key id's for left/right navigation
remoteKeyLeft = 4
remoteKeyRight = 5
isPlaying = false ' Set to true when the user presses the Play button on the audio Springboard screen
isPaused = false ' Set to true when the user presses the Pause button on the audio Springboard screen
isBuffering = true ' Set to true when audio is buffering or waiting for play to start
while true
' Use a timeout on the wait loop to allow for updating of the audio progress bar
' The smaller the timeout value, the smoother the updates to the progress bar
msg = wait(100, screen.GetMessagePort())
if msg = invalid ' Wait Timeout - update the audio progress bar
if isAudioStream(show) and isPlaying and not isBuffering
runtimeElapsed = setProgressBar(screen, show)
' roAudioPlayer has a bug where if the audio player is paused immediately before the content finishes playing
' (within half a second or so), then the events that signify the end of the content do not fire.
' The 'if' statement below is a workaround for that bug. Assuming the runtime has been set correctly for
' the audio content item, if the audio content has reached its runtime then the audio player is stopped.
' Uncomment the 'if' statement below if you care enough to implement this workaround ...
REM if runtimeElapsed
REM print "Terminating play after runtime has elapsed"
REM isPlaying = false
REM isPaused = false
REM isBuffering = true
REM audio.Stop()
REM zeroProgressBar(screen, show)
REM screen.ClearButtons()
REM screen.AddButton(AUDIO_BUTTON_PLAY(), "Play")
REM endif
endif
else if type(msg) = "roSpringboardScreenEvent"
if msg.isScreenClosed()
print "Screen closed"
exit while
else if msg.isRemoteKeyPressed()
key = msg.GetIndex()
print "Remote key pressed: "; key
if key = remoteKeyLeft ' Play the previous content item
isPlaying = false
isPaused = false
audio.Stop()
audio.ClearContent()
showIndex = getPrevShow(showList, showIndex)
if showIndex <> -1
refreshShowDetail(screen, audio, showList, showIndex)
show = showList[showIndex]
endif
else if key = remoteKeyRight ' Play the next content item
isPlaying = false
isPaused = false
audio.Stop()
audio.ClearContent()
showIndex = getNextShow(showList, showIndex)
if showIndex <> -1
refreshShowDetail(screen, audio, showList, showIndex)
show = showList[showIndex]
endif
endif
else if msg.isButtonPressed()
button = msg.GetIndex()
if button = VIDEO_BUTTON_RESUME()
PlayStart = RegRead(showList[showIndex].ContentId)
if PlayStart <> invalid
showList[showIndex].PlayStart = PlayStart.ToInt()
endif
showVideoScreen(showList[showIndex])
refreshShowDetail(screen, audio, showList, showIndex)
else if button = VIDEO_BUTTON_PLAY()
showList[showIndex].PlayStart = 0
showVideoScreen(showList[showIndex])
refreshShowDetail(screen, audio, showList, showIndex)
else if button = AUDIO_BUTTON_PLAY()
isPlaying = true
isPaused = false
audio.Play()
show.CurrentPosition = 0
zeroProgressBar(screen, show)
screen.ClearButtons()
screen.AddButton(AUDIO_BUTTON_PAUSE(), "Pause")
screen.AddButton(AUDIO_BUTTON_STOP(), "Stop")
else if button = AUDIO_BUTTON_STOP()
isPlaying = false
isPaused = false
isBuffering = true
audio.Stop()
show.CurrentPosition = 0
zeroProgressBar(screen, show)
screen.ClearButtons()
screen.AddButton(AUDIO_BUTTON_PLAY(), "Play")
else if button = AUDIO_BUTTON_PAUSE()
isPlaying = false
isPaused = true
audio.Pause()
screen.ClearButtons()
screen.AddButton(AUDIO_BUTTON_RESUME(), "Resume")
screen.AddButton(AUDIO_BUTTON_STOP(), "Stop")
else if button = AUDIO_BUTTON_RESUME()
isPlaying = true
isPaused = false
audio.Resume()
screen.ClearButtons()
screen.AddButton(AUDIO_BUTTON_PAUSE(), "Pause")
screen.AddButton(AUDIO_BUTTON_STOP(), "Stop")
else
print "Invalid button pressed"
endif
print "Button pressed:"; button " " msg.GetData()
endif
else if type(msg) = "roAudioPlayerEvent"
if msg.IsRequestSucceeded() or msg.IsRequestFailed() or msg.IsPartialResult() or msg.IsFullResult()
if msg.IsRequestSucceeded() then print "roAudioPlayerEvent: IsRequestSucceeded"
if msg.IsRequestFailed() then print "roAudioPlayerEvent: IsRequestFailed: "; msg.GetMessage ()
if msg.IsPartialResult() then print "roAudioPlayerEvent: IsPartialResult"
if msg.IsFullResult() then print "roAudioPlayerEvent: IsFullResult"
isPlaying = false
isPaused = false
isBuffering = true
audio.Stop()
zeroProgressBar(screen, show)
screen.ClearButtons()
screen.AddButton(AUDIO_BUTTON_PLAY(), "Play")
else if msg.IsPaused()
print "roAudioPlayerEvent: IsPaused"
if not isBuffering ' If we're buffering, the current position has already been stored
show.CurrentPosition = show.CurrentPosition + show.PlaybackTimer.TotalMilliseconds()
endif
else if msg.IsResumed()
print "roAudioPlayerEvent: IsResumed"
show.PlaybackTimer.Mark()
else if msg.IsStatusMessage()
message = msg.GetMessage()
print "roAudioPlayerEvent: IsStatusMessage: "; message
if message = "startup progress"
if not isBuffering ' Audio player has started buffering - reset playback timer
show.CurrentPosition = show.CurrentPosition + show.PlaybackTimer.TotalMilliseconds()
isBuffering = true
endif
else if message = "start of play"
show.PlaybackTimer.Mark()
isBuffering = false
endif
else if msg.IsListItemSelected()
print "roAudioPlayerEvent: IsListItemSelected"
else if msg.IsStreamStarted()
print "roAudioPlayerEvent: IsStreamStarted"
else
print "roAudioPlayerEvent: Unknown Event:"; msg.GetType()
endif
else
print "Unexpected message class: "; type(msg)
endif
end while
return showIndex
End Function
'**************************************************************
'** Refresh the contents of the show detail screen. This may be
'** required on initial entry to the screen or as the user moves
'** left/right on the springboard. When the user is on the
'** springboard, we generally let them press left/right arrow keys
'** to navigate to the previous/next show in a circular manner.
'** When leaving the screen, the should be positioned on the
'** corresponding item in the poster screen matching the current show
'**************************************************************
Function refreshShowDetail(screen As Object, audio As Object, showList As Object, showIndex as Integer) As Integer
if validateParam(screen, "roSpringboardScreen", "refreshShowDetail") = false return -1
if validateParam(audio, "roAudioPlayer", "refreshShowDetail") = false return -1
if validateParam(showList, "roArray", "refreshShowDetail") = false return -1
show = showList[showIndex]
show.PlaybackTimer = CreateObject("roTimespan")
'Uncomment this statement to dump the details for each show
'PrintAA(show)
if isAudioStream(show)
if show.StreamUrls.Count() > 0
show.Url = show.StreamUrls[0]
else
print "No audio stream found"
endif
audio.AddContent(show)
show.CurrentPosition = 0
if show.Runtime <> "" and show.Runtime.ToInt() > 0
show.ContentType = "audio" ' ContentType controls the size of the artwork and whether a progress bar is allowed
screen.SetProgressIndicatorEnabled(true)
zeroProgressBar(screen, show)
else
screen.SetProgressIndicatorEnabled(false)
endif
'
' You can set the springboard screen's description style depending on which meta-data fields you want displayed.
'
' "audio": All tags on audio screen are substituted with Content Meta-Data (Album and Artist).
' "movie": All tags on the video screen are substituted with Content Meta-Data
' "video": All tags except <Directors> and <Ratings> on the video screen are replaced with Content Meta-Data.
' "generic": Only the <Title> and <Description> tags on the video screen are replaced with Content Meta-Data.
'
screen.SetDescriptionStyle("movie")
screen.ClearButtons()
screen.AddButton(AUDIO_BUTTON_PLAY(), "Play")
screen.SetContent(show)
screen.Show()
else
' Changed the description type from "video" in the original Roku SDK videoplayer example to "movie",
' so that more content Meta-Data items are displayed on the Springboard screen.
screen.SetDescriptionStyle("movie")
screen.ClearButtons()
if regRead(show.contentid) <> invalid and regRead(show.contentid).ToInt() >= 30
screen.AddButton(VIDEO_BUTTON_RESUME(), "Resume playing")
screen.AddButton(VIDEO_BUTTON_PLAY(), "Play from beginning")
else
screen.addbutton(VIDEO_BUTTON_PLAY(),"Play")
endif
screen.SetContent(show)
screen.Show()
endif
End Function
'********************************************************
'** Get the next item in the list and handle the wrap
'** around case to implement a circular list for left/right
'** navigation on the springboard screen
'********************************************************
Function getNextShow(showList As Object, showIndex As Integer) As Integer
if validateParam(showList, "roArray", "getNextShow") = false return -1
nextIndex = showIndex + 1
if nextIndex >= showList.Count() or nextIndex < 0
nextIndex = 0
endif
show = showList[nextIndex]
if validateParam(show, "roAssociativeArray", "getNextShow") = false return -1
return nextIndex
End Function
'********************************************************
'** Get the previous item in the list and handle the wrap
'** around case to implement a circular list for left/right
'** navigation on the springboard screen
'********************************************************
Function getPrevShow(showList As Object, showIndex As Integer) As Integer
if validateParam(showList, "roArray", "getPrevShow") = false return -1
prevIndex = showIndex - 1
if prevIndex < 0 or prevIndex >= showList.Count()
if showList.Count() > 0 then
prevIndex = showList.Count() - 1
else
return -1
endif
endif
show = showList[prevIndex]
if validateParam(show, "roAssociativeArray", "getPrevShow") = false return -1
return prevIndex
End Function
'********************************************************************
'** Return true if the content's StreamFormat denotes an audio stream
'********************************************************************
Function isAudioStream(show As Object) As Boolean
return LCase(show.StreamFormat) = "mp3" or LCase(show.StreamFormat) = "wma"
End Function
'*******************************
'** Reset the audio progress bar
'*******************************
Function zeroProgressBar(screen As Object, show As Object) As Void
if show.Runtime <> "" and show.Runtime.ToInt() > 0
screen.SetProgressIndicator(0, show.Runtime.ToInt())
endif
End Function
'*************************************************
'** Update the audio progress bar
'** If the show's runtime has elapsed, return true
'*************************************************
Function setProgressBar(screen As Object, show As Object) As Boolean
if show.Runtime <> "" and show.Runtime.ToInt() > 0
' Update the progress indicator
screen.SetProgressIndicator(show.CurrentPosition + show.PlaybackTimer.TotalMilliseconds(), show.Runtime.ToInt() * 1000)
' Workaround for roAudioplayer bug where no event is fired when the end of the content is reached if the player was paused immediately before the end
return (show.CurrentPosition + show.PlaybackTimer.TotalMilliseconds ()) > (show.Runtime.ToInt () * 1000)
endif
return false
End Function
This will display a springboard screen for the audio content containing Play/Pause/Resume/Stop buttons. If the <runtime> tag is present and set to a non-zero value, then an audio player progress bar will also be displayed along the bottom edge of the artwork.